From f5def06cf220acd6fe015f366ed28fa241727a75 Mon Sep 17 00:00:00 2001 From: suneettipirneni Date: Wed, 13 Apr 2022 00:29:00 -0400 Subject: [PATCH 01/60] feat: add support for guild forums --- packages/discord.js/src/errors/Messages.js | 2 + packages/discord.js/src/index.js | 3 +- .../src/managers/GuildChannelManager.js | 4 +- .../src/managers/GuildForumThreadManager.js | 76 +++++++++++++++ .../src/managers/GuildTextThreadManager.js | 91 ++++++++++++++++++ .../discord.js/src/managers/ThreadManager.js | 93 ++++++------------- .../src/structures/BaseGuildTextChannel.js | 4 +- .../src/structures/GuildForumChannel.js | 22 +++++ packages/discord.js/src/structures/Message.js | 2 +- packages/discord.js/typings/index.d.ts | 27 ++++-- 10 files changed, 245 insertions(+), 79 deletions(-) create mode 100644 packages/discord.js/src/managers/GuildForumThreadManager.js create mode 100644 packages/discord.js/src/managers/GuildTextThreadManager.js create mode 100644 packages/discord.js/src/structures/GuildForumChannel.js diff --git a/packages/discord.js/src/errors/Messages.js b/packages/discord.js/src/errors/Messages.js index 417e7a809637..24437b5023c9 100644 --- a/packages/discord.js/src/errors/Messages.js +++ b/packages/discord.js/src/errors/Messages.js @@ -157,6 +157,8 @@ const Messages = { [DjsErrorCodes.NotImplemented]: (what, name) => `Method ${what} not implemented on ${name}.`, [DjsErrorCodes.SweepFilterReturn]: 'The return value of the sweepFilter function was not false or a Function', + + [DjsErrorCodes.GuildForumMessageRequired]: 'You must provide a message to create a guild forum thread', }; module.exports = Messages; diff --git a/packages/discord.js/src/index.js b/packages/discord.js/src/index.js index 9ec254f017f3..1feb34dafa6d 100644 --- a/packages/discord.js/src/index.js +++ b/packages/discord.js/src/index.js @@ -64,6 +64,7 @@ exports.GuildMemberManager = require('./managers/GuildMemberManager'); exports.GuildMemberRoleManager = require('./managers/GuildMemberRoleManager'); exports.GuildScheduledEventManager = require('./managers/GuildScheduledEventManager'); exports.GuildStickerManager = require('./managers/GuildStickerManager'); +exports.GuildTextThreadManager = require('./managers/GuildTextThreadManager'); exports.MessageManager = require('./managers/MessageManager'); exports.PermissionOverwriteManager = require('./managers/PermissionOverwriteManager'); exports.PresenceManager = require('./managers/PresenceManager'); @@ -71,7 +72,7 @@ exports.ReactionManager = require('./managers/ReactionManager'); exports.ReactionUserManager = require('./managers/ReactionUserManager'); exports.RoleManager = require('./managers/RoleManager'); exports.StageInstanceManager = require('./managers/StageInstanceManager'); -exports.ThreadManager = require('./managers/ThreadManager'); +exports.ThreadManager = require('./managers/GuildTextThreadManager'); exports.ThreadMemberManager = require('./managers/ThreadMemberManager'); exports.UserManager = require('./managers/UserManager'); exports.VoiceStateManager = require('./managers/VoiceStateManager'); diff --git a/packages/discord.js/src/managers/GuildChannelManager.js b/packages/discord.js/src/managers/GuildChannelManager.js index 7e76d5bc89b5..455b404dff84 100644 --- a/packages/discord.js/src/managers/GuildChannelManager.js +++ b/packages/discord.js/src/managers/GuildChannelManager.js @@ -4,7 +4,7 @@ const process = require('node:process'); const { Collection } = require('@discordjs/collection'); const { ChannelType, Routes } = require('discord-api-types/v10'); const CachedManager = require('./CachedManager'); -const ThreadManager = require('./ThreadManager'); +const GuildTextThreadManager = require('./GuildTextThreadManager'); const { Error, TypeError, ErrorCodes } = require('../errors'); const GuildChannel = require('../structures/GuildChannel'); const PermissionOverwrites = require('../structures/PermissionOverwrites'); @@ -418,7 +418,7 @@ class GuildChannelManager extends CachedManager { */ async fetchActiveThreads(cache = true) { const raw = await this.client.rest.get(Routes.guildActiveThreads(this.guild.id)); - return ThreadManager._mapThreads(raw, this.client, { guild: this.guild, cache }); + return GuildTextThreadManager._mapThreads(raw, this.client, { guild: this.guild, cache }); } /** diff --git a/packages/discord.js/src/managers/GuildForumThreadManager.js b/packages/discord.js/src/managers/GuildForumThreadManager.js new file mode 100644 index 000000000000..3c4f618c0c43 --- /dev/null +++ b/packages/discord.js/src/managers/GuildForumThreadManager.js @@ -0,0 +1,76 @@ +'use strict'; + +const { Routes } = require('discord-api-types/v10'); +const ThreadManager = require('./ThreadManager'); +const { TypeError } = require('../errors'); +const MessagePayload = require('../structures/MessagePayload'); +const { resolveAutoArchiveMaxLimit } = require('../util/Util'); + +class GuildForumThreadManager extends ThreadManager { + /** + * Options for creating a thread. Only one of `startMessage` or `type` can be defined. + * @typedef {StartThreadOptions} GuildForumThreadCreateOptions + * @property {MessageOptions|MessagePayload} message The message associated with the thread post + */ + + /** + * Creates a new thread in the channel. + * @param {GuildForumThreadCreateOptions} [options] Options to create a new thread + * @returns {Promise} + * @example + * // Create a new public thread + * channel.threads + * .create({ + * name: 'food-talk', + * autoArchiveDuration: 60, + * reason: 'Needed a separate thread for food', + * }) + * .then(threadChannel => console.log(threadChannel)) + * .catch(console.error); + * @example + * // Create a new private thread + * channel.threads + * .create({ + * name: 'mod-talk', + * autoArchiveDuration: 60, + * type: ChannelType.GuildPrivateThread, + * reason: 'Needed a separate thread for moderation', + * }) + * .then(threadChannel => console.log(threadChannel)) + * .catch(console.error); + */ + async create({ + name, + autoArchiveDuration = this.channel.defaultAutoArchiveDuration, + message, + reason, + rateLimitPerUser, + } = {}) { + if (!message) { + throw new TypeError('GUILD_FORUM_MESSAGE_REQUIRED'); + } + + const messagePayload = + message instanceof MessagePayload ? message.resolveBody() : MessagePayload.create(this, message); + + const { body, files } = messagePayload.resolveFiles(); + + if (autoArchiveDuration === 'MAX') autoArchiveDuration = resolveAutoArchiveMaxLimit(this.channel.guild); + + const data = await this.client.rest.post(Routes.threads(this.channel.id), { + body: { + name, + auto_archive_duration: autoArchiveDuration, + rate_limit_per_user: rateLimitPerUser, + ...body, + }, + files, + reason, + }); + + // TODO: Posts will most likely need to be serialized differently than regular threads. + return this.client.actions.ThreadCreate.handle(data).thread; + } +} + +module.exports = GuildForumThreadManager; diff --git a/packages/discord.js/src/managers/GuildTextThreadManager.js b/packages/discord.js/src/managers/GuildTextThreadManager.js new file mode 100644 index 000000000000..656dd4623197 --- /dev/null +++ b/packages/discord.js/src/managers/GuildTextThreadManager.js @@ -0,0 +1,91 @@ +'use strict'; + +const { ChannelType, Routes } = require('discord-api-types/v10'); +const ThreadManager = require('./ThreadManager'); +const { TypeError } = require('../errors'); +const { resolveAutoArchiveMaxLimit } = require('../util/Util'); + +/** + * Manages API methods for {@link ThreadChannel} objects and stores their cache. + * @extends {CachedManager} + */ +class GuildTextThreadManager extends ThreadManager { + /** + * Options for creating a thread. Only one of `startMessage` or `type` can be defined. + * @typedef {StartThreadOptions} ThreadCreateOptions + * @property {MessageResolvable} [startMessage] The message to start a thread from. If this is defined then type + * of thread gets automatically defined and cannot be changed. The provided `type` field will be ignored + * @property {ThreadChannelTypes|number} [type] The type of thread to create. + * Defaults to {@link ChannelType.GuildPublicThread} if created in a {@link TextChannel} + * When creating threads in a {@link NewsChannel} this is ignored and is always + * {@link ChannelType.GuildNewsThread} + * @property {boolean} [invitable] Whether non-moderators can add other non-moderators to the thread + * Can only be set when type will be {@link ChannelType.GuildPrivateThread} + */ + + /** + * Creates a new thread in the channel. + * @param {ThreadCreateOptions} [options] Options to create a new thread + * @returns {Promise} + * @example + * // Create a new public thread + * channel.threads + * .create({ + * name: 'food-talk', + * autoArchiveDuration: 60, + * reason: 'Needed a separate thread for food', + * }) + * .then(threadChannel => console.log(threadChannel)) + * .catch(console.error); + * @example + * // Create a new private thread + * channel.threads + * .create({ + * name: 'mod-talk', + * autoArchiveDuration: 60, + * type: ChannelType.GuildPrivateThread, + * reason: 'Needed a separate thread for moderation', + * }) + * .then(threadChannel => console.log(threadChannel)) + * .catch(console.error); + */ + async create({ + name, + autoArchiveDuration = this.channel.defaultAutoArchiveDuration, + startMessage, + type, + invitable, + reason, + rateLimitPerUser, + } = {}) { + if (type && typeof type !== 'string' && typeof type !== 'number') { + throw new TypeError('INVALID_TYPE', 'type', 'ThreadChannelType or Number'); + } + let resolvedType = + this.channel.type === ChannelType.GuildNews ? ChannelType.GuildNewsThread : ChannelType.GuildPublicThread; + let startMessageId; + if (startMessage) { + startMessageId = this.channel.messages.resolveId(startMessage); + if (!startMessageId) throw new TypeError('INVALID_TYPE', 'startMessage', 'MessageResolvable'); + } else if (this.channel.type !== ChannelType.GuildNews) { + resolvedType = type ?? resolvedType; + } + + if (autoArchiveDuration === 'MAX') autoArchiveDuration = resolveAutoArchiveMaxLimit(this.channel.guild); + + const data = await this.client.rest.post(Routes.threads(this.channel.id, startMessageId), { + body: { + name, + auto_archive_duration: autoArchiveDuration, + type: resolvedType, + invitable: resolvedType === ChannelType.GuildPrivateThread ? invitable : undefined, + rate_limit_per_user: rateLimitPerUser, + }, + reason, + }); + + return this.client.actions.ThreadCreate.handle(data).thread; + } +} + +module.exports = GuildTextThreadManager; diff --git a/packages/discord.js/src/managers/ThreadManager.js b/packages/discord.js/src/managers/ThreadManager.js index f2662d862676..83c0b1fa3539 100644 --- a/packages/discord.js/src/managers/ThreadManager.js +++ b/packages/discord.js/src/managers/ThreadManager.js @@ -2,13 +2,13 @@ const { Collection } = require('@discordjs/collection'); const { makeURLSearchParams } = require('@discordjs/rest'); -const { ChannelType, Routes } = require('discord-api-types/v10'); +const { Routes } = require('discord-api-types/v10'); const CachedManager = require('./CachedManager'); const { TypeError, ErrorCodes } = require('../errors'); const ThreadChannel = require('../structures/ThreadChannel'); /** - * Manages API methods for {@link ThreadChannel} objects and stores their cache. + * Manages API methods for thread based channels and stores their cache. * @extends {CachedManager} */ class ThreadManager extends CachedManager { @@ -17,11 +17,36 @@ class ThreadManager extends CachedManager { /** * The channel this Manager belongs to - * @type {NewsChannel|TextChannel} + * @type {NewsChannel|TextChannel|GuildForumChannel} */ this.channel = channel; } + /** + * Data that can be resolved to a Thread Channel object. This can be: + * * A ThreadChannel object + * * A Snowflake + * @typedef {ThreadChannel|Snowflake} ThreadChannelResolvable + */ + + /** + * Resolves a {@link ThreadChannelResolvable} to a {@link ThreadChannel} object. + * @method resolve + * @memberof ThreadManager + * @instance + * @param {ThreadChannelResolvable} thread The ThreadChannel resolvable to resolve + * @returns {?ThreadChannel} + */ + + /** + * Resolves a {@link ThreadChannelResolvable} to a {@link ThreadChannel} id. + * @method resolveId + * @memberof ThreadManager + * @instance + * @param {ThreadChannelResolvable} thread The ThreadChannel resolvable to resolve + * @returns {?Snowflake} + */ + /** * The cache of this Manager * @type {Collection} @@ -74,68 +99,6 @@ class ThreadManager extends CachedManager { * Can only be set when type will be {@link ChannelType.PrivateThread} */ - /** - * Creates a new thread in the channel. - * @param {ThreadCreateOptions} [options] Options to create a new thread - * @returns {Promise} - * @example - * // Create a new public thread - * channel.threads - * .create({ - * name: 'food-talk', - * autoArchiveDuration: ThreadAutoArchiveDuration.OneHour, - * reason: 'Needed a separate thread for food', - * }) - * .then(threadChannel => console.log(threadChannel)) - * .catch(console.error); - * @example - * // Create a new private thread - * channel.threads - * .create({ - * name: 'mod-talk', - * autoArchiveDuration: ThreadAutoArchiveDuration.OneHour, - * type: ChannelType.PrivateThread, - * reason: 'Needed a separate thread for moderation', - * }) - * .then(threadChannel => console.log(threadChannel)) - * .catch(console.error); - */ - async create({ - name, - autoArchiveDuration = this.channel.defaultAutoArchiveDuration, - startMessage, - type, - invitable, - reason, - rateLimitPerUser, - } = {}) { - if (type && typeof type !== 'string' && typeof type !== 'number') { - throw new TypeError(ErrorCodes.InvalidType, 'type', 'ThreadChannelType or Number'); - } - let resolvedType = - this.channel.type === ChannelType.GuildAnnouncement ? ChannelType.AnnouncementThread : ChannelType.PublicThread; - let startMessageId; - if (startMessage) { - startMessageId = this.channel.messages.resolveId(startMessage); - if (!startMessageId) throw new TypeError(ErrorCodes.InvalidType, 'startMessage', 'MessageResolvable'); - } else if (this.channel.type !== ChannelType.GuildAnnouncement) { - resolvedType = type ?? resolvedType; - } - - const data = await this.client.rest.post(Routes.threads(this.channel.id, startMessageId), { - body: { - name, - auto_archive_duration: autoArchiveDuration, - type: resolvedType, - invitable: resolvedType === ChannelType.PrivateThread ? invitable : undefined, - rate_limit_per_user: rateLimitPerUser, - }, - reason, - }); - - return this.client.actions.ThreadCreate.handle(data).thread; - } - /** * The options for fetching multiple threads, the properties are mutually exclusive * @typedef {Object} FetchThreadsOptions diff --git a/packages/discord.js/src/structures/BaseGuildTextChannel.js b/packages/discord.js/src/structures/BaseGuildTextChannel.js index 12cad909249a..1276799d4f40 100644 --- a/packages/discord.js/src/structures/BaseGuildTextChannel.js +++ b/packages/discord.js/src/structures/BaseGuildTextChannel.js @@ -2,8 +2,8 @@ const GuildChannel = require('./GuildChannel'); const TextBasedChannel = require('./interfaces/TextBasedChannel'); +const ThreadManager = require('../managers/GuildTextThreadManager'); const MessageManager = require('../managers/MessageManager'); -const ThreadManager = require('../managers/ThreadManager'); /** * Represents a text-based guild channel on Discord. @@ -22,7 +22,7 @@ class BaseGuildTextChannel extends GuildChannel { /** * A manager of the threads belonging to this channel - * @type {ThreadManager} + * @type {GuildTextThreadManager} */ this.threads = new ThreadManager(this); diff --git a/packages/discord.js/src/structures/GuildForumChannel.js b/packages/discord.js/src/structures/GuildForumChannel.js new file mode 100644 index 000000000000..0ff0a3840c26 --- /dev/null +++ b/packages/discord.js/src/structures/GuildForumChannel.js @@ -0,0 +1,22 @@ +'use strict'; + +const GuildChannel = require('./GuildChannel'); +const GuildForumThreadManager = require('../managers/GuildForumThreadManager'); + +/** + * Represents a channel that only contains threads + * @extends {GuildChannel} + */ +class GuildForumChannel extends GuildChannel { + constructor(guild, data, client) { + super(guild, data, client, false); + + /** + * A manager of the threads belonging to this channel + * @type {GuildForumThreadManager} + */ + this.threads = new GuildForumThreadManager(this); + } +} + +module.exports = GuildForumChannel; diff --git a/packages/discord.js/src/structures/Message.js b/packages/discord.js/src/structures/Message.js index efb48ea6a2a0..b8702d73723e 100644 --- a/packages/discord.js/src/structures/Message.js +++ b/packages/discord.js/src/structures/Message.js @@ -800,7 +800,7 @@ class Message extends Base { /** * Create a new public thread from this message - * @see ThreadManager#create + * @see GuildTextThreadManager#create * @param {StartThreadOptions} [options] Options for starting a thread on this message * @returns {Promise} */ diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 4ceeb1d27844..678eac2130cb 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -507,7 +507,7 @@ export class BaseGuildTextChannel extends TextBasedChannelMixin(GuildChannel, tr public defaultAutoArchiveDuration?: ThreadAutoArchiveDuration; public rateLimitPerUser: number | null; public nsfw: boolean; - public threads: ThreadManager; + public threads: GuildTextThreadManager; public topic: string | null; public createInvite(options?: CreateInviteOptions): Promise; public fetchInvites(cache?: boolean): Promise>; @@ -2018,8 +2018,8 @@ export class ModalSubmitInteraction extend } export class NewsChannel extends BaseGuildTextChannel { - public threads: ThreadManager; - public type: ChannelType.GuildAnnouncement; + public threads: GuildTextThreadManager; + public type: ChannelType.AnnouncementThread; public addFollower(channel: TextChannelResolvable, reason?: string): Promise; } @@ -2489,7 +2489,7 @@ export class TeamMember extends Base { export class TextChannel extends BaseGuildTextChannel { public rateLimitPerUser: number; - public threads: ThreadManager; + public threads: GuildTextThreadManager; public type: ChannelType.GuildText; } @@ -3620,16 +3620,23 @@ export class StageInstanceManager extends CachedManager; } -export class ThreadManager extends CachedManager { - private constructor(channel: TextChannel | NewsChannel, iterable?: Iterable); +export class ThreadManager extends CachedManager { + public constructor(channel: TextChannel | NewsChannel, iterable?: Iterable); public channel: TextChannel | NewsChannel; - public create(options: ThreadCreateOptions): Promise; public fetch(options: ThreadChannelResolvable, cacheOptions?: BaseFetchOptions): Promise; public fetch(options?: FetchThreadsOptions, cacheOptions?: { cache?: boolean }): Promise; public fetchArchived(options?: FetchArchivedThreadOptions, cache?: boolean): Promise; public fetchActive(cache?: boolean): Promise; } +export class GuildTextThreadManager extends ThreadManager { + public create(options: GuildTextThreadCreateOptions): Promise; +} + +export class GuildForumThreadManger extends ThreadManager { + public create(options: GuildForumThreadCreateOptions): Promise; +} + export class ThreadMemberManager extends CachedManager { private constructor(thread: ThreadChannel, iterable?: Iterable); public thread: AnyThreadChannel; @@ -5562,12 +5569,16 @@ export type ThreadChannelResolvable = AnyThreadChannel | Snowflake; export type ThreadChannelType = ChannelType.AnnouncementThread | ChannelType.PublicThread | ChannelType.PrivateThread; -export interface ThreadCreateOptions extends StartThreadOptions { +export interface GuildTextThreadCreateOptions extends StartThreadOptions { startMessage?: MessageResolvable; type?: AllowedThreadType; invitable?: AllowedThreadType extends ChannelType.PrivateThread ? boolean : never; } +export interface GuildForumThreadCreateOptions extends StartThreadOptions { + message: MessageOptions | MessagePayload; +} + export interface ThreadEditData { name?: string; archived?: boolean; From d4c05c33e8c47510b84a619457aef0baa0998e24 Mon Sep 17 00:00:00 2001 From: suneettipirneni Date: Tue, 31 May 2022 17:06:51 -0400 Subject: [PATCH 02/60] feat(webhook): add support for creating forum channel posts --- packages/discord.js/src/structures/MessagePayload.js | 3 +++ packages/discord.js/src/structures/Webhook.js | 1 + packages/discord.js/typings/index.d.ts | 1 + 3 files changed, 5 insertions(+) diff --git a/packages/discord.js/src/structures/MessagePayload.js b/packages/discord.js/src/structures/MessagePayload.js index 3d7b693ae2ea..71a895347e1e 100644 --- a/packages/discord.js/src/structures/MessagePayload.js +++ b/packages/discord.js/src/structures/MessagePayload.js @@ -137,9 +137,11 @@ class MessagePayload { let username; let avatarURL; + let threadName; if (isWebhook) { username = this.options.username ?? this.target.name; if (this.options.avatarURL) avatarURL = this.options.avatarURL; + if (this.options.threadName) threadName = this.options.threadName; } let flags; @@ -207,6 +209,7 @@ class MessagePayload { message_reference, attachments: this.options.attachments, sticker_ids: this.options.stickers?.map(sticker => sticker.id ?? sticker), + thread_name: threadName, }; return this; } diff --git a/packages/discord.js/src/structures/Webhook.js b/packages/discord.js/src/structures/Webhook.js index 729e1d613072..ba03fae09d95 100644 --- a/packages/discord.js/src/structures/Webhook.js +++ b/packages/discord.js/src/structures/Webhook.js @@ -130,6 +130,7 @@ class Webhook { * @property {string} [avatarURL] Avatar URL override for the message * @property {Snowflake} [threadId] The id of the thread in the channel to send to. * For interaction webhooks, this property is ignored + * @property {string} [threadName] Name of the thread to create (only available if webhook is in a forum channel) */ /** diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 678eac2130cb..5158dc1a4103 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -5641,6 +5641,7 @@ export interface WebhookCreateMessageOptions extends Omit Date: Wed, 1 Jun 2022 17:56:04 -0400 Subject: [PATCH 03/60] fix: duplicated docs --- .../discord.js/src/managers/ThreadManager.js | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/packages/discord.js/src/managers/ThreadManager.js b/packages/discord.js/src/managers/ThreadManager.js index 83c0b1fa3539..4ed1cae7fdb1 100644 --- a/packages/discord.js/src/managers/ThreadManager.js +++ b/packages/discord.js/src/managers/ThreadManager.js @@ -29,24 +29,6 @@ class ThreadManager extends CachedManager { * @typedef {ThreadChannel|Snowflake} ThreadChannelResolvable */ - /** - * Resolves a {@link ThreadChannelResolvable} to a {@link ThreadChannel} object. - * @method resolve - * @memberof ThreadManager - * @instance - * @param {ThreadChannelResolvable} thread The ThreadChannel resolvable to resolve - * @returns {?ThreadChannel} - */ - - /** - * Resolves a {@link ThreadChannelResolvable} to a {@link ThreadChannel} id. - * @method resolveId - * @memberof ThreadManager - * @instance - * @param {ThreadChannelResolvable} thread The ThreadChannel resolvable to resolve - * @returns {?Snowflake} - */ - /** * The cache of this Manager * @type {Collection} From d69a223f0f9ec60c6e8bb6948a8baf8b006ad9b8 Mon Sep 17 00:00:00 2001 From: suneettipirneni Date: Wed, 20 Jul 2022 13:15:49 -0400 Subject: [PATCH 04/60] feat: add support for message counts --- packages/discord.js/src/errors/ErrorCodes.js | 2 ++ packages/discord.js/src/index.js | 2 +- .../src/managers/GuildForumThreadManager.js | 4 ++-- packages/discord.js/src/structures/Message.js | 11 +++++++++++ packages/discord.js/src/structures/ThreadChannel.js | 11 +++++++++++ packages/discord.js/typings/index.d.ts | 6 +++++- 6 files changed, 32 insertions(+), 4 deletions(-) diff --git a/packages/discord.js/src/errors/ErrorCodes.js b/packages/discord.js/src/errors/ErrorCodes.js index df748196984c..f627e5925aeb 100644 --- a/packages/discord.js/src/errors/ErrorCodes.js +++ b/packages/discord.js/src/errors/ErrorCodes.js @@ -288,6 +288,8 @@ const keys = [ 'NotImplemented', 'SweepFilterReturn', + + 'GuildForumMessageRequired', ]; // JSDoc for IntelliSense purposes diff --git a/packages/discord.js/src/index.js b/packages/discord.js/src/index.js index 1feb34dafa6d..7003ae6b19ff 100644 --- a/packages/discord.js/src/index.js +++ b/packages/discord.js/src/index.js @@ -72,7 +72,7 @@ exports.ReactionManager = require('./managers/ReactionManager'); exports.ReactionUserManager = require('./managers/ReactionUserManager'); exports.RoleManager = require('./managers/RoleManager'); exports.StageInstanceManager = require('./managers/StageInstanceManager'); -exports.ThreadManager = require('./managers/GuildTextThreadManager'); +exports.ThreadManager = require('./managers/ThreadManager'); exports.ThreadMemberManager = require('./managers/ThreadMemberManager'); exports.UserManager = require('./managers/UserManager'); exports.VoiceStateManager = require('./managers/VoiceStateManager'); diff --git a/packages/discord.js/src/managers/GuildForumThreadManager.js b/packages/discord.js/src/managers/GuildForumThreadManager.js index 3c4f618c0c43..2865309bb395 100644 --- a/packages/discord.js/src/managers/GuildForumThreadManager.js +++ b/packages/discord.js/src/managers/GuildForumThreadManager.js @@ -2,7 +2,7 @@ const { Routes } = require('discord-api-types/v10'); const ThreadManager = require('./ThreadManager'); -const { TypeError } = require('../errors'); +const { TypeError, ErrorCodes } = require('../errors'); const MessagePayload = require('../structures/MessagePayload'); const { resolveAutoArchiveMaxLimit } = require('../util/Util'); @@ -47,7 +47,7 @@ class GuildForumThreadManager extends ThreadManager { rateLimitPerUser, } = {}) { if (!message) { - throw new TypeError('GUILD_FORUM_MESSAGE_REQUIRED'); + throw new TypeError(ErrorCodes.GuildForumMessageRequired); } const messagePayload = diff --git a/packages/discord.js/src/structures/Message.js b/packages/discord.js/src/structures/Message.js index b8702d73723e..c5133feb481e 100644 --- a/packages/discord.js/src/structures/Message.js +++ b/packages/discord.js/src/structures/Message.js @@ -187,6 +187,17 @@ class Message extends Base { this.stickers = new Collection(this.stickers); } + if ('position' in data) { + /** + * A generally increasing integer (there may be gaps or duplicates) that represents + * the approximate position of the message in a thread. + * @type {?number} + */ + this.position = data.position; + } else { + this.position ??= null; + } + // Discord sends null if the message has not been edited if (data.edited_timestamp) { /** diff --git a/packages/discord.js/src/structures/ThreadChannel.js b/packages/discord.js/src/structures/ThreadChannel.js index b63db743efc0..b87a88150656 100644 --- a/packages/discord.js/src/structures/ThreadChannel.js +++ b/packages/discord.js/src/structures/ThreadChannel.js @@ -180,6 +180,17 @@ class ThreadChannel extends BaseChannel { this.memberCount ??= null; } + if ('total_message_sent' in data) { + /** + * The number of messages ever sent in a thread, similar to `ThreadChannel#messageCount` except it + * will not decrement whenever a message is deleted + * @type {?number} + */ + this.totalMessageSent = data.total_message_sent; + } else { + this.totalMessageSent ??= null; + } + if (data.member && this.client.user) this.members._add({ user_id: this.client.user.id, ...data.member }); if (data.messages) for (const message of data.messages) this.messages._add(message); } diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 5158dc1a4103..d51174402989 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -1698,6 +1698,7 @@ export class Message extends Base { public pinned: boolean; public reactions: ReactionManager; public stickers: Collection; + public position: number | null; public system: boolean; public get thread(): AnyThreadChannel | null; public tts: boolean; @@ -2531,6 +2532,7 @@ export class ThreadChannel extends TextBasedChannelMixin(BaseChannel, true, [ public get sendable(): boolean; public memberCount: number | null; public messageCount: number | null; + public totalMessageSent: number | null; public members: ThreadMemberManager; public name: string; public ownerId: Snowflake | null; @@ -3176,6 +3178,8 @@ export enum DiscordjsErrorCodes { NotImplemented = 'NotImplemented', SweepFilterReturn = 'SweepFilterReturn', + + GuildForumMessageRequired = 'GuildForumMessageRequired', } export interface DiscordjsErrorFields { @@ -3633,7 +3637,7 @@ export class GuildTextThreadManager extends ThreadManager { public create(options: GuildTextThreadCreateOptions): Promise; } -export class GuildForumThreadManger extends ThreadManager { +export class GuildForumThreadManager extends ThreadManager { public create(options: GuildForumThreadCreateOptions): Promise; } From ee20f2e1c4fbdb1cf638e1906f3a0fca34f6f7fa Mon Sep 17 00:00:00 2001 From: suneettipirneni Date: Tue, 30 Aug 2022 12:09:33 -0400 Subject: [PATCH 05/60] feat: add support for latest upstream changes --- .../src/managers/GuildChannelManager.js | 3 + .../src/managers/GuildForumThreadManager.js | 4 +- .../src/structures/GuildForumChannel.js | 82 +++++++++++++++++++ .../src/structures/ThreadChannel.js | 20 +++++ packages/discord.js/src/util/Channels.js | 30 +++++++ packages/discord.js/typings/index.d.ts | 29 ++++++- 6 files changed, 166 insertions(+), 2 deletions(-) diff --git a/packages/discord.js/src/managers/GuildChannelManager.js b/packages/discord.js/src/managers/GuildChannelManager.js index 455b404dff84..45e60e5df224 100644 --- a/packages/discord.js/src/managers/GuildChannelManager.js +++ b/packages/discord.js/src/managers/GuildChannelManager.js @@ -274,6 +274,9 @@ class GuildChannelManager extends CachedManager { rate_limit_per_user: data.rateLimitPerUser, default_auto_archive_duration: data.defaultAutoArchiveDuration, permission_overwrites, + available_tags: data.availableTags, + default_reaction_emoji: data.defaultReactionEmoji, + default_thread_rate_limit_per_user: data.defaultThreadRateLimitPerUser, }, reason: data.reason, }); diff --git a/packages/discord.js/src/managers/GuildForumThreadManager.js b/packages/discord.js/src/managers/GuildForumThreadManager.js index 2865309bb395..365d4e0c09bb 100644 --- a/packages/discord.js/src/managers/GuildForumThreadManager.js +++ b/packages/discord.js/src/managers/GuildForumThreadManager.js @@ -11,6 +11,7 @@ class GuildForumThreadManager extends ThreadManager { * Options for creating a thread. Only one of `startMessage` or `type` can be defined. * @typedef {StartThreadOptions} GuildForumThreadCreateOptions * @property {MessageOptions|MessagePayload} message The message associated with the thread post + * @property {GuildForumTag[]} [appliedTags] The tags to apply to the thread */ /** @@ -45,6 +46,7 @@ class GuildForumThreadManager extends ThreadManager { message, reason, rateLimitPerUser, + appliedTags, } = {}) { if (!message) { throw new TypeError(ErrorCodes.GuildForumMessageRequired); @@ -62,13 +64,13 @@ class GuildForumThreadManager extends ThreadManager { name, auto_archive_duration: autoArchiveDuration, rate_limit_per_user: rateLimitPerUser, + applied_tags: appliedTags, ...body, }, files, reason, }); - // TODO: Posts will most likely need to be serialized differently than regular threads. return this.client.actions.ThreadCreate.handle(data).thread; } } diff --git a/packages/discord.js/src/structures/GuildForumChannel.js b/packages/discord.js/src/structures/GuildForumChannel.js index 0ff0a3840c26..955fab9f316f 100644 --- a/packages/discord.js/src/structures/GuildForumChannel.js +++ b/packages/discord.js/src/structures/GuildForumChannel.js @@ -2,6 +2,23 @@ const GuildChannel = require('./GuildChannel'); const GuildForumThreadManager = require('../managers/GuildForumThreadManager'); +const { transformGuildForumTag, transformGuildDefaultReaction } = require('../util/Channels'); + +/** + * @typedef {Object} GuildForumTag + * @property {Snowflake} id The id of the tag + * @property {string} name The name of the tag + * @property {boolean} moderated Whether this tag can only be added to or removed from threads + * by a member with the `ManageThreads` permission + * @property {Snowflake} emojiId The id of a guild's custom emoji, or 0 if unset + * @property {string} [emojiName] The unicode character of the emoji + */ + +/** + * @typedef {Object} DefaultReaction + * @property {Snowflake} emojiId The id of a guild's custom emoji, or 0 if unset + * @property {string} [emojiName] The unicode character of the emoji + */ /** * Represents a channel that only contains threads @@ -16,6 +33,71 @@ class GuildForumChannel extends GuildChannel { * @type {GuildForumThreadManager} */ this.threads = new GuildForumThreadManager(this); + + this._patch(data); + } + + _patch(data) { + super._patch(data); + if ('available_tags' in data) { + /** + * The set of tags that can be used in this channel. + * @type {GuildForumTag[]} + */ + this.availableTags = data.available_tags.map(tag => transformGuildForumTag(tag)); + } else { + this.availableTags ??= []; + } + + if ('default_reaction_emoji' in data) { + /** + * The emoji to show in the add reaction button on a thread in a guild forum channel + * @type {DefaultReaction} + */ + this.defaultReaction = transformGuildDefaultReaction(data.default_reaction_emoji); + } else { + this.defaultReaction ??= null; + } + + if ('default_thread_rate_limit_per_user' in data) { + /** + * The initial rate_limit_per_user to set on newly created threads in a channel. + * @type {number} + */ + this.defaultThreadRateLimitPerUser = data.default_thread_rate_limit_per_user; + } else { + this.defaultThreadRateLimitPerUser ??= null; + } + } + + /** + * Sets the available tags for this forum channel + * @param {GuildForumTag[]} availableTags The tags to set as available in this channel + * @returns {Promise} + */ + async setAvailableTags(availableTags) { + await this.edit({ availableTags }); + return this; + } + + /** + * Sets the default reaction emoji for this channel + * @param {DefaultReaction} defaultReactionEmoji The emoji to set as the default reaction emoji + * @returns {Promise} + */ + async setDefaultReactionEmoji(defaultReactionEmoji) { + await this.edit({ defaultReactionEmoji }); + return this; + } + + /** + * Sets the default rate_limit_per_user for new threads in this channel + * @param {number} defaultThreadRateLimitPerUser The rate limit to set on newly created threads in this channel + * @returns {Promise} + */ + async setDefaultThreadRateLimitPerUser(defaultThreadRateLimitPerUser) { + await this.edit({ defaultThreadRateLimitPerUser }); + return this; } } diff --git a/packages/discord.js/src/structures/ThreadChannel.js b/packages/discord.js/src/structures/ThreadChannel.js index b87a88150656..e61eb60383f9 100644 --- a/packages/discord.js/src/structures/ThreadChannel.js +++ b/packages/discord.js/src/structures/ThreadChannel.js @@ -6,6 +6,7 @@ const TextBasedChannel = require('./interfaces/TextBasedChannel'); const { RangeError, ErrorCodes } = require('../errors'); const MessageManager = require('../managers/MessageManager'); const ThreadMemberManager = require('../managers/ThreadMemberManager'); +const { transformGuildForumTag } = require('../util/Channels'); /** * Represents a thread channel on Discord. @@ -193,6 +194,14 @@ class ThreadChannel extends BaseChannel { if (data.member && this.client.user) this.members._add({ user_id: this.client.user.id, ...data.member }); if (data.messages) for (const message of data.messages) this.messages._add(message); + + if ('applied_tags' in data) { + /** + * The tags applied to this thread + * @type {?GuildForumTag[]} + */ + this.appliedTags = data.applied_tags.map(tag => transformGuildForumTag(tag)); + } } /** @@ -334,6 +343,7 @@ class ThreadChannel extends BaseChannel { rate_limit_per_user: data.rateLimitPerUser, locked: data.locked, invitable: this.type === ChannelType.PrivateThread ? data.invitable : undefined, + applied_tags: data.appliedTags, }, reason: data.reason, }); @@ -430,6 +440,16 @@ class ThreadChannel extends BaseChannel { return this.edit({ rateLimitPerUser, reason }); } + /** + * Set the applied tags for this channel (only applicable to forum threads) + * @param {GuildForumTag[]} appliedTags The tags to set for this channel + * @returns {Promise} + */ + async setAppliedTags(appliedTags) { + await this.edit({ appliedTags }); + return this; + } + /** * Whether the client user is a member of the thread. * @type {boolean} diff --git a/packages/discord.js/src/util/Channels.js b/packages/discord.js/src/util/Channels.js index a1dc1de4222d..fff78a4166b1 100644 --- a/packages/discord.js/src/util/Channels.js +++ b/packages/discord.js/src/util/Channels.js @@ -72,6 +72,36 @@ function createChannel(client, data, guild, { allowUnknownGuild, fromInteraction return channel; } +/** + * Transforms an api guild forum tag to camelcased guild forum tag. + * @param {GuildForumTag} tag The tag to transform + * @returns {GuildForumTag} + */ +function transformGuildForumTag(tag) { + return { + id: tag.id, + name: tag.name, + moderated: tag.moderated, + emojiId: tag.emoji_id, + emojiName: tag.emoji_name, + }; +} + +/** + * Transforms an api guild forum default reaction object to a + * camelcased guild forum default reaction object. + * @param {APIDefaultReaction} defaultReaction The default reaction to transform + * @returns {DefaultReaction} + */ +function transformGuildDefaultReaction(defaultReaction) { + return { + emojiId: defaultReaction.emoji_id, + emojiName: defaultReaction.emoji_name, + }; +} + module.exports = { + transformGuildDefaultReaction, + transformGuildForumTag, createChannel, }; diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index d51174402989..448c87182e05 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -2040,6 +2040,30 @@ export class PartialGroupDMChannel extends BaseChannel { public toString(): ChannelMention; } +export interface GuildForumTag { + id: Snowflake; + name: string; + moderated: boolean; + emojiId?: Snowflake | null; + emoji?: GuildEmoji | null; +} + +export interface DefaultReaction { + emojiId: Snowflake; + emojiName?: string; +} + +export class GuildForumChannel extends GuildChannel { + public threads: GuildForumThreadManager; + public availableTags: GuildForumTag[]; + public defaultReactionEmoji: DefaultReaction | null; + public defaultThreadRateLimitPerUser: number | null; + + public setAvailableTags(tags: GuildForumTag[]): Promise; + public setDefaultReaction(emojiId: DefaultReaction): Promise; + public setDefaultThreadRateLimitPerUser(rateLimit: number): Promise; +} + export class PermissionOverwrites extends Base { private constructor(client: Client, data: RawPermissionOverwriteData, channel: NonThreadGuildBasedChannel); public allow: Readonly; @@ -2560,6 +2584,7 @@ export class ThreadChannel extends TextBasedChannelMixin(BaseChannel, true, [ public setInvitable(invitable?: boolean, reason?: string): Promise; public setLocked(locked?: boolean, reason?: string): Promise; public setName(name: string, reason?: string): Promise; + public setAppliedTags(appliedTags: GuildForumTag[]): Promise; public toString(): ChannelMention; } @@ -5549,7 +5574,8 @@ export type Channel = | StageChannel | TextChannel | AnyThreadChannel - | VoiceChannel; + | VoiceChannel + | GuildForumChannel; export type TextBasedChannel = Exclude, PartialGroupDMChannel>; @@ -5581,6 +5607,7 @@ export interface GuildTextThreadCreateOptions extends StartTh export interface GuildForumThreadCreateOptions extends StartThreadOptions { message: MessageOptions | MessagePayload; + appliedTags?: GuildForumTag[]; } export interface ThreadEditData { From a39129e3eaa4bc53cfa5d3fcf0bb56e6496250f6 Mon Sep 17 00:00:00 2001 From: suneettipirneni Date: Thu, 1 Sep 2022 22:02:48 -0400 Subject: [PATCH 06/60] fix: serialize forum channels --- packages/discord.js/src/util/Channels.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/discord.js/src/util/Channels.js b/packages/discord.js/src/util/Channels.js index fff78a4166b1..adfa95948f12 100644 --- a/packages/discord.js/src/util/Channels.js +++ b/packages/discord.js/src/util/Channels.js @@ -12,6 +12,7 @@ const getThreadChannel = lazy(() => require('../structures/ThreadChannel')); const getVoiceChannel = lazy(() => require('../structures/VoiceChannel')); const getDirectoryChannel = lazy(() => require('../structures/DirectoryChannel')); const getPartialGroupDMChannel = lazy(() => require('../structures/PartialGroupDMChannel')); +const getForumChannel = lazy(() => require('../structures/GuildForumChannel')); /** * Creates a discord.js channel from data received from the API. @@ -65,6 +66,9 @@ function createChannel(client, data, guild, { allowUnknownGuild, fromInteraction case ChannelType.GuildDirectory: channel = new (getDirectoryChannel())(guild, data, client); break; + case ChannelType.GuildForum: + channel = new (getForumChannel())(guild, data, client); + break; } if (channel && !allowUnknownGuild) guild.channels?.cache.set(channel.id, channel); } From 09388317ce61b9f1316d41e7a8bd4f00a7fae10d Mon Sep 17 00:00:00 2001 From: suneettipirneni Date: Thu, 1 Sep 2022 22:17:31 -0400 Subject: [PATCH 07/60] types: fix channel unions --- packages/discord.js/typings/index.d.ts | 10 +++++++--- packages/discord.js/typings/index.test-d.ts | 3 ++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 448c87182e05..bc493852d36d 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -2054,6 +2054,7 @@ export interface DefaultReaction { } export class GuildForumChannel extends GuildChannel { + public type: ChannelType.GuildForum; public threads: GuildForumThreadManager; public availableTags: GuildForumTag[]; public defaultReactionEmoji: DefaultReaction | null; @@ -2518,7 +2519,7 @@ export class TextChannel extends BaseGuildTextChannel { public type: ChannelType.GuildText; } -export type AnyThreadChannel = PublicThreadChannel | PrivateThreadChannel; +export type AnyThreadChannel = PublicThreadChannel | PrivateThreadChannel | GuildForumChannel; export interface PublicThreadChannel extends ThreadChannel { type: ChannelType.PublicThread | ChannelType.AnnouncementThread; @@ -5577,7 +5578,10 @@ export type Channel = | VoiceChannel | GuildForumChannel; -export type TextBasedChannel = Exclude, PartialGroupDMChannel>; +export type TextBasedChannel = Exclude< + Extract, + PartialGroupDMChannel | GuildForumChannel +>; export type TextBasedChannelTypes = TextBasedChannel['type']; @@ -5589,7 +5593,7 @@ export type CategoryChildChannel = Exclude; -export type GuildTextBasedChannel = Extract; +export type GuildTextBasedChannel = Exclude, GuildForumChannel>; export type TextChannelResolvable = Snowflake | TextChannel; diff --git a/packages/discord.js/typings/index.test-d.ts b/packages/discord.js/typings/index.test-d.ts index 394afc329e11..9c7ac111bf71 100644 --- a/packages/discord.js/typings/index.test-d.ts +++ b/packages/discord.js/typings/index.test-d.ts @@ -137,6 +137,7 @@ import { GuildAuditLogsActionType, GuildAuditLogsTargetType, ModalSubmitInteraction, + GuildForumChannel, } from '.'; import { expectAssignable, expectNotAssignable, expectNotType, expectType } from 'tsd'; import type { ContextMenuCommandBuilder, SlashCommandBuilder } from '@discordjs/builders'; @@ -1360,7 +1361,7 @@ declare const categoryChannelChildManager: CategoryChannelChildManager; declare const guildChannelManager: GuildChannelManager; { - type AnyChannel = TextChannel | VoiceChannel | CategoryChannel | NewsChannel | StageChannel; + type AnyChannel = TextChannel | VoiceChannel | CategoryChannel | NewsChannel | StageChannel | GuildForumChannel; expectType>(guildChannelManager.create({ name: 'name' })); expectType>(guildChannelManager.create({ name: 'name' })); From 89686848de335df420229b81b14cbdf4f5ed37fb Mon Sep 17 00:00:00 2001 From: suneettipirneni Date: Thu, 1 Sep 2022 22:30:45 -0400 Subject: [PATCH 08/60] types: fix tests --- packages/discord.js/typings/index.test-d.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/discord.js/typings/index.test-d.ts b/packages/discord.js/typings/index.test-d.ts index 9c7ac111bf71..79ca134d2351 100644 --- a/packages/discord.js/typings/index.test-d.ts +++ b/packages/discord.js/typings/index.test-d.ts @@ -1372,8 +1372,10 @@ declare const guildChannelManager: GuildChannelManager; expectType>(guildChannelManager.create({ name: 'name', type: ChannelType.GuildStageVoice })); expectType>>(guildChannelManager.fetch()); - expectType>>(guildChannelManager.fetch(undefined, {})); - expectType>(guildChannelManager.fetch('0')); + expectType>>( + guildChannelManager.fetch(undefined, {}), + ); + expectType>(guildChannelManager.fetch('0')); const channel = guildChannelManager.cache.first()!; From 8f9c78a430fd35763dafd2618946d7df7e0be71e Mon Sep 17 00:00:00 2001 From: suneettipirneni Date: Thu, 1 Sep 2022 22:37:24 -0400 Subject: [PATCH 09/60] types: fix tests (again) --- packages/discord.js/typings/index.test-d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/discord.js/typings/index.test-d.ts b/packages/discord.js/typings/index.test-d.ts index 79ca134d2351..6abd7372677a 100644 --- a/packages/discord.js/typings/index.test-d.ts +++ b/packages/discord.js/typings/index.test-d.ts @@ -1371,7 +1371,7 @@ declare const guildChannelManager: GuildChannelManager; expectType>(guildChannelManager.create({ name: 'name', type: ChannelType.GuildAnnouncement })); expectType>(guildChannelManager.create({ name: 'name', type: ChannelType.GuildStageVoice })); - expectType>>(guildChannelManager.fetch()); + expectType>>(guildChannelManager.fetch()); expectType>>( guildChannelManager.fetch(undefined, {}), ); From 73a187778cc9de80cc58167453bdd6a609a0a3fe Mon Sep 17 00:00:00 2001 From: suneettipirneni Date: Thu, 1 Sep 2022 22:55:06 -0400 Subject: [PATCH 10/60] types: fix tests (again (again)) --- packages/discord.js/typings/index.test-d.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/discord.js/typings/index.test-d.ts b/packages/discord.js/typings/index.test-d.ts index 6abd7372677a..f143d4da86ca 100644 --- a/packages/discord.js/typings/index.test-d.ts +++ b/packages/discord.js/typings/index.test-d.ts @@ -1361,8 +1361,6 @@ declare const categoryChannelChildManager: CategoryChannelChildManager; declare const guildChannelManager: GuildChannelManager; { - type AnyChannel = TextChannel | VoiceChannel | CategoryChannel | NewsChannel | StageChannel | GuildForumChannel; - expectType>(guildChannelManager.create({ name: 'name' })); expectType>(guildChannelManager.create({ name: 'name' })); expectType>(guildChannelManager.create({ name: 'name', type: ChannelType.GuildVoice })); From 3704d2010c46b452565fc75f6cd7fb7f9d305b79 Mon Sep 17 00:00:00 2001 From: suneettipirneni Date: Tue, 13 Sep 2022 10:54:12 -0400 Subject: [PATCH 11/60] chore: make requested changes --- packages/discord.js/src/index.js | 1 + packages/discord.js/src/managers/ThreadManager.js | 7 ------- packages/discord.js/typings/index.d.ts | 2 +- packages/discord.js/typings/index.test-d.ts | 2 +- 4 files changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/discord.js/src/index.js b/packages/discord.js/src/index.js index 7003ae6b19ff..d4183ba834cc 100644 --- a/packages/discord.js/src/index.js +++ b/packages/discord.js/src/index.js @@ -58,6 +58,7 @@ exports.GuildBanManager = require('./managers/GuildBanManager'); exports.GuildChannelManager = require('./managers/GuildChannelManager'); exports.GuildEmojiManager = require('./managers/GuildEmojiManager'); exports.GuildEmojiRoleManager = require('./managers/GuildEmojiRoleManager'); +exports.GuildForumThreadManager = require('./managers/GuildForumThreadManager'); exports.GuildInviteManager = require('./managers/GuildInviteManager'); exports.GuildManager = require('./managers/GuildManager'); exports.GuildMemberManager = require('./managers/GuildMemberManager'); diff --git a/packages/discord.js/src/managers/ThreadManager.js b/packages/discord.js/src/managers/ThreadManager.js index 4ed1cae7fdb1..474f5bac370a 100644 --- a/packages/discord.js/src/managers/ThreadManager.js +++ b/packages/discord.js/src/managers/ThreadManager.js @@ -42,13 +42,6 @@ class ThreadManager extends CachedManager { return thread; } - /** - * Data that can be resolved to a Thread Channel object. This can be: - * * A ThreadChannel object - * * A Snowflake - * @typedef {ThreadChannel|Snowflake} ThreadChannelResolvable - */ - /** * Resolves a {@link ThreadChannelResolvable} to a {@link ThreadChannel} object. * @method resolve diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index bc493852d36d..3b9b8dbc7fc7 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -5610,7 +5610,7 @@ export interface GuildTextThreadCreateOptions extends StartTh } export interface GuildForumThreadCreateOptions extends StartThreadOptions { - message: MessageOptions | MessagePayload; + message: BaseMessageOptions | MessagePayload; appliedTags?: GuildForumTag[]; } diff --git a/packages/discord.js/typings/index.test-d.ts b/packages/discord.js/typings/index.test-d.ts index f143d4da86ca..2f8303ff1b57 100644 --- a/packages/discord.js/typings/index.test-d.ts +++ b/packages/discord.js/typings/index.test-d.ts @@ -1373,7 +1373,7 @@ declare const guildChannelManager: GuildChannelManager; expectType>>( guildChannelManager.fetch(undefined, {}), ); - expectType>(guildChannelManager.fetch('0')); + expectType>(guildChannelManager.fetch('0')); const channel = guildChannelManager.cache.first()!; From 2353b6389dbe2a1aafd04f6bc036489dbf174cbc Mon Sep 17 00:00:00 2001 From: suneettipirneni Date: Tue, 13 Sep 2022 12:06:33 -0400 Subject: [PATCH 12/60] chore: fix bugs and make requested changes --- packages/discord.js/src/index.js | 1 + .../src/managers/GuildForumThreadManager.js | 8 ++++--- .../src/structures/GuildForumChannel.js | 21 ++++++++++++------- .../src/structures/ThreadChannel.js | 5 +++-- packages/discord.js/typings/index.d.ts | 10 ++++----- packages/discord.js/typings/index.test-d.ts | 4 +++- 6 files changed, 30 insertions(+), 19 deletions(-) diff --git a/packages/discord.js/src/index.js b/packages/discord.js/src/index.js index d4183ba834cc..69d5b98ba222 100644 --- a/packages/discord.js/src/index.js +++ b/packages/discord.js/src/index.js @@ -117,6 +117,7 @@ exports.GuildAuditLogsEntry = require('./structures/GuildAuditLogsEntry'); exports.GuildBan = require('./structures/GuildBan'); exports.GuildChannel = require('./structures/GuildChannel'); exports.GuildEmoji = require('./structures/GuildEmoji'); +exports.GuildForumChannel = require('./structures/GuildForumChannel'); exports.GuildMember = require('./structures/GuildMember').GuildMember; exports.GuildPreview = require('./structures/GuildPreview'); exports.GuildPreviewEmoji = require('./structures/GuildPreviewEmoji'); diff --git a/packages/discord.js/src/managers/GuildForumThreadManager.js b/packages/discord.js/src/managers/GuildForumThreadManager.js index 365d4e0c09bb..a32abafc2400 100644 --- a/packages/discord.js/src/managers/GuildForumThreadManager.js +++ b/packages/discord.js/src/managers/GuildForumThreadManager.js @@ -53,10 +53,12 @@ class GuildForumThreadManager extends ThreadManager { } const messagePayload = - message instanceof MessagePayload ? message.resolveBody() : MessagePayload.create(this, message); + message instanceof MessagePayload ? message.resolveBody() : MessagePayload.create(this, message).resolveBody(); - const { body, files } = messagePayload.resolveFiles(); + console.log(messagePayload); + const { body, files } = await messagePayload.resolveFiles(); + console.log(body); if (autoArchiveDuration === 'MAX') autoArchiveDuration = resolveAutoArchiveMaxLimit(this.channel.guild); const data = await this.client.rest.post(Routes.threads(this.channel.id), { @@ -65,7 +67,7 @@ class GuildForumThreadManager extends ThreadManager { auto_archive_duration: autoArchiveDuration, rate_limit_per_user: rateLimitPerUser, applied_tags: appliedTags, - ...body, + message: body, }, files, reason, diff --git a/packages/discord.js/src/structures/GuildForumChannel.js b/packages/discord.js/src/structures/GuildForumChannel.js index 955fab9f316f..2aac4e068a99 100644 --- a/packages/discord.js/src/structures/GuildForumChannel.js +++ b/packages/discord.js/src/structures/GuildForumChannel.js @@ -54,9 +54,11 @@ class GuildForumChannel extends GuildChannel { * The emoji to show in the add reaction button on a thread in a guild forum channel * @type {DefaultReaction} */ - this.defaultReaction = transformGuildDefaultReaction(data.default_reaction_emoji); + this.defaultReactionEmoji = data.default_reaction_emoji + ? transformGuildDefaultReaction(data.default_reaction_emoji) + : null; } else { - this.defaultReaction ??= null; + this.defaultReactionEmoji ??= null; } if ('default_thread_rate_limit_per_user' in data) { @@ -73,30 +75,33 @@ class GuildForumChannel extends GuildChannel { /** * Sets the available tags for this forum channel * @param {GuildForumTag[]} availableTags The tags to set as available in this channel + * @param {string} [reason] Reason for changing the available tags * @returns {Promise} */ - async setAvailableTags(availableTags) { - await this.edit({ availableTags }); + async setAvailableTags(availableTags, reason) { + await this.edit({ availableTags, reason }); return this; } /** * Sets the default reaction emoji for this channel * @param {DefaultReaction} defaultReactionEmoji The emoji to set as the default reaction emoji + * @param {string} [reason] Reason for changing the default reaction emoji * @returns {Promise} */ - async setDefaultReactionEmoji(defaultReactionEmoji) { - await this.edit({ defaultReactionEmoji }); + async setDefaultReactionEmoji(defaultReactionEmoji, reason) { + await this.edit({ defaultReactionEmoji, reason }); return this; } /** * Sets the default rate_limit_per_user for new threads in this channel * @param {number} defaultThreadRateLimitPerUser The rate limit to set on newly created threads in this channel + * @param {string} [reason] Reason for changing the default rate limit * @returns {Promise} */ - async setDefaultThreadRateLimitPerUser(defaultThreadRateLimitPerUser) { - await this.edit({ defaultThreadRateLimitPerUser }); + async setDefaultThreadRateLimitPerUser(defaultThreadRateLimitPerUser, reason) { + await this.edit({ defaultThreadRateLimitPerUser, reason }); return this; } } diff --git a/packages/discord.js/src/structures/ThreadChannel.js b/packages/discord.js/src/structures/ThreadChannel.js index e61eb60383f9..12104cd110f5 100644 --- a/packages/discord.js/src/structures/ThreadChannel.js +++ b/packages/discord.js/src/structures/ThreadChannel.js @@ -443,10 +443,11 @@ class ThreadChannel extends BaseChannel { /** * Set the applied tags for this channel (only applicable to forum threads) * @param {GuildForumTag[]} appliedTags The tags to set for this channel + * @param {string} [reason] Reason for changing the thread's applied tags * @returns {Promise} */ - async setAppliedTags(appliedTags) { - await this.edit({ appliedTags }); + async setAppliedTags(appliedTags, reason) { + await this.edit({ appliedTags, reason }); return this; } diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 3b9b8dbc7fc7..6b8c17f174f0 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -2060,9 +2060,9 @@ export class GuildForumChannel extends GuildChannel { public defaultReactionEmoji: DefaultReaction | null; public defaultThreadRateLimitPerUser: number | null; - public setAvailableTags(tags: GuildForumTag[]): Promise; - public setDefaultReaction(emojiId: DefaultReaction): Promise; - public setDefaultThreadRateLimitPerUser(rateLimit: number): Promise; + public setAvailableTags(tags: GuildForumTag[], reason?: string): Promise; + public setDefaultReaction(emojiId: DefaultReaction, reason?: string): Promise; + public setDefaultThreadRateLimitPerUser(rateLimit: number, reason?: string): Promise; } export class PermissionOverwrites extends Base { @@ -2519,7 +2519,7 @@ export class TextChannel extends BaseGuildTextChannel { public type: ChannelType.GuildText; } -export type AnyThreadChannel = PublicThreadChannel | PrivateThreadChannel | GuildForumChannel; +export type AnyThreadChannel = PublicThreadChannel | PrivateThreadChannel; export interface PublicThreadChannel extends ThreadChannel { type: ChannelType.PublicThread | ChannelType.AnnouncementThread; @@ -2585,7 +2585,7 @@ export class ThreadChannel extends TextBasedChannelMixin(BaseChannel, true, [ public setInvitable(invitable?: boolean, reason?: string): Promise; public setLocked(locked?: boolean, reason?: string): Promise; public setName(name: string, reason?: string): Promise; - public setAppliedTags(appliedTags: GuildForumTag[]): Promise; + public setAppliedTags(appliedTags: GuildForumTag[], reason?: string): Promise; public toString(): ChannelMention; } diff --git a/packages/discord.js/typings/index.test-d.ts b/packages/discord.js/typings/index.test-d.ts index 2f8303ff1b57..7a3110803923 100644 --- a/packages/discord.js/typings/index.test-d.ts +++ b/packages/discord.js/typings/index.test-d.ts @@ -1847,7 +1847,9 @@ expectType< >(TextBasedChannelTypes); expectType(VoiceBasedChannel); expectType(GuildBasedChannel); -expectType(NonThreadGuildBasedChannel); +expectType( + NonThreadGuildBasedChannel, +); expectType(GuildTextBasedChannel); const button = new ButtonBuilder({ From 36ff6ef53005e747b67b88215ed8d6717e4c9b44 Mon Sep 17 00:00:00 2001 From: suneettipirneni Date: Tue, 13 Sep 2022 12:14:22 -0400 Subject: [PATCH 13/60] types: use correct type for guild forum start messages --- packages/discord.js/typings/index.d.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 6b8c17f174f0..5eb4f218fd3b 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -5241,6 +5241,8 @@ export interface MessageCreateOptions extends BaseMessageOptions { flags?: BitFieldResolvable, MessageFlags.SuppressEmbeds>; } +export type GuildForumThreadMessageCreateOptions = Omit; + export interface MessageEditOptions extends Omit { content?: string | null; attachments?: JSONEncodable[]; @@ -5610,7 +5612,7 @@ export interface GuildTextThreadCreateOptions extends StartTh } export interface GuildForumThreadCreateOptions extends StartThreadOptions { - message: BaseMessageOptions | MessagePayload; + message: GuildForumThreadMessageCreateOptions | MessagePayload; appliedTags?: GuildForumTag[]; } From ee6c7c731f76854024a963eb0e4f50a42942cd4d Mon Sep 17 00:00:00 2001 From: suneettipirneni Date: Tue, 13 Sep 2022 12:17:56 -0400 Subject: [PATCH 14/60] chore: remove console.log --- packages/discord.js/src/managers/GuildForumThreadManager.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/discord.js/src/managers/GuildForumThreadManager.js b/packages/discord.js/src/managers/GuildForumThreadManager.js index a32abafc2400..1c515a64395e 100644 --- a/packages/discord.js/src/managers/GuildForumThreadManager.js +++ b/packages/discord.js/src/managers/GuildForumThreadManager.js @@ -55,10 +55,7 @@ class GuildForumThreadManager extends ThreadManager { const messagePayload = message instanceof MessagePayload ? message.resolveBody() : MessagePayload.create(this, message).resolveBody(); - console.log(messagePayload); const { body, files } = await messagePayload.resolveFiles(); - - console.log(body); if (autoArchiveDuration === 'MAX') autoArchiveDuration = resolveAutoArchiveMaxLimit(this.channel.guild); const data = await this.client.rest.post(Routes.threads(this.channel.id), { From 0f9261cd0486804f9a71055953af575d09defbeb Mon Sep 17 00:00:00 2001 From: suneettipirneni Date: Tue, 13 Sep 2022 12:23:57 -0400 Subject: [PATCH 15/60] chore: make requested changes --- packages/discord.js/src/managers/GuildForumThreadManager.js | 6 ++++++ packages/discord.js/src/util/Channels.js | 6 +++--- packages/discord.js/typings/index.d.ts | 5 +++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/discord.js/src/managers/GuildForumThreadManager.js b/packages/discord.js/src/managers/GuildForumThreadManager.js index 1c515a64395e..20b4ed3b0ebb 100644 --- a/packages/discord.js/src/managers/GuildForumThreadManager.js +++ b/packages/discord.js/src/managers/GuildForumThreadManager.js @@ -7,6 +7,12 @@ const MessagePayload = require('../structures/MessagePayload'); const { resolveAutoArchiveMaxLimit } = require('../util/Util'); class GuildForumThreadManager extends ThreadManager { + /** + * @typedef {BaseMessageOptions} GuildForumThreadCreateOptions + * @property {stickers} [stickers] The stickers to send with the message + * @property {BitFieldResolvable} [flags] The flags to send with the message + */ + /** * Options for creating a thread. Only one of `startMessage` or `type` can be defined. * @typedef {StartThreadOptions} GuildForumThreadCreateOptions diff --git a/packages/discord.js/src/util/Channels.js b/packages/discord.js/src/util/Channels.js index adfa95948f12..9d206da03e0b 100644 --- a/packages/discord.js/src/util/Channels.js +++ b/packages/discord.js/src/util/Channels.js @@ -77,7 +77,7 @@ function createChannel(client, data, guild, { allowUnknownGuild, fromInteraction } /** - * Transforms an api guild forum tag to camelcased guild forum tag. + * Transforms an API guild forum tag to camel-cased guild forum tag. * @param {GuildForumTag} tag The tag to transform * @returns {GuildForumTag} */ @@ -92,8 +92,8 @@ function transformGuildForumTag(tag) { } /** - * Transforms an api guild forum default reaction object to a - * camelcased guild forum default reaction object. + * Transforms an API guild forum default reaction object to a + * camel-cased guild forum default reaction object. * @param {APIDefaultReaction} defaultReaction The default reaction to transform * @returns {DefaultReaction} */ diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 5eb4f218fd3b..cb3b63c877d0 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -125,7 +125,7 @@ import { AuditLogOptionsType, TextChannelType, } from 'discord-api-types/v10'; -import { ChildProcess } from 'node:child_process'; +import { ChildProcess, MessageOptions } from 'node:child_process'; import { EventEmitter } from 'node:events'; import { Stream } from 'node:stream'; import { MessagePort, Worker } from 'node:worker_threads'; @@ -5241,7 +5241,8 @@ export interface MessageCreateOptions extends BaseMessageOptions { flags?: BitFieldResolvable, MessageFlags.SuppressEmbeds>; } -export type GuildForumThreadMessageCreateOptions = Omit; +export type GuildForumThreadMessageCreateOptions = BaseMessageOptions & + Pick; export interface MessageEditOptions extends Omit { content?: string | null; From aedb3d39a3f5426eb56d5a30ed1412907e850636 Mon Sep 17 00:00:00 2001 From: suneettipirneni Date: Tue, 13 Sep 2022 12:41:13 -0400 Subject: [PATCH 16/60] chore: make requested changes --- .../src/managers/GuildForumThreadManager.js | 20 ++++++------------- .../discord.js/src/managers/ThreadManager.js | 2 +- .../src/structures/GuildForumChannel.js | 2 +- .../src/structures/ThreadChannel.js | 2 +- 4 files changed, 9 insertions(+), 17 deletions(-) diff --git a/packages/discord.js/src/managers/GuildForumThreadManager.js b/packages/discord.js/src/managers/GuildForumThreadManager.js index 20b4ed3b0ebb..fa324e9c9606 100644 --- a/packages/discord.js/src/managers/GuildForumThreadManager.js +++ b/packages/discord.js/src/managers/GuildForumThreadManager.js @@ -25,26 +25,18 @@ class GuildForumThreadManager extends ThreadManager { * @param {GuildForumThreadCreateOptions} [options] Options to create a new thread * @returns {Promise} * @example - * // Create a new public thread - * channel.threads + * // Create a new forum post + * forum.threads * .create({ - * name: 'food-talk', + * name: 'Food Talk', * autoArchiveDuration: 60, + * message: { + * content: 'Discuss your favorite food!', + * }} * reason: 'Needed a separate thread for food', * }) * .then(threadChannel => console.log(threadChannel)) * .catch(console.error); - * @example - * // Create a new private thread - * channel.threads - * .create({ - * name: 'mod-talk', - * autoArchiveDuration: 60, - * type: ChannelType.GuildPrivateThread, - * reason: 'Needed a separate thread for moderation', - * }) - * .then(threadChannel => console.log(threadChannel)) - * .catch(console.error); */ async create({ name, diff --git a/packages/discord.js/src/managers/ThreadManager.js b/packages/discord.js/src/managers/ThreadManager.js index 474f5bac370a..1adc914ec091 100644 --- a/packages/discord.js/src/managers/ThreadManager.js +++ b/packages/discord.js/src/managers/ThreadManager.js @@ -8,7 +8,7 @@ const { TypeError, ErrorCodes } = require('../errors'); const ThreadChannel = require('../structures/ThreadChannel'); /** - * Manages API methods for thread based channels and stores their cache. + * Manages API methods for thread-based channels and stores their cache. * @extends {CachedManager} */ class ThreadManager extends CachedManager { diff --git a/packages/discord.js/src/structures/GuildForumChannel.js b/packages/discord.js/src/structures/GuildForumChannel.js index 2aac4e068a99..ce011231415c 100644 --- a/packages/discord.js/src/structures/GuildForumChannel.js +++ b/packages/discord.js/src/structures/GuildForumChannel.js @@ -95,7 +95,7 @@ class GuildForumChannel extends GuildChannel { } /** - * Sets the default rate_limit_per_user for new threads in this channel + * Sets the default rate limit per user (slowmode) for new threads in this channel * @param {number} defaultThreadRateLimitPerUser The rate limit to set on newly created threads in this channel * @param {string} [reason] Reason for changing the default rate limit * @returns {Promise} diff --git a/packages/discord.js/src/structures/ThreadChannel.js b/packages/discord.js/src/structures/ThreadChannel.js index 12104cd110f5..15bd64b66122 100644 --- a/packages/discord.js/src/structures/ThreadChannel.js +++ b/packages/discord.js/src/structures/ThreadChannel.js @@ -183,7 +183,7 @@ class ThreadChannel extends BaseChannel { if ('total_message_sent' in data) { /** - * The number of messages ever sent in a thread, similar to `ThreadChannel#messageCount` except it + * The number of messages ever sent in a thread, similar to {@link ThreadChannel#messageCount} except it * will not decrement whenever a message is deleted * @type {?number} */ From 24e2b4c420ce5ba8c3ad638ddfc91972e3b879ea Mon Sep 17 00:00:00 2001 From: suneettipirneni Date: Tue, 13 Sep 2022 12:51:36 -0400 Subject: [PATCH 17/60] chore: fix docs --- packages/discord.js/src/managers/GuildForumThreadManager.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/discord.js/src/managers/GuildForumThreadManager.js b/packages/discord.js/src/managers/GuildForumThreadManager.js index fa324e9c9606..a117f4404ba6 100644 --- a/packages/discord.js/src/managers/GuildForumThreadManager.js +++ b/packages/discord.js/src/managers/GuildForumThreadManager.js @@ -6,6 +6,10 @@ const { TypeError, ErrorCodes } = require('../errors'); const MessagePayload = require('../structures/MessagePayload'); const { resolveAutoArchiveMaxLimit } = require('../util/Util'); +/** + * Manages API methods for thread in forum channels and stores their cache. + * @extends {ThreadManager} + */ class GuildForumThreadManager extends ThreadManager { /** * @typedef {BaseMessageOptions} GuildForumThreadCreateOptions @@ -32,7 +36,7 @@ class GuildForumThreadManager extends ThreadManager { * autoArchiveDuration: 60, * message: { * content: 'Discuss your favorite food!', - * }} + * }, * reason: 'Needed a separate thread for food', * }) * .then(threadChannel => console.log(threadChannel)) From 5385ccf1bf7fc34df09c3552a1559ca34644ab4e Mon Sep 17 00:00:00 2001 From: Suneet Tipirneni <77477100+suneettipirneni@users.noreply.github.com> Date: Tue, 13 Sep 2022 20:59:54 -0400 Subject: [PATCH 18/60] Update packages/discord.js/src/managers/GuildForumThreadManager.js Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com> --- packages/discord.js/src/managers/GuildForumThreadManager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/discord.js/src/managers/GuildForumThreadManager.js b/packages/discord.js/src/managers/GuildForumThreadManager.js index a117f4404ba6..6669b586a268 100644 --- a/packages/discord.js/src/managers/GuildForumThreadManager.js +++ b/packages/discord.js/src/managers/GuildForumThreadManager.js @@ -7,7 +7,7 @@ const MessagePayload = require('../structures/MessagePayload'); const { resolveAutoArchiveMaxLimit } = require('../util/Util'); /** - * Manages API methods for thread in forum channels and stores their cache. + * Manages API methods for threads in forum channels and stores their cache. * @extends {ThreadManager} */ class GuildForumThreadManager extends ThreadManager { From 0df75a723be80c7cea228496feb47a91f061083c Mon Sep 17 00:00:00 2001 From: suneettipirneni Date: Wed, 14 Sep 2022 14:41:07 -0400 Subject: [PATCH 19/60] chore: update types --- .../src/managers/GuildForumThreadManager.js | 2 +- .../discord.js/src/structures/GuildForumChannel.js | 8 ++++---- packages/discord.js/typings/index.d.ts | 14 +++++++------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/discord.js/src/managers/GuildForumThreadManager.js b/packages/discord.js/src/managers/GuildForumThreadManager.js index 6669b586a268..4bcb5742ff8b 100644 --- a/packages/discord.js/src/managers/GuildForumThreadManager.js +++ b/packages/discord.js/src/managers/GuildForumThreadManager.js @@ -20,7 +20,7 @@ class GuildForumThreadManager extends ThreadManager { /** * Options for creating a thread. Only one of `startMessage` or `type` can be defined. * @typedef {StartThreadOptions} GuildForumThreadCreateOptions - * @property {MessageOptions|MessagePayload} message The message associated with the thread post + * @property {GuildForumThreadCreateOptions|MessagePayload} message The message associated with the thread post * @property {GuildForumTag[]} [appliedTags] The tags to apply to the thread */ diff --git a/packages/discord.js/src/structures/GuildForumChannel.js b/packages/discord.js/src/structures/GuildForumChannel.js index ce011231415c..d969dc1981ea 100644 --- a/packages/discord.js/src/structures/GuildForumChannel.js +++ b/packages/discord.js/src/structures/GuildForumChannel.js @@ -10,14 +10,14 @@ const { transformGuildForumTag, transformGuildDefaultReaction } = require('../ut * @property {string} name The name of the tag * @property {boolean} moderated Whether this tag can only be added to or removed from threads * by a member with the `ManageThreads` permission - * @property {Snowflake} emojiId The id of a guild's custom emoji, or 0 if unset - * @property {string} [emojiName] The unicode character of the emoji + * @property {?Snowflake} emojiId The id of a guild's custom emoji, or 0 if unset + * @property {?string} emojiName The unicode character of the emoji */ /** * @typedef {Object} DefaultReaction - * @property {Snowflake} emojiId The id of a guild's custom emoji, or 0 if unset - * @property {string} [emojiName] The unicode character of the emoji + * @property {?Snowflake} emojiId The id of a guild's custom emoji, or 0 if unset + * @property {?string} emojiName The unicode character of the emoji */ /** diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index cb3b63c877d0..162763d32d32 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -2044,24 +2044,24 @@ export interface GuildForumTag { id: Snowflake; name: string; moderated: boolean; - emojiId?: Snowflake | null; - emoji?: GuildEmoji | null; + emojiId: Snowflake | null; + emojiName: string | null; } -export interface DefaultReaction { - emojiId: Snowflake; - emojiName?: string; +export interface DefaultReactionEmoji { + emojiId: Snowflake | null; + emojiName: string | null; } export class GuildForumChannel extends GuildChannel { public type: ChannelType.GuildForum; public threads: GuildForumThreadManager; public availableTags: GuildForumTag[]; - public defaultReactionEmoji: DefaultReaction | null; + public defaultReactionEmoji: DefaultReactionEmoji | null; public defaultThreadRateLimitPerUser: number | null; public setAvailableTags(tags: GuildForumTag[], reason?: string): Promise; - public setDefaultReaction(emojiId: DefaultReaction, reason?: string): Promise; + public setDefaultReaction(emojiId: DefaultReactionEmoji, reason?: string): Promise; public setDefaultThreadRateLimitPerUser(rateLimit: number, reason?: string): Promise; } From 634ba285717ce6790b39d860c45499d3c40fe3be Mon Sep 17 00:00:00 2001 From: suneettipirneni Date: Wed, 14 Sep 2022 16:48:47 -0400 Subject: [PATCH 20/60] chore: make requested changes --- packages/discord.js/src/structures/GuildForumChannel.js | 9 ++++----- packages/discord.js/src/structures/ThreadChannel.js | 9 +++++---- packages/discord.js/typings/index.d.ts | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/discord.js/src/structures/GuildForumChannel.js b/packages/discord.js/src/structures/GuildForumChannel.js index d969dc1981ea..1f96fe630eb1 100644 --- a/packages/discord.js/src/structures/GuildForumChannel.js +++ b/packages/discord.js/src/structures/GuildForumChannel.js @@ -52,7 +52,7 @@ class GuildForumChannel extends GuildChannel { if ('default_reaction_emoji' in data) { /** * The emoji to show in the add reaction button on a thread in a guild forum channel - * @type {DefaultReaction} + * @type {?DefaultReaction} */ this.defaultReactionEmoji = data.default_reaction_emoji ? transformGuildDefaultReaction(data.default_reaction_emoji) @@ -64,7 +64,7 @@ class GuildForumChannel extends GuildChannel { if ('default_thread_rate_limit_per_user' in data) { /** * The initial rate_limit_per_user to set on newly created threads in a channel. - * @type {number} + * @type {?number} */ this.defaultThreadRateLimitPerUser = data.default_thread_rate_limit_per_user; } else { @@ -78,9 +78,8 @@ class GuildForumChannel extends GuildChannel { * @param {string} [reason] Reason for changing the available tags * @returns {Promise} */ - async setAvailableTags(availableTags, reason) { - await this.edit({ availableTags, reason }); - return this; + setAvailableTags(availableTags, reason) { + return this.edit({ availableTags, reason }); } /** diff --git a/packages/discord.js/src/structures/ThreadChannel.js b/packages/discord.js/src/structures/ThreadChannel.js index 15bd64b66122..d6dfc1986205 100644 --- a/packages/discord.js/src/structures/ThreadChannel.js +++ b/packages/discord.js/src/structures/ThreadChannel.js @@ -198,9 +198,11 @@ class ThreadChannel extends BaseChannel { if ('applied_tags' in data) { /** * The tags applied to this thread - * @type {?GuildForumTag[]} + * @type {GuildForumTag[]} */ this.appliedTags = data.applied_tags.map(tag => transformGuildForumTag(tag)); + } else { + this.appliedTags ??= []; } } @@ -446,9 +448,8 @@ class ThreadChannel extends BaseChannel { * @param {string} [reason] Reason for changing the thread's applied tags * @returns {Promise} */ - async setAppliedTags(appliedTags, reason) { - await this.edit({ appliedTags, reason }); - return this; + setAppliedTags(appliedTags, reason) { + return this.edit({ appliedTags, reason }); } /** diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 162763d32d32..6dbf14f2ff42 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -125,7 +125,7 @@ import { AuditLogOptionsType, TextChannelType, } from 'discord-api-types/v10'; -import { ChildProcess, MessageOptions } from 'node:child_process'; +import { ChildProcess } from 'node:child_process'; import { EventEmitter } from 'node:events'; import { Stream } from 'node:stream'; import { MessagePort, Worker } from 'node:worker_threads'; From 03fd070d59060fe90c2e1d1ee7bdf9979f2b3b1a Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Thu, 15 Sep 2022 20:02:19 +0100 Subject: [PATCH 21/60] chore: Apply suggestions Co-authored-by: Jaworek Co-authored-by: Jonathan Rubenstein --- .../discord.js/src/managers/GuildForumThreadManager.js | 2 +- .../discord.js/src/managers/GuildTextThreadManager.js | 8 ++++---- .../discord.js/src/structures/BaseGuildTextChannel.js | 4 ++-- packages/discord.js/src/structures/GuildForumChannel.js | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/discord.js/src/managers/GuildForumThreadManager.js b/packages/discord.js/src/managers/GuildForumThreadManager.js index 4bcb5742ff8b..d6d989c2d459 100644 --- a/packages/discord.js/src/managers/GuildForumThreadManager.js +++ b/packages/discord.js/src/managers/GuildForumThreadManager.js @@ -18,7 +18,7 @@ class GuildForumThreadManager extends ThreadManager { */ /** - * Options for creating a thread. Only one of `startMessage` or `type` can be defined. + * Options for creating a thread. * @typedef {StartThreadOptions} GuildForumThreadCreateOptions * @property {GuildForumThreadCreateOptions|MessagePayload} message The message associated with the thread post * @property {GuildForumTag[]} [appliedTags] The tags to apply to the thread diff --git a/packages/discord.js/src/managers/GuildTextThreadManager.js b/packages/discord.js/src/managers/GuildTextThreadManager.js index 656dd4623197..8bda414783c7 100644 --- a/packages/discord.js/src/managers/GuildTextThreadManager.js +++ b/packages/discord.js/src/managers/GuildTextThreadManager.js @@ -13,8 +13,8 @@ class GuildTextThreadManager extends ThreadManager { /** * Options for creating a thread. Only one of `startMessage` or `type` can be defined. * @typedef {StartThreadOptions} ThreadCreateOptions - * @property {MessageResolvable} [startMessage] The message to start a thread from. If this is defined then type - * of thread gets automatically defined and cannot be changed. The provided `type` field will be ignored + * @property {MessageResolvable} [startMessage] The message to start a thread from. + * If this is defined, then the `type` of thread gets inferred automatically and cannot be changed. * @property {ThreadChannelTypes|number} [type] The type of thread to create. * Defaults to {@link ChannelType.GuildPublicThread} if created in a {@link TextChannel} * When creating threads in a {@link NewsChannel} this is ignored and is always @@ -59,14 +59,14 @@ class GuildTextThreadManager extends ThreadManager { rateLimitPerUser, } = {}) { if (type && typeof type !== 'string' && typeof type !== 'number') { - throw new TypeError('INVALID_TYPE', 'type', 'ThreadChannelType or Number'); + throw new TypeError(ErrorCodes.InvalidType, 'type', 'ThreadChannelType or Number'); } let resolvedType = this.channel.type === ChannelType.GuildNews ? ChannelType.GuildNewsThread : ChannelType.GuildPublicThread; let startMessageId; if (startMessage) { startMessageId = this.channel.messages.resolveId(startMessage); - if (!startMessageId) throw new TypeError('INVALID_TYPE', 'startMessage', 'MessageResolvable'); + if (!startMessageId) throw new TypeError(ErrorCodes.InvalidType, 'startMessage', 'MessageResolvable'); } else if (this.channel.type !== ChannelType.GuildNews) { resolvedType = type ?? resolvedType; } diff --git a/packages/discord.js/src/structures/BaseGuildTextChannel.js b/packages/discord.js/src/structures/BaseGuildTextChannel.js index 1276799d4f40..71cb3c797aac 100644 --- a/packages/discord.js/src/structures/BaseGuildTextChannel.js +++ b/packages/discord.js/src/structures/BaseGuildTextChannel.js @@ -2,7 +2,7 @@ const GuildChannel = require('./GuildChannel'); const TextBasedChannel = require('./interfaces/TextBasedChannel'); -const ThreadManager = require('../managers/GuildTextThreadManager'); +const GuildTextThreadManager = require('../managers/GuildTextThreadManager'); const MessageManager = require('../managers/MessageManager'); /** @@ -24,7 +24,7 @@ class BaseGuildTextChannel extends GuildChannel { * A manager of the threads belonging to this channel * @type {GuildTextThreadManager} */ - this.threads = new ThreadManager(this); + this.threads = new GuildTextThreadManager(this); /** * If the guild considers this channel NSFW diff --git a/packages/discord.js/src/structures/GuildForumChannel.js b/packages/discord.js/src/structures/GuildForumChannel.js index 1f96fe630eb1..7b3d6246aba2 100644 --- a/packages/discord.js/src/structures/GuildForumChannel.js +++ b/packages/discord.js/src/structures/GuildForumChannel.js @@ -63,7 +63,7 @@ class GuildForumChannel extends GuildChannel { if ('default_thread_rate_limit_per_user' in data) { /** - * The initial rate_limit_per_user to set on newly created threads in a channel. + * The initial rate limit per user (slowmode) to set on newly created threads in a channel. * @type {?number} */ this.defaultThreadRateLimitPerUser = data.default_thread_rate_limit_per_user; From 46d3629ba5ce272edd446af9307a746c192b880d Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Thu, 15 Sep 2022 20:36:04 +0100 Subject: [PATCH 22/60] fix: import `ErrorCodes` --- packages/discord.js/src/managers/GuildTextThreadManager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/discord.js/src/managers/GuildTextThreadManager.js b/packages/discord.js/src/managers/GuildTextThreadManager.js index 8bda414783c7..032826083194 100644 --- a/packages/discord.js/src/managers/GuildTextThreadManager.js +++ b/packages/discord.js/src/managers/GuildTextThreadManager.js @@ -2,7 +2,7 @@ const { ChannelType, Routes } = require('discord-api-types/v10'); const ThreadManager = require('./ThreadManager'); -const { TypeError } = require('../errors'); +const { ErrorCodes, TypeError } = require('../errors'); const { resolveAutoArchiveMaxLimit } = require('../util/Util'); /** From 05f0094b5d1cd82fe44d046762f50d1868687773 Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Thu, 15 Sep 2022 20:41:51 +0100 Subject: [PATCH 23/60] fix: remove defunct code --- .../discord.js/src/managers/GuildForumThreadManager.js | 4 +--- packages/discord.js/src/managers/GuildTextThreadManager.js | 7 ++----- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/discord.js/src/managers/GuildForumThreadManager.js b/packages/discord.js/src/managers/GuildForumThreadManager.js index d6d989c2d459..425c931d70fe 100644 --- a/packages/discord.js/src/managers/GuildForumThreadManager.js +++ b/packages/discord.js/src/managers/GuildForumThreadManager.js @@ -4,7 +4,6 @@ const { Routes } = require('discord-api-types/v10'); const ThreadManager = require('./ThreadManager'); const { TypeError, ErrorCodes } = require('../errors'); const MessagePayload = require('../structures/MessagePayload'); -const { resolveAutoArchiveMaxLimit } = require('../util/Util'); /** * Manages API methods for threads in forum channels and stores their cache. @@ -33,7 +32,7 @@ class GuildForumThreadManager extends ThreadManager { * forum.threads * .create({ * name: 'Food Talk', - * autoArchiveDuration: 60, + * autoArchiveDuration: ThreadAutoArchiveDuration.OneHour, * message: { * content: 'Discuss your favorite food!', * }, @@ -58,7 +57,6 @@ class GuildForumThreadManager extends ThreadManager { message instanceof MessagePayload ? message.resolveBody() : MessagePayload.create(this, message).resolveBody(); const { body, files } = await messagePayload.resolveFiles(); - if (autoArchiveDuration === 'MAX') autoArchiveDuration = resolveAutoArchiveMaxLimit(this.channel.guild); const data = await this.client.rest.post(Routes.threads(this.channel.id), { body: { diff --git a/packages/discord.js/src/managers/GuildTextThreadManager.js b/packages/discord.js/src/managers/GuildTextThreadManager.js index 032826083194..83f8fad66d8b 100644 --- a/packages/discord.js/src/managers/GuildTextThreadManager.js +++ b/packages/discord.js/src/managers/GuildTextThreadManager.js @@ -3,7 +3,6 @@ const { ChannelType, Routes } = require('discord-api-types/v10'); const ThreadManager = require('./ThreadManager'); const { ErrorCodes, TypeError } = require('../errors'); -const { resolveAutoArchiveMaxLimit } = require('../util/Util'); /** * Manages API methods for {@link ThreadChannel} objects and stores their cache. @@ -32,7 +31,7 @@ class GuildTextThreadManager extends ThreadManager { * channel.threads * .create({ * name: 'food-talk', - * autoArchiveDuration: 60, + * autoArchiveDuration: ThreadAutoArchiveDuration.OneHour, * reason: 'Needed a separate thread for food', * }) * .then(threadChannel => console.log(threadChannel)) @@ -42,7 +41,7 @@ class GuildTextThreadManager extends ThreadManager { * channel.threads * .create({ * name: 'mod-talk', - * autoArchiveDuration: 60, + * autoArchiveDuration: ThreadAutoArchiveDuration.OneHour, * type: ChannelType.GuildPrivateThread, * reason: 'Needed a separate thread for moderation', * }) @@ -71,8 +70,6 @@ class GuildTextThreadManager extends ThreadManager { resolvedType = type ?? resolvedType; } - if (autoArchiveDuration === 'MAX') autoArchiveDuration = resolveAutoArchiveMaxLimit(this.channel.guild); - const data = await this.client.rest.post(Routes.threads(this.channel.id, startMessageId), { body: { name, From 8020ee87e7912b91c3287e773984fc41dcd6657a Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Thu, 15 Sep 2022 21:00:50 +0100 Subject: [PATCH 24/60] refactor: be consistent with channel class names --- packages/discord.js/src/index.js | 2 +- packages/discord.js/src/managers/ThreadManager.js | 2 +- packages/discord.js/src/structures/GuildChannel.js | 1 + .../discord.js/src/structures/GuildForumChannel.js | 10 +++++----- packages/discord.js/src/util/Channels.js | 2 +- packages/discord.js/typings/index.d.ts | 8 ++++---- packages/discord.js/typings/index.test-d.ts | 4 ++-- 7 files changed, 15 insertions(+), 14 deletions(-) diff --git a/packages/discord.js/src/index.js b/packages/discord.js/src/index.js index 69d5b98ba222..8090895b045d 100644 --- a/packages/discord.js/src/index.js +++ b/packages/discord.js/src/index.js @@ -111,13 +111,13 @@ exports.DMChannel = require('./structures/DMChannel'); exports.Embed = require('./structures/Embed'); exports.EmbedBuilder = require('./structures/EmbedBuilder'); exports.Emoji = require('./structures/Emoji').Emoji; +exports.ForumChannel = require('./structures/ForumChannel'); exports.Guild = require('./structures/Guild').Guild; exports.GuildAuditLogs = require('./structures/GuildAuditLogs'); exports.GuildAuditLogsEntry = require('./structures/GuildAuditLogsEntry'); exports.GuildBan = require('./structures/GuildBan'); exports.GuildChannel = require('./structures/GuildChannel'); exports.GuildEmoji = require('./structures/GuildEmoji'); -exports.GuildForumChannel = require('./structures/GuildForumChannel'); exports.GuildMember = require('./structures/GuildMember').GuildMember; exports.GuildPreview = require('./structures/GuildPreview'); exports.GuildPreviewEmoji = require('./structures/GuildPreviewEmoji'); diff --git a/packages/discord.js/src/managers/ThreadManager.js b/packages/discord.js/src/managers/ThreadManager.js index 1adc914ec091..fc32c668c7c1 100644 --- a/packages/discord.js/src/managers/ThreadManager.js +++ b/packages/discord.js/src/managers/ThreadManager.js @@ -17,7 +17,7 @@ class ThreadManager extends CachedManager { /** * The channel this Manager belongs to - * @type {NewsChannel|TextChannel|GuildForumChannel} + * @type {NewsChannel|TextChannel|ForumChannel} */ this.channel = channel; } diff --git a/packages/discord.js/src/structures/GuildChannel.js b/packages/discord.js/src/structures/GuildChannel.js index c8e42c66e272..8f05faa8262b 100644 --- a/packages/discord.js/src/structures/GuildChannel.js +++ b/packages/discord.js/src/structures/GuildChannel.js @@ -14,6 +14,7 @@ const PermissionsBitField = require('../util/PermissionsBitField'); * - {@link CategoryChannel} * - {@link NewsChannel} * - {@link StageChannel} + * - {@link ForumChannel} * @extends {BaseChannel} * @abstract */ diff --git a/packages/discord.js/src/structures/GuildForumChannel.js b/packages/discord.js/src/structures/GuildForumChannel.js index 7b3d6246aba2..6dee83edae43 100644 --- a/packages/discord.js/src/structures/GuildForumChannel.js +++ b/packages/discord.js/src/structures/GuildForumChannel.js @@ -24,7 +24,7 @@ const { transformGuildForumTag, transformGuildDefaultReaction } = require('../ut * Represents a channel that only contains threads * @extends {GuildChannel} */ -class GuildForumChannel extends GuildChannel { +class ForumChannel extends GuildChannel { constructor(guild, data, client) { super(guild, data, client, false); @@ -76,7 +76,7 @@ class GuildForumChannel extends GuildChannel { * Sets the available tags for this forum channel * @param {GuildForumTag[]} availableTags The tags to set as available in this channel * @param {string} [reason] Reason for changing the available tags - * @returns {Promise} + * @returns {Promise} */ setAvailableTags(availableTags, reason) { return this.edit({ availableTags, reason }); @@ -86,7 +86,7 @@ class GuildForumChannel extends GuildChannel { * Sets the default reaction emoji for this channel * @param {DefaultReaction} defaultReactionEmoji The emoji to set as the default reaction emoji * @param {string} [reason] Reason for changing the default reaction emoji - * @returns {Promise} + * @returns {Promise} */ async setDefaultReactionEmoji(defaultReactionEmoji, reason) { await this.edit({ defaultReactionEmoji, reason }); @@ -97,7 +97,7 @@ class GuildForumChannel extends GuildChannel { * Sets the default rate limit per user (slowmode) for new threads in this channel * @param {number} defaultThreadRateLimitPerUser The rate limit to set on newly created threads in this channel * @param {string} [reason] Reason for changing the default rate limit - * @returns {Promise} + * @returns {Promise} */ async setDefaultThreadRateLimitPerUser(defaultThreadRateLimitPerUser, reason) { await this.edit({ defaultThreadRateLimitPerUser, reason }); @@ -105,4 +105,4 @@ class GuildForumChannel extends GuildChannel { } } -module.exports = GuildForumChannel; +module.exports = ForumChannel; diff --git a/packages/discord.js/src/util/Channels.js b/packages/discord.js/src/util/Channels.js index 9d206da03e0b..e9c4ce576ecb 100644 --- a/packages/discord.js/src/util/Channels.js +++ b/packages/discord.js/src/util/Channels.js @@ -12,7 +12,7 @@ const getThreadChannel = lazy(() => require('../structures/ThreadChannel')); const getVoiceChannel = lazy(() => require('../structures/VoiceChannel')); const getDirectoryChannel = lazy(() => require('../structures/DirectoryChannel')); const getPartialGroupDMChannel = lazy(() => require('../structures/PartialGroupDMChannel')); -const getForumChannel = lazy(() => require('../structures/GuildForumChannel')); +const getForumChannel = lazy(() => require('../structures/ForumChannel')); /** * Creates a discord.js channel from data received from the API. diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 6dbf14f2ff42..c9b084aec9f5 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -2053,7 +2053,7 @@ export interface DefaultReactionEmoji { emojiName: string | null; } -export class GuildForumChannel extends GuildChannel { +export class ForumChannel extends GuildChannel { public type: ChannelType.GuildForum; public threads: GuildForumThreadManager; public availableTags: GuildForumTag[]; @@ -5579,11 +5579,11 @@ export type Channel = | TextChannel | AnyThreadChannel | VoiceChannel - | GuildForumChannel; + | ForumChannel; export type TextBasedChannel = Exclude< Extract, - PartialGroupDMChannel | GuildForumChannel + PartialGroupDMChannel | ForumChannel >; export type TextBasedChannelTypes = TextBasedChannel['type']; @@ -5596,7 +5596,7 @@ export type CategoryChildChannel = Exclude; -export type GuildTextBasedChannel = Exclude, GuildForumChannel>; +export type GuildTextBasedChannel = Exclude, ForumChannel>; export type TextChannelResolvable = Snowflake | TextChannel; diff --git a/packages/discord.js/typings/index.test-d.ts b/packages/discord.js/typings/index.test-d.ts index 7a3110803923..efd100f7b857 100644 --- a/packages/discord.js/typings/index.test-d.ts +++ b/packages/discord.js/typings/index.test-d.ts @@ -137,7 +137,7 @@ import { GuildAuditLogsActionType, GuildAuditLogsTargetType, ModalSubmitInteraction, - GuildForumChannel, + ForumChannel, } from '.'; import { expectAssignable, expectNotAssignable, expectNotType, expectType } from 'tsd'; import type { ContextMenuCommandBuilder, SlashCommandBuilder } from '@discordjs/builders'; @@ -1847,7 +1847,7 @@ expectType< >(TextBasedChannelTypes); expectType(VoiceBasedChannel); expectType(GuildBasedChannel); -expectType( +expectType( NonThreadGuildBasedChannel, ); expectType(GuildTextBasedChannel); From 62a5d96ba01b881ca11b6c057914f5dc8684a20e Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Thu, 15 Sep 2022 21:24:20 +0100 Subject: [PATCH 25/60] feat(GuildChannel): add flags --- packages/discord.js/src/index.js | 1 + .../discord.js/src/structures/GuildChannel.js | 11 +++++++ .../src/util/GuildChannelFlagsBitField.js | 32 +++++++++++++++++++ packages/discord.js/typings/index.d.ts | 9 ++++++ 4 files changed, 53 insertions(+) create mode 100644 packages/discord.js/src/util/GuildChannelFlagsBitField.js diff --git a/packages/discord.js/src/index.js b/packages/discord.js/src/index.js index 8090895b045d..230795e312da 100644 --- a/packages/discord.js/src/index.js +++ b/packages/discord.js/src/index.js @@ -28,6 +28,7 @@ exports.Colors = require('./util/Colors'); exports.DataResolver = require('./util/DataResolver'); exports.Events = require('./util/Events'); exports.Formatters = require('./util/Formatters'); +exports.GuildChannelFlagsBitField = require('./util/GuildChannelFlagsBitField'); exports.IntentsBitField = require('./util/IntentsBitField'); exports.LimitedCollection = require('./util/LimitedCollection'); exports.MessageFlagsBitField = require('./util/MessageFlagsBitField'); diff --git a/packages/discord.js/src/structures/GuildChannel.js b/packages/discord.js/src/structures/GuildChannel.js index 8f05faa8262b..c0fb36bc6e45 100644 --- a/packages/discord.js/src/structures/GuildChannel.js +++ b/packages/discord.js/src/structures/GuildChannel.js @@ -5,6 +5,7 @@ const { BaseChannel } = require('./BaseChannel'); const { Error, ErrorCodes } = require('../errors'); const PermissionOverwriteManager = require('../managers/PermissionOverwriteManager'); const { VoiceBasedChannelTypes } = require('../util/Constants'); +const GuildChannelFlagsBitField = require('../util/GuildChannelFlagsBitField'); const PermissionsBitField = require('../util/PermissionsBitField'); /** @@ -47,6 +48,16 @@ class GuildChannel extends BaseChannel { _patch(data) { super._patch(data); + if ('flags' in data) { + /** + * The flags that are applied to the channel. + * @type {Readonly} + */ + this.flags = new GuildChannelFlagsBitField(data.flags).freeze(); + } else { + this.flags = new GuildChannelFlagsBitField(this.flags).freeze(); + } + if ('name' in data) { /** * The name of the guild channel diff --git a/packages/discord.js/src/util/GuildChannelFlagsBitField.js b/packages/discord.js/src/util/GuildChannelFlagsBitField.js new file mode 100644 index 000000000000..246faf8e9e5a --- /dev/null +++ b/packages/discord.js/src/util/GuildChannelFlagsBitField.js @@ -0,0 +1,32 @@ +'use strict'; + +const { ChannelFlags } = require('discord-api-types/v10'); +const BitField = require('./BitField'); + +/** + * Data structure that makes it easy to interact with a {@link GuildChannel#flags} bitfield. + * @extends {BitField} + */ +class GuildChannelFlagsBitField extends BitField { + /** + * Numeric guild channel flags. + * @type {ChannelFlags} + * @memberof GuildChannelFlagsBitField + */ + static Flags = ChannelFlags; +} + +/** + * @name GuildChannelFlagsBitField + * @kind constructor + * @memberof GuildChannelFlagsBitField + * @param {BitFieldResolvable} [bits=0] Bit(s) to read from + */ + +/** + * Bitfield of the packed bits + * @type {number} + * @name GuildChannelFlagsBitField#bitfield + */ + +module.exports = GuildChannelFlagsBitField; diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index c9b084aec9f5..a47445770d50 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -124,6 +124,7 @@ import { APIEmbedProvider, AuditLogOptionsType, TextChannelType, + ChannelFlags, } from 'discord-api-types/v10'; import { ChildProcess } from 'node:child_process'; import { EventEmitter } from 'node:events'; @@ -1224,6 +1225,7 @@ export abstract class GuildChannel extends BaseChannel { public get createdAt(): Date; public get createdTimestamp(): number; public get deletable(): boolean; + public flags: Readonly; public guild: Guild; public guildId: Snowflake; public get manageable(): boolean; @@ -1254,6 +1256,13 @@ export abstract class GuildChannel extends BaseChannel { public toString(): ChannelMention; } +export type GuildChannelFlagsString = keyof typeof ChannelFlags; + +export class GuildChannelFlagsBitField extends BitField { + public static Flags: typeof ChannelFlags; + public static resolve(bit?: BitFieldResolvable): number; +} + export class GuildEmoji extends BaseGuildEmoji { private constructor(client: Client, data: RawGuildEmojiData, guild: Guild); private _roles: Snowflake[]; From bbd058181c05bee4f8418e9670392f8676950266 Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Thu, 15 Sep 2022 21:28:30 +0100 Subject: [PATCH 26/60] fix: rename file --- .../src/structures/{GuildForumChannel.js => ForumChannel.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/discord.js/src/structures/{GuildForumChannel.js => ForumChannel.js} (100%) diff --git a/packages/discord.js/src/structures/GuildForumChannel.js b/packages/discord.js/src/structures/ForumChannel.js similarity index 100% rename from packages/discord.js/src/structures/GuildForumChannel.js rename to packages/discord.js/src/structures/ForumChannel.js From 16033b42b82ef032f9f38a58474189a0cf181bc3 Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Thu, 15 Sep 2022 21:45:38 +0100 Subject: [PATCH 27/60] refactor: channel flags are everywhere! --- packages/discord.js/src/index.js | 2 +- packages/discord.js/src/structures/BaseChannel.js | 11 +++++++++++ packages/discord.js/src/structures/GuildChannel.js | 11 ----------- .../src/structures/PartialGroupDMChannel.js | 3 +++ ...nelFlagsBitField.js => ChannelFlagsBitField.js} | 14 +++++++------- packages/discord.js/typings/index.d.ts | 1 + 6 files changed, 23 insertions(+), 19 deletions(-) rename packages/discord.js/src/util/{GuildChannelFlagsBitField.js => ChannelFlagsBitField.js} (53%) diff --git a/packages/discord.js/src/index.js b/packages/discord.js/src/index.js index 230795e312da..a015ba4954c0 100644 --- a/packages/discord.js/src/index.js +++ b/packages/discord.js/src/index.js @@ -22,13 +22,13 @@ exports.ActivityFlagsBitField = require('./util/ActivityFlagsBitField'); exports.ApplicationFlagsBitField = require('./util/ApplicationFlagsBitField'); exports.BaseManager = require('./managers/BaseManager'); exports.BitField = require('./util/BitField'); +exports.ChannelFlagsBitField = require('./util/ChannelFlagsBitField'); exports.Collection = require('@discordjs/collection').Collection; exports.Constants = require('./util/Constants'); exports.Colors = require('./util/Colors'); exports.DataResolver = require('./util/DataResolver'); exports.Events = require('./util/Events'); exports.Formatters = require('./util/Formatters'); -exports.GuildChannelFlagsBitField = require('./util/GuildChannelFlagsBitField'); exports.IntentsBitField = require('./util/IntentsBitField'); exports.LimitedCollection = require('./util/LimitedCollection'); exports.MessageFlagsBitField = require('./util/MessageFlagsBitField'); diff --git a/packages/discord.js/src/structures/BaseChannel.js b/packages/discord.js/src/structures/BaseChannel.js index 49d611436e19..d7fd1f400d4d 100644 --- a/packages/discord.js/src/structures/BaseChannel.js +++ b/packages/discord.js/src/structures/BaseChannel.js @@ -4,6 +4,7 @@ const { channelLink } = require('@discordjs/builders'); const { DiscordSnowflake } = require('@sapphire/snowflake'); const { ChannelType, Routes } = require('discord-api-types/v10'); const Base = require('./Base'); +const { ChannelFlagsBitField } = require('../util/ChannelFlagsBitField'); const { ThreadChannelTypes } = require('../util/Constants'); /** @@ -25,6 +26,16 @@ class BaseChannel extends Base { } _patch(data) { + if ('flags' in data) { + /** + * The flags that are applied to the channel. + * @type {Readonly} + */ + this.flags = new ChannelFlagsBitField(data.flags).freeze(); + } else { + this.flags = new ChannelFlagsBitField(this.flags).freeze(); + } + /** * The channel's id * @type {Snowflake} diff --git a/packages/discord.js/src/structures/GuildChannel.js b/packages/discord.js/src/structures/GuildChannel.js index c0fb36bc6e45..8f05faa8262b 100644 --- a/packages/discord.js/src/structures/GuildChannel.js +++ b/packages/discord.js/src/structures/GuildChannel.js @@ -5,7 +5,6 @@ const { BaseChannel } = require('./BaseChannel'); const { Error, ErrorCodes } = require('../errors'); const PermissionOverwriteManager = require('../managers/PermissionOverwriteManager'); const { VoiceBasedChannelTypes } = require('../util/Constants'); -const GuildChannelFlagsBitField = require('../util/GuildChannelFlagsBitField'); const PermissionsBitField = require('../util/PermissionsBitField'); /** @@ -48,16 +47,6 @@ class GuildChannel extends BaseChannel { _patch(data) { super._patch(data); - if ('flags' in data) { - /** - * The flags that are applied to the channel. - * @type {Readonly} - */ - this.flags = new GuildChannelFlagsBitField(data.flags).freeze(); - } else { - this.flags = new GuildChannelFlagsBitField(this.flags).freeze(); - } - if ('name' in data) { /** * The name of the guild channel diff --git a/packages/discord.js/src/structures/PartialGroupDMChannel.js b/packages/discord.js/src/structures/PartialGroupDMChannel.js index 92d7d1ea3f88..8f57ed2d6759 100644 --- a/packages/discord.js/src/structures/PartialGroupDMChannel.js +++ b/packages/discord.js/src/structures/PartialGroupDMChannel.js @@ -11,6 +11,9 @@ class PartialGroupDMChannel extends BaseChannel { constructor(client, data) { super(client, data); + // No flags are present when fetching partial group DM channels. + delete this.flags; + /** * The name of this Group DM Channel * @type {?string} diff --git a/packages/discord.js/src/util/GuildChannelFlagsBitField.js b/packages/discord.js/src/util/ChannelFlagsBitField.js similarity index 53% rename from packages/discord.js/src/util/GuildChannelFlagsBitField.js rename to packages/discord.js/src/util/ChannelFlagsBitField.js index 246faf8e9e5a..c6b6d07d3f7e 100644 --- a/packages/discord.js/src/util/GuildChannelFlagsBitField.js +++ b/packages/discord.js/src/util/ChannelFlagsBitField.js @@ -4,29 +4,29 @@ const { ChannelFlags } = require('discord-api-types/v10'); const BitField = require('./BitField'); /** - * Data structure that makes it easy to interact with a {@link GuildChannel#flags} bitfield. + * Data structure that makes it easy to interact with a {@link BaseChannel#flags} bitfield. * @extends {BitField} */ -class GuildChannelFlagsBitField extends BitField { +class ChannelFlagsBitField extends BitField { /** * Numeric guild channel flags. * @type {ChannelFlags} - * @memberof GuildChannelFlagsBitField + * @memberof ChannelFlagsBitField */ static Flags = ChannelFlags; } /** - * @name GuildChannelFlagsBitField + * @name ChannelFlagsBitField * @kind constructor - * @memberof GuildChannelFlagsBitField + * @memberof ChannelFlagsBitField * @param {BitFieldResolvable} [bits=0] Bit(s) to read from */ /** * Bitfield of the packed bits * @type {number} - * @name GuildChannelFlagsBitField#bitfield + * @name ChannelFlagsBitField#bitfield */ -module.exports = GuildChannelFlagsBitField; +module.exports = ChannelFlagsBitField; diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index a47445770d50..15740c1697b1 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -2042,6 +2042,7 @@ export class OAuth2Guild extends BaseGuild { export class PartialGroupDMChannel extends BaseChannel { private constructor(client: Client, data: RawPartialGroupDMChannelData); public type: ChannelType.GroupDM; + public flags: never; public name: string | null; public icon: string | null; public recipients: PartialRecipient[]; From f34566f51fdecb6d964a9ba6522ad7d4236d8ab5 Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Thu, 15 Sep 2022 21:59:40 +0100 Subject: [PATCH 28/60] fix: import flags correctly --- packages/discord.js/src/structures/BaseChannel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/discord.js/src/structures/BaseChannel.js b/packages/discord.js/src/structures/BaseChannel.js index d7fd1f400d4d..6e820feb126b 100644 --- a/packages/discord.js/src/structures/BaseChannel.js +++ b/packages/discord.js/src/structures/BaseChannel.js @@ -4,7 +4,7 @@ const { channelLink } = require('@discordjs/builders'); const { DiscordSnowflake } = require('@sapphire/snowflake'); const { ChannelType, Routes } = require('discord-api-types/v10'); const Base = require('./Base'); -const { ChannelFlagsBitField } = require('../util/ChannelFlagsBitField'); +const ChannelFlagsBitField = require('../util/ChannelFlagsBitField'); const { ThreadChannelTypes } = require('../util/Constants'); /** From c8494d07d488d37dcf78aae9c735b2501888c029 Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Thu, 15 Sep 2022 22:07:09 +0100 Subject: [PATCH 29/60] chore(ThreadChannel): update message count string --- packages/discord.js/src/structures/ThreadChannel.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/discord.js/src/structures/ThreadChannel.js b/packages/discord.js/src/structures/ThreadChannel.js index d6dfc1986205..7d5b829a4c35 100644 --- a/packages/discord.js/src/structures/ThreadChannel.js +++ b/packages/discord.js/src/structures/ThreadChannel.js @@ -160,8 +160,8 @@ class ThreadChannel extends BaseChannel { if ('message_count' in data) { /** * The approximate count of messages in this thread - * This stops counting at 50. If you need an approximate value higher than that, use - * `ThreadChannel#messages.cache.size` + * Threads created before July 1, 2022 may have an inaccurate count. + * If you need an approximate value higher than that, use `ThreadChannel#messages.cache.size` * @type {?number} */ this.messageCount = data.message_count; From abe4d1e65eb1bcb03b190a10192959f9c949df14 Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Thu, 15 Sep 2022 22:12:50 +0100 Subject: [PATCH 30/60] docs(Channels): correct `@param` type --- packages/discord.js/src/util/APITypes.js | 5 +++++ packages/discord.js/src/util/Channels.js | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/discord.js/src/util/APITypes.js b/packages/discord.js/src/util/APITypes.js index 1edae74bc81f..5657f0342a9b 100644 --- a/packages/discord.js/src/util/APITypes.js +++ b/packages/discord.js/src/util/APITypes.js @@ -63,6 +63,11 @@ * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIGuild} */ +/** + * @external APIGuildForumTag + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIGuildForumTag} + */ + /** * @external APIInteraction * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIInteraction} diff --git a/packages/discord.js/src/util/Channels.js b/packages/discord.js/src/util/Channels.js index e9c4ce576ecb..bcd1ef6a487e 100644 --- a/packages/discord.js/src/util/Channels.js +++ b/packages/discord.js/src/util/Channels.js @@ -78,7 +78,7 @@ function createChannel(client, data, guild, { allowUnknownGuild, fromInteraction /** * Transforms an API guild forum tag to camel-cased guild forum tag. - * @param {GuildForumTag} tag The tag to transform + * @param {APIGuildForumTag} tag The tag to transform * @returns {GuildForumTag} */ function transformGuildForumTag(tag) { From a475de3d9713d12c2cd096d40f108a6823cfbb85 Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Thu, 15 Sep 2022 22:30:30 +0100 Subject: [PATCH 31/60] docs(Channels): ignore transformGuildDefaultReaction --- packages/discord.js/src/util/Channels.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/discord.js/src/util/Channels.js b/packages/discord.js/src/util/Channels.js index bcd1ef6a487e..858f87659a82 100644 --- a/packages/discord.js/src/util/Channels.js +++ b/packages/discord.js/src/util/Channels.js @@ -96,6 +96,7 @@ function transformGuildForumTag(tag) { * camel-cased guild forum default reaction object. * @param {APIDefaultReaction} defaultReaction The default reaction to transform * @returns {DefaultReaction} + * @ignore */ function transformGuildDefaultReaction(defaultReaction) { return { From a3b5deb7113f3529de689a70be4bde3c47e91a36 Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Thu, 15 Sep 2022 22:38:15 +0100 Subject: [PATCH 32/60] refactor: emoji object in tags --- .../src/managers/GuildChannelManager.js | 4 +++- .../src/managers/GuildForumThreadManager.js | 3 ++- .../discord.js/src/structures/ForumChannel.js | 15 ++++++++---- .../src/structures/ThreadChannel.js | 4 ++-- packages/discord.js/src/util/Channels.js | 24 +++++++++++++++++-- packages/discord.js/typings/index.d.ts | 9 +++++-- 6 files changed, 46 insertions(+), 13 deletions(-) diff --git a/packages/discord.js/src/managers/GuildChannelManager.js b/packages/discord.js/src/managers/GuildChannelManager.js index 45e60e5df224..df675b8c3190 100644 --- a/packages/discord.js/src/managers/GuildChannelManager.js +++ b/packages/discord.js/src/managers/GuildChannelManager.js @@ -10,6 +10,7 @@ const GuildChannel = require('../structures/GuildChannel'); const PermissionOverwrites = require('../structures/PermissionOverwrites'); const ThreadChannel = require('../structures/ThreadChannel'); const Webhook = require('../structures/Webhook'); +const { transformGuildForumTag } = require('../util/Channels'); const { ThreadChannelTypes } = require('../util/Constants'); const DataResolver = require('../util/DataResolver'); const { setPosition } = require('../util/Util'); @@ -218,6 +219,7 @@ class GuildChannelManager extends CachedManager { * The default auto archive duration for all new threads in this channel * @property {?string} [rtcRegion] The RTC region of the channel * @property {?VideoQualityMode} [videoQualityMode] The camera video quality mode of the channel + * @property {GuildForumTag[]} [availableTags] The tags to set as available in a forum channel * @property {string} [reason] Reason for editing this channel */ @@ -274,7 +276,7 @@ class GuildChannelManager extends CachedManager { rate_limit_per_user: data.rateLimitPerUser, default_auto_archive_duration: data.defaultAutoArchiveDuration, permission_overwrites, - available_tags: data.availableTags, + available_tags: data.availableTags ? transformGuildForumTag(data.availableTags) : undefined, default_reaction_emoji: data.defaultReactionEmoji, default_thread_rate_limit_per_user: data.defaultThreadRateLimitPerUser, }, diff --git a/packages/discord.js/src/managers/GuildForumThreadManager.js b/packages/discord.js/src/managers/GuildForumThreadManager.js index 425c931d70fe..a0f2b41274ba 100644 --- a/packages/discord.js/src/managers/GuildForumThreadManager.js +++ b/packages/discord.js/src/managers/GuildForumThreadManager.js @@ -4,6 +4,7 @@ const { Routes } = require('discord-api-types/v10'); const ThreadManager = require('./ThreadManager'); const { TypeError, ErrorCodes } = require('../errors'); const MessagePayload = require('../structures/MessagePayload'); +const { transformGuildForumTag } = require('../util/Channels'); /** * Manages API methods for threads in forum channels and stores their cache. @@ -63,7 +64,7 @@ class GuildForumThreadManager extends ThreadManager { name, auto_archive_duration: autoArchiveDuration, rate_limit_per_user: rateLimitPerUser, - applied_tags: appliedTags, + applied_tags: appliedTags ? transformGuildForumTag(appliedTags) : undefined, message: body, }, files, diff --git a/packages/discord.js/src/structures/ForumChannel.js b/packages/discord.js/src/structures/ForumChannel.js index 6dee83edae43..268a29808eda 100644 --- a/packages/discord.js/src/structures/ForumChannel.js +++ b/packages/discord.js/src/structures/ForumChannel.js @@ -2,16 +2,21 @@ const GuildChannel = require('./GuildChannel'); const GuildForumThreadManager = require('../managers/GuildForumThreadManager'); -const { transformGuildForumTag, transformGuildDefaultReaction } = require('../util/Channels'); +const { transformAPIGuildForumTag, transformGuildDefaultReaction } = require('../util/Channels'); + +/** + * @typedef {Object} GuildForumTagEmoji + * @property {?Snowflake} id The id of a guild's custom emoji + * @property {?string} name The unicode character of the emoji + */ /** * @typedef {Object} GuildForumTag * @property {Snowflake} id The id of the tag * @property {string} name The name of the tag * @property {boolean} moderated Whether this tag can only be added to or removed from threads - * by a member with the `ManageThreads` permission - * @property {?Snowflake} emojiId The id of a guild's custom emoji, or 0 if unset - * @property {?string} emojiName The unicode character of the emoji + * by a member with the `ManageThreads` permission + * @property {GuildForumTagEmoji} emoji The emoji of this tag */ /** @@ -44,7 +49,7 @@ class ForumChannel extends GuildChannel { * The set of tags that can be used in this channel. * @type {GuildForumTag[]} */ - this.availableTags = data.available_tags.map(tag => transformGuildForumTag(tag)); + this.availableTags = data.available_tags.map(tag => transformAPIGuildForumTag(tag)); } else { this.availableTags ??= []; } diff --git a/packages/discord.js/src/structures/ThreadChannel.js b/packages/discord.js/src/structures/ThreadChannel.js index 7d5b829a4c35..7cf6b03fb4c9 100644 --- a/packages/discord.js/src/structures/ThreadChannel.js +++ b/packages/discord.js/src/structures/ThreadChannel.js @@ -6,7 +6,7 @@ const TextBasedChannel = require('./interfaces/TextBasedChannel'); const { RangeError, ErrorCodes } = require('../errors'); const MessageManager = require('../managers/MessageManager'); const ThreadMemberManager = require('../managers/ThreadMemberManager'); -const { transformGuildForumTag } = require('../util/Channels'); +const { transformAPIGuildForumTag } = require('../util/Channels'); /** * Represents a thread channel on Discord. @@ -200,7 +200,7 @@ class ThreadChannel extends BaseChannel { * The tags applied to this thread * @type {GuildForumTag[]} */ - this.appliedTags = data.applied_tags.map(tag => transformGuildForumTag(tag)); + this.appliedTags = data.applied_tags.map(tag => transformAPIGuildForumTag(tag)); } else { this.appliedTags ??= []; } diff --git a/packages/discord.js/src/util/Channels.js b/packages/discord.js/src/util/Channels.js index 858f87659a82..f89b0c6b4c84 100644 --- a/packages/discord.js/src/util/Channels.js +++ b/packages/discord.js/src/util/Channels.js @@ -80,14 +80,33 @@ function createChannel(client, data, guild, { allowUnknownGuild, fromInteraction * Transforms an API guild forum tag to camel-cased guild forum tag. * @param {APIGuildForumTag} tag The tag to transform * @returns {GuildForumTag} + * @ignore + */ +function transformAPIGuildForumTag(tag) { + return { + id: tag.id, + name: tag.name, + moderated: tag.moderated, + emoji: { + id: tag.emoji_id, + name: tag.emoji_name, + }, + }; +} + +/** + * Transforms a camel-cased guild forum tag to an API guild forum tag. + * @param {GuildForumTag} tag The tag to transform + * @returns {APIGuildForumTag} + * @ignore */ function transformGuildForumTag(tag) { return { id: tag.id, name: tag.name, moderated: tag.moderated, - emojiId: tag.emoji_id, - emojiName: tag.emoji_name, + emoji_id: tag.emoji.id, + emoji_name: tag.emoji.name, }; } @@ -107,6 +126,7 @@ function transformGuildDefaultReaction(defaultReaction) { module.exports = { transformGuildDefaultReaction, + transformAPIGuildForumTag, transformGuildForumTag, createChannel, }; diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 15740c1697b1..c1c5eb1fe687 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -2050,12 +2050,16 @@ export class PartialGroupDMChannel extends BaseChannel { public toString(): ChannelMention; } +export interface GuildForumTagEmoji { + id: Snowflake | null; + name: string | null; +} + export interface GuildForumTag { id: Snowflake; name: string; moderated: boolean; - emojiId: Snowflake | null; - emojiName: string | null; + emoji: GuildForumTagEmoji } export interface DefaultReactionEmoji { @@ -4882,6 +4886,7 @@ export interface GuildChannelEditOptions { defaultAutoArchiveDuration?: ThreadAutoArchiveDuration; rtcRegion?: string | null; videoQualityMode?: VideoQualityMode | null; + availableTags?: GuildForumTag[]; reason?: string; } From aeeba371d63a1f6345054f49973ed04e9beddefe Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Thu, 15 Sep 2022 22:39:38 +0100 Subject: [PATCH 33/60] chore: renaming consistency --- packages/discord.js/src/structures/ForumChannel.js | 4 ++-- packages/discord.js/src/util/Channels.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/discord.js/src/structures/ForumChannel.js b/packages/discord.js/src/structures/ForumChannel.js index 268a29808eda..36b37a8819a3 100644 --- a/packages/discord.js/src/structures/ForumChannel.js +++ b/packages/discord.js/src/structures/ForumChannel.js @@ -2,7 +2,7 @@ const GuildChannel = require('./GuildChannel'); const GuildForumThreadManager = require('../managers/GuildForumThreadManager'); -const { transformAPIGuildForumTag, transformGuildDefaultReaction } = require('../util/Channels'); +const { transformAPIGuildForumTag, transformAPIGuildDefaultReaction } = require('../util/Channels'); /** * @typedef {Object} GuildForumTagEmoji @@ -60,7 +60,7 @@ class ForumChannel extends GuildChannel { * @type {?DefaultReaction} */ this.defaultReactionEmoji = data.default_reaction_emoji - ? transformGuildDefaultReaction(data.default_reaction_emoji) + ? transformAPIGuildDefaultReaction(data.default_reaction_emoji) : null; } else { this.defaultReactionEmoji ??= null; diff --git a/packages/discord.js/src/util/Channels.js b/packages/discord.js/src/util/Channels.js index f89b0c6b4c84..bb765ca31d91 100644 --- a/packages/discord.js/src/util/Channels.js +++ b/packages/discord.js/src/util/Channels.js @@ -117,7 +117,7 @@ function transformGuildForumTag(tag) { * @returns {DefaultReaction} * @ignore */ -function transformGuildDefaultReaction(defaultReaction) { +function transformAPIGuildDefaultReaction(defaultReaction) { return { emojiId: defaultReaction.emoji_id, emojiName: defaultReaction.emoji_name, @@ -125,7 +125,7 @@ function transformGuildDefaultReaction(defaultReaction) { } module.exports = { - transformGuildDefaultReaction, + transformAPIGuildDefaultReaction, transformAPIGuildForumTag, transformGuildForumTag, createChannel, From ebbb6ebebd24954624b504cb8f1110fc84572880 Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Thu, 15 Sep 2022 22:48:20 +0100 Subject: [PATCH 34/60] fix: document default reaction emojis in patching --- packages/discord.js/src/managers/GuildChannelManager.js | 1 + packages/discord.js/src/structures/ForumChannel.js | 8 ++++---- packages/discord.js/src/util/Channels.js | 2 +- packages/discord.js/typings/index.d.ts | 1 + 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/discord.js/src/managers/GuildChannelManager.js b/packages/discord.js/src/managers/GuildChannelManager.js index df675b8c3190..0bdc6db00ebd 100644 --- a/packages/discord.js/src/managers/GuildChannelManager.js +++ b/packages/discord.js/src/managers/GuildChannelManager.js @@ -220,6 +220,7 @@ class GuildChannelManager extends CachedManager { * @property {?string} [rtcRegion] The RTC region of the channel * @property {?VideoQualityMode} [videoQualityMode] The camera video quality mode of the channel * @property {GuildForumTag[]} [availableTags] The tags to set as available in a forum channel + * @property {DefaultReactionEmoji} [defaultReactionEmoji] The emoji to set as the default reaction emoji * @property {string} [reason] Reason for editing this channel */ diff --git a/packages/discord.js/src/structures/ForumChannel.js b/packages/discord.js/src/structures/ForumChannel.js index 36b37a8819a3..7fcba172bf02 100644 --- a/packages/discord.js/src/structures/ForumChannel.js +++ b/packages/discord.js/src/structures/ForumChannel.js @@ -20,8 +20,8 @@ const { transformAPIGuildForumTag, transformAPIGuildDefaultReaction } = require( */ /** - * @typedef {Object} DefaultReaction - * @property {?Snowflake} emojiId The id of a guild's custom emoji, or 0 if unset + * @typedef {Object} DefaultReactionEmoji + * @property {?Snowflake} emojiId The id of a guild's custom emoji * @property {?string} emojiName The unicode character of the emoji */ @@ -57,7 +57,7 @@ class ForumChannel extends GuildChannel { if ('default_reaction_emoji' in data) { /** * The emoji to show in the add reaction button on a thread in a guild forum channel - * @type {?DefaultReaction} + * @type {?DefaultReactionEmoji} */ this.defaultReactionEmoji = data.default_reaction_emoji ? transformAPIGuildDefaultReaction(data.default_reaction_emoji) @@ -89,7 +89,7 @@ class ForumChannel extends GuildChannel { /** * Sets the default reaction emoji for this channel - * @param {DefaultReaction} defaultReactionEmoji The emoji to set as the default reaction emoji + * @param {DefaultReactionEmoji} defaultReactionEmoji The emoji to set as the default reaction emoji * @param {string} [reason] Reason for changing the default reaction emoji * @returns {Promise} */ diff --git a/packages/discord.js/src/util/Channels.js b/packages/discord.js/src/util/Channels.js index bb765ca31d91..e87222b23e78 100644 --- a/packages/discord.js/src/util/Channels.js +++ b/packages/discord.js/src/util/Channels.js @@ -114,7 +114,7 @@ function transformGuildForumTag(tag) { * Transforms an API guild forum default reaction object to a * camel-cased guild forum default reaction object. * @param {APIDefaultReaction} defaultReaction The default reaction to transform - * @returns {DefaultReaction} + * @returns {DefaultReactionEmoji} * @ignore */ function transformAPIGuildDefaultReaction(defaultReaction) { diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index c1c5eb1fe687..74b281b31a06 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -4887,6 +4887,7 @@ export interface GuildChannelEditOptions { rtcRegion?: string | null; videoQualityMode?: VideoQualityMode | null; availableTags?: GuildForumTag[]; + defaultReactionEmoji?: DefaultReactionEmoji; reason?: string; } From b8294b9f35c5c33df01dd00368cae53c9f65e61a Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Thu, 15 Sep 2022 22:52:16 +0100 Subject: [PATCH 35/60] fix(GuildChannelManager): document `defaultThreadRateLimitPerUser` --- packages/discord.js/src/managers/GuildChannelManager.js | 1 + packages/discord.js/typings/index.d.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/discord.js/src/managers/GuildChannelManager.js b/packages/discord.js/src/managers/GuildChannelManager.js index 0bdc6db00ebd..d3a9f350cc68 100644 --- a/packages/discord.js/src/managers/GuildChannelManager.js +++ b/packages/discord.js/src/managers/GuildChannelManager.js @@ -221,6 +221,7 @@ class GuildChannelManager extends CachedManager { * @property {?VideoQualityMode} [videoQualityMode] The camera video quality mode of the channel * @property {GuildForumTag[]} [availableTags] The tags to set as available in a forum channel * @property {DefaultReactionEmoji} [defaultReactionEmoji] The emoji to set as the default reaction emoji + * @property {number} [defaultThreadRateLimitPerUser] The rate limit per user (slowmode) to set on forum posts * @property {string} [reason] Reason for editing this channel */ diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 74b281b31a06..c7a3bdcea70b 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -4888,6 +4888,7 @@ export interface GuildChannelEditOptions { videoQualityMode?: VideoQualityMode | null; availableTags?: GuildForumTag[]; defaultReactionEmoji?: DefaultReactionEmoji; + defaultThreadRateLimitPerUser?: number; reason?: string; } From 84c9eab70aea07fe7b2357f60cd3fd3dcc55442c Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Thu, 15 Sep 2022 22:53:02 +0100 Subject: [PATCH 36/60] chore: semicolon --- packages/discord.js/typings/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index c7a3bdcea70b..7d6aca90ab0b 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -2059,7 +2059,7 @@ export interface GuildForumTag { id: Snowflake; name: string; moderated: boolean; - emoji: GuildForumTagEmoji + emoji: GuildForumTagEmoji; } export interface DefaultReactionEmoji { From 564ddba1e769894b4f5d22b77937d5d9762a4abe Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Fri, 16 Sep 2022 12:54:31 +0100 Subject: [PATCH 37/60] docs(ErrorCodes): document `GuildForumMessageRequired` --- packages/discord.js/src/errors/ErrorCodes.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/discord.js/src/errors/ErrorCodes.js b/packages/discord.js/src/errors/ErrorCodes.js index f627e5925aeb..f0566a0433a8 100644 --- a/packages/discord.js/src/errors/ErrorCodes.js +++ b/packages/discord.js/src/errors/ErrorCodes.js @@ -143,6 +143,8 @@ * @property {'NotImplemented'} NotImplemented + * @property {'GuildForumMessageRequired'} GuildForumMessageRequired + * @property {'SweepFilterReturn'} SweepFilterReturn */ From b9815d13d8fd4ff22c8949f27034ce4cd6d44617 Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Fri, 16 Sep 2022 15:18:31 +0100 Subject: [PATCH 38/60] refactor: transform default reactions --- .../src/managers/GuildChannelManager.js | 6 +++-- packages/discord.js/src/util/APITypes.js | 5 ++++ packages/discord.js/src/util/Channels.js | 27 ++++++++++++++----- packages/discord.js/typings/index.d.ts | 4 +-- 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/packages/discord.js/src/managers/GuildChannelManager.js b/packages/discord.js/src/managers/GuildChannelManager.js index d3a9f350cc68..b9db27595029 100644 --- a/packages/discord.js/src/managers/GuildChannelManager.js +++ b/packages/discord.js/src/managers/GuildChannelManager.js @@ -10,7 +10,7 @@ const GuildChannel = require('../structures/GuildChannel'); const PermissionOverwrites = require('../structures/PermissionOverwrites'); const ThreadChannel = require('../structures/ThreadChannel'); const Webhook = require('../structures/Webhook'); -const { transformGuildForumTag } = require('../util/Channels'); +const { transformGuildForumTag, transformGuildDefaultReaction } = require('../util/Channels'); const { ThreadChannelTypes } = require('../util/Constants'); const DataResolver = require('../util/DataResolver'); const { setPosition } = require('../util/Util'); @@ -279,7 +279,9 @@ class GuildChannelManager extends CachedManager { default_auto_archive_duration: data.defaultAutoArchiveDuration, permission_overwrites, available_tags: data.availableTags ? transformGuildForumTag(data.availableTags) : undefined, - default_reaction_emoji: data.defaultReactionEmoji, + default_reaction_emoji: data.defaultReactionEmoji + ? transformGuildDefaultReaction(data.defaultReactionEmoji) + : undefined, default_thread_rate_limit_per_user: data.defaultThreadRateLimitPerUser, }, reason: data.reason, diff --git a/packages/discord.js/src/util/APITypes.js b/packages/discord.js/src/util/APITypes.js index 5657f0342a9b..2b389e35210d 100644 --- a/packages/discord.js/src/util/APITypes.js +++ b/packages/discord.js/src/util/APITypes.js @@ -63,6 +63,11 @@ * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIGuild} */ +/** + * @external APIGuildForumDefaultReactionEmoji + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIGuildForumDefaultReactionEmoji} + */ + /** * @external APIGuildForumTag * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIGuildForumTag} diff --git a/packages/discord.js/src/util/Channels.js b/packages/discord.js/src/util/Channels.js index e87222b23e78..b2741b0288f8 100644 --- a/packages/discord.js/src/util/Channels.js +++ b/packages/discord.js/src/util/Channels.js @@ -113,20 +113,35 @@ function transformGuildForumTag(tag) { /** * Transforms an API guild forum default reaction object to a * camel-cased guild forum default reaction object. - * @param {APIDefaultReaction} defaultReaction The default reaction to transform + * @param {APIGuildForumDefaultReactionEmoji} defaultReaction The default reaction to transform * @returns {DefaultReactionEmoji} * @ignore */ function transformAPIGuildDefaultReaction(defaultReaction) { return { - emojiId: defaultReaction.emoji_id, - emojiName: defaultReaction.emoji_name, + id: defaultReaction.emoji_id, + name: defaultReaction.emoji_name, + }; +} + +/** + * Transforms a camel-cased guild forum default reaction object to an + * API guild forum default reaction object. + * @param {DefaultReactionEmoji} defaultReaction The default reaction to transform + * @returns {APIGuildForumDefaultReactionEmoji} + * @ignore + */ +function transformGuildDefaultReaction(defaultReaction) { + return { + emoji_id: defaultReaction.id, + emoji_name: defaultReaction.name, }; } module.exports = { - transformAPIGuildDefaultReaction, - transformAPIGuildForumTag, - transformGuildForumTag, createChannel, + transformGuildForumTag, + transformAPIGuildForumTag, + transformGuildDefaultReaction, + transformAPIGuildDefaultReaction, }; diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 7d6aca90ab0b..596ca9b83f08 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -2063,8 +2063,8 @@ export interface GuildForumTag { } export interface DefaultReactionEmoji { - emojiId: Snowflake | null; - emojiName: string | null; + id: Snowflake | null; + name: string | null; } export class ForumChannel extends GuildChannel { From 4c88604648f814a4f762472f131b866f61541d6d Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Fri, 16 Sep 2022 15:55:47 +0100 Subject: [PATCH 39/60] docs(APITypes): Add `ChannelFlags` --- packages/discord.js/src/util/APITypes.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/discord.js/src/util/APITypes.js b/packages/discord.js/src/util/APITypes.js index 2b389e35210d..dd70c87295ad 100644 --- a/packages/discord.js/src/util/APITypes.js +++ b/packages/discord.js/src/util/APITypes.js @@ -178,6 +178,11 @@ * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ButtonStyle} */ +/** + * @external ChannelFlags + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ChannelFlags} + */ + /** * @external ChannelType * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ChannelType} From a0d17b76a454864b881480b1c25d3e74dd0cb283 Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Fri, 16 Sep 2022 15:58:21 +0100 Subject: [PATCH 40/60] fix: convert tags properly --- packages/discord.js/src/managers/GuildChannelManager.js | 2 +- packages/discord.js/src/managers/GuildForumThreadManager.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/discord.js/src/managers/GuildChannelManager.js b/packages/discord.js/src/managers/GuildChannelManager.js index b9db27595029..84a52e94e6f7 100644 --- a/packages/discord.js/src/managers/GuildChannelManager.js +++ b/packages/discord.js/src/managers/GuildChannelManager.js @@ -278,7 +278,7 @@ class GuildChannelManager extends CachedManager { rate_limit_per_user: data.rateLimitPerUser, default_auto_archive_duration: data.defaultAutoArchiveDuration, permission_overwrites, - available_tags: data.availableTags ? transformGuildForumTag(data.availableTags) : undefined, + available_tags: data.availableTags?.map(availableTag => transformGuildForumTag(availableTag)), default_reaction_emoji: data.defaultReactionEmoji ? transformGuildDefaultReaction(data.defaultReactionEmoji) : undefined, diff --git a/packages/discord.js/src/managers/GuildForumThreadManager.js b/packages/discord.js/src/managers/GuildForumThreadManager.js index a0f2b41274ba..2ec218b4bb22 100644 --- a/packages/discord.js/src/managers/GuildForumThreadManager.js +++ b/packages/discord.js/src/managers/GuildForumThreadManager.js @@ -64,7 +64,7 @@ class GuildForumThreadManager extends ThreadManager { name, auto_archive_duration: autoArchiveDuration, rate_limit_per_user: rateLimitPerUser, - applied_tags: appliedTags ? transformGuildForumTag(appliedTags) : undefined, + applied_tags: appliedTags?.map(appliedTag => transformGuildForumTag(appliedTag)), message: body, }, files, From 6c2d2fca9770ad9b8eb772a734adc9cea2df01c5 Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Fri, 16 Sep 2022 16:19:19 +0100 Subject: [PATCH 41/60] fix: pass an array of snowflakes --- packages/discord.js/src/managers/GuildForumThreadManager.js | 5 ++--- packages/discord.js/typings/index.d.ts | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/discord.js/src/managers/GuildForumThreadManager.js b/packages/discord.js/src/managers/GuildForumThreadManager.js index 2ec218b4bb22..ee49223e184f 100644 --- a/packages/discord.js/src/managers/GuildForumThreadManager.js +++ b/packages/discord.js/src/managers/GuildForumThreadManager.js @@ -4,7 +4,6 @@ const { Routes } = require('discord-api-types/v10'); const ThreadManager = require('./ThreadManager'); const { TypeError, ErrorCodes } = require('../errors'); const MessagePayload = require('../structures/MessagePayload'); -const { transformGuildForumTag } = require('../util/Channels'); /** * Manages API methods for threads in forum channels and stores their cache. @@ -21,7 +20,7 @@ class GuildForumThreadManager extends ThreadManager { * Options for creating a thread. * @typedef {StartThreadOptions} GuildForumThreadCreateOptions * @property {GuildForumThreadCreateOptions|MessagePayload} message The message associated with the thread post - * @property {GuildForumTag[]} [appliedTags] The tags to apply to the thread + * @property {Snowflake[]} [appliedTags] The tags to apply to the thread */ /** @@ -64,7 +63,7 @@ class GuildForumThreadManager extends ThreadManager { name, auto_archive_duration: autoArchiveDuration, rate_limit_per_user: rateLimitPerUser, - applied_tags: appliedTags?.map(appliedTag => transformGuildForumTag(appliedTag)), + applied_tags: appliedTags, message: body, }, files, diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 596ca9b83f08..1d849b4ba282 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -5631,7 +5631,7 @@ export interface GuildTextThreadCreateOptions extends StartTh export interface GuildForumThreadCreateOptions extends StartThreadOptions { message: GuildForumThreadMessageCreateOptions | MessagePayload; - appliedTags?: GuildForumTag[]; + appliedTags?: Snowflake[]; } export interface ThreadEditData { From 6a2495597eca909dddc0888f0a7cd2b3563de61e Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Fri, 16 Sep 2022 16:29:36 +0100 Subject: [PATCH 42/60] refactor: handle flags better --- .../discord.js/src/structures/BaseChannel.js | 3 ++- packages/discord.js/typings/index.d.ts | 20 ++++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/packages/discord.js/src/structures/BaseChannel.js b/packages/discord.js/src/structures/BaseChannel.js index 6e820feb126b..b44a6e402ef1 100644 --- a/packages/discord.js/src/structures/BaseChannel.js +++ b/packages/discord.js/src/structures/BaseChannel.js @@ -29,7 +29,8 @@ class BaseChannel extends Base { if ('flags' in data) { /** * The flags that are applied to the channel. - * @type {Readonly} + * This is only `null` in a {@link PartialGroupDMChannel}. In all other cases, it is not `null`. + * @type {?Readonly} */ this.flags = new ChannelFlagsBitField(data.flags).freeze(); } else { diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 1d849b4ba282..b3aed37c2be8 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -727,11 +727,19 @@ export class CategoryChannel extends GuildChannel { export type CategoryChannelResolvable = Snowflake | CategoryChannel; +export type ChannelFlagsString = keyof typeof ChannelFlags; + +export class ChannelFlagsBitField extends BitField { + public static Flags: typeof ChannelFlags; + public static resolve(bit?: BitFieldResolvable): number; +} + export abstract class BaseChannel extends Base { public constructor(client: Client, data?: RawChannelData, immediatePatch?: boolean); public get createdAt(): Date | null; public get createdTimestamp(): number | null; public id: Snowflake; + public flags: Readonly | null; public get partial(): false; public type: ChannelType; public get url(): string; @@ -1225,7 +1233,7 @@ export abstract class GuildChannel extends BaseChannel { public get createdAt(): Date; public get createdTimestamp(): number; public get deletable(): boolean; - public flags: Readonly; + public flags: Readonly; public guild: Guild; public guildId: Snowflake; public get manageable(): boolean; @@ -1256,13 +1264,6 @@ export abstract class GuildChannel extends BaseChannel { public toString(): ChannelMention; } -export type GuildChannelFlagsString = keyof typeof ChannelFlags; - -export class GuildChannelFlagsBitField extends BitField { - public static Flags: typeof ChannelFlags; - public static resolve(bit?: BitFieldResolvable): number; -} - export class GuildEmoji extends BaseGuildEmoji { private constructor(client: Client, data: RawGuildEmojiData, guild: Guild); private _roles: Snowflake[]; @@ -2042,7 +2043,7 @@ export class OAuth2Guild extends BaseGuild { export class PartialGroupDMChannel extends BaseChannel { private constructor(client: Client, data: RawPartialGroupDMChannelData); public type: ChannelType.GroupDM; - public flags: never; + public flags: null; public name: string | null; public icon: string | null; public recipients: PartialRecipient[]; @@ -2365,6 +2366,7 @@ export class StageChannel extends BaseGuildVoiceChannel { } export class DirectoryChannel extends BaseChannel { + public flags: Readonly; public guild: InviteGuild; public guildId: Snowflake; public name: string; From 82788059b7a6dfc7888b64d4473699046123d686 Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Fri, 16 Sep 2022 16:41:09 +0100 Subject: [PATCH 43/60] fix(ThreadChannel): receive tags --- packages/discord.js/src/structures/ThreadChannel.js | 5 ++--- packages/discord.js/typings/index.d.ts | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/discord.js/src/structures/ThreadChannel.js b/packages/discord.js/src/structures/ThreadChannel.js index 7cf6b03fb4c9..fc365c17dc43 100644 --- a/packages/discord.js/src/structures/ThreadChannel.js +++ b/packages/discord.js/src/structures/ThreadChannel.js @@ -6,7 +6,6 @@ const TextBasedChannel = require('./interfaces/TextBasedChannel'); const { RangeError, ErrorCodes } = require('../errors'); const MessageManager = require('../managers/MessageManager'); const ThreadMemberManager = require('../managers/ThreadMemberManager'); -const { transformAPIGuildForumTag } = require('../util/Channels'); /** * Represents a thread channel on Discord. @@ -198,9 +197,9 @@ class ThreadChannel extends BaseChannel { if ('applied_tags' in data) { /** * The tags applied to this thread - * @type {GuildForumTag[]} + * @type {Snowflake[]} */ - this.appliedTags = data.applied_tags.map(tag => transformAPIGuildForumTag(tag)); + this.appliedTags = data.applied_tags; } else { this.appliedTags ??= []; } diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index b3aed37c2be8..b04968e0af90 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -2573,6 +2573,7 @@ export class ThreadChannel extends TextBasedChannelMixin(BaseChannel, true, [ public get sendable(): boolean; public memberCount: number | null; public messageCount: number | null; + public appliedTags: Snowflake[]; public totalMessageSent: number | null; public members: ThreadMemberManager; public name: string; From 2bd75f9565559ac48d0f531de4bb2347f30f17bb Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Fri, 16 Sep 2022 17:01:22 +0100 Subject: [PATCH 44/60] fix(PartialGroupDMChannel): nullify `flags` Apparently did not do this earlier. --- packages/discord.js/src/structures/PartialGroupDMChannel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/discord.js/src/structures/PartialGroupDMChannel.js b/packages/discord.js/src/structures/PartialGroupDMChannel.js index 8f57ed2d6759..6f0c81a5ad23 100644 --- a/packages/discord.js/src/structures/PartialGroupDMChannel.js +++ b/packages/discord.js/src/structures/PartialGroupDMChannel.js @@ -12,7 +12,7 @@ class PartialGroupDMChannel extends BaseChannel { super(client, data); // No flags are present when fetching partial group DM channels. - delete this.flags; + this.flags = null; /** * The name of this Group DM Channel From 6ef3db73fd5211c39fe6e36818424425825446ce Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Fri, 16 Sep 2022 17:18:22 +0100 Subject: [PATCH 45/60] chore: misc sorting --- packages/discord.js/src/util/Channels.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/discord.js/src/util/Channels.js b/packages/discord.js/src/util/Channels.js index b2741b0288f8..cd3698ff92ba 100644 --- a/packages/discord.js/src/util/Channels.js +++ b/packages/discord.js/src/util/Channels.js @@ -140,8 +140,8 @@ function transformGuildDefaultReaction(defaultReaction) { module.exports = { createChannel, - transformGuildForumTag, transformAPIGuildForumTag, - transformGuildDefaultReaction, + transformGuildForumTag, transformAPIGuildDefaultReaction, + transformGuildDefaultReaction, }; From b69417ad9ef1e766e79eff8805fc33070b2774fc Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Fri, 16 Sep 2022 17:27:27 +0100 Subject: [PATCH 46/60] refactor: nullify emoji on tags if not present --- .../discord.js/src/structures/ForumChannel.js | 2 +- packages/discord.js/src/util/Channels.js | 15 +++++++++------ packages/discord.js/typings/index.d.ts | 2 +- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/discord.js/src/structures/ForumChannel.js b/packages/discord.js/src/structures/ForumChannel.js index 7fcba172bf02..34177ea88f72 100644 --- a/packages/discord.js/src/structures/ForumChannel.js +++ b/packages/discord.js/src/structures/ForumChannel.js @@ -16,7 +16,7 @@ const { transformAPIGuildForumTag, transformAPIGuildDefaultReaction } = require( * @property {string} name The name of the tag * @property {boolean} moderated Whether this tag can only be added to or removed from threads * by a member with the `ManageThreads` permission - * @property {GuildForumTagEmoji} emoji The emoji of this tag + * @property {?GuildForumTagEmoji} emoji The emoji of this tag */ /** diff --git a/packages/discord.js/src/util/Channels.js b/packages/discord.js/src/util/Channels.js index cd3698ff92ba..d08e00ccc4f8 100644 --- a/packages/discord.js/src/util/Channels.js +++ b/packages/discord.js/src/util/Channels.js @@ -87,10 +87,13 @@ function transformAPIGuildForumTag(tag) { id: tag.id, name: tag.name, moderated: tag.moderated, - emoji: { - id: tag.emoji_id, - name: tag.emoji_name, - }, + emoji: + tag.emoji_id ?? tag.emoji_name + ? { + id: tag.emoji_id, + name: tag.emoji_name, + } + : null, }; } @@ -105,8 +108,8 @@ function transformGuildForumTag(tag) { id: tag.id, name: tag.name, moderated: tag.moderated, - emoji_id: tag.emoji.id, - emoji_name: tag.emoji.name, + emoji_id: tag.emoji?.id ?? null, + emoji_name: tag.emoji?.name ?? null, }; } diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index b04968e0af90..e842a5d2257a 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -2060,7 +2060,7 @@ export interface GuildForumTag { id: Snowflake; name: string; moderated: boolean; - emoji: GuildForumTagEmoji; + emoji: GuildForumTagEmoji | null; } export interface DefaultReactionEmoji { From 510a0ae40c904f4258f583b9e15fefbcd7b317c7 Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Fri, 16 Sep 2022 20:30:54 +0100 Subject: [PATCH 47/60] refactor(ForumChannel): modify returns --- packages/discord.js/src/structures/ForumChannel.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/discord.js/src/structures/ForumChannel.js b/packages/discord.js/src/structures/ForumChannel.js index 34177ea88f72..18fd01dbcdb4 100644 --- a/packages/discord.js/src/structures/ForumChannel.js +++ b/packages/discord.js/src/structures/ForumChannel.js @@ -93,9 +93,8 @@ class ForumChannel extends GuildChannel { * @param {string} [reason] Reason for changing the default reaction emoji * @returns {Promise} */ - async setDefaultReactionEmoji(defaultReactionEmoji, reason) { - await this.edit({ defaultReactionEmoji, reason }); - return this; + setDefaultReactionEmoji(defaultReactionEmoji, reason) { + return this.edit({ defaultReactionEmoji, reason }); } /** @@ -104,9 +103,8 @@ class ForumChannel extends GuildChannel { * @param {string} [reason] Reason for changing the default rate limit * @returns {Promise} */ - async setDefaultThreadRateLimitPerUser(defaultThreadRateLimitPerUser, reason) { - await this.edit({ defaultThreadRateLimitPerUser, reason }); - return this; + setDefaultThreadRateLimitPerUser(defaultThreadRateLimitPerUser, reason) { + return this.edit({ defaultThreadRateLimitPerUser, reason }); } } From d1cc0b58da5bc2a2a672bee73e259186d7658b8b Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Sat, 17 Sep 2022 14:51:58 +0100 Subject: [PATCH 48/60] types: protect the thread manager! Co-authored-by: SpaceEEC --- packages/discord.js/typings/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index e842a5d2257a..985345af82b6 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -3668,7 +3668,7 @@ export class StageInstanceManager extends CachedManager { - public constructor(channel: TextChannel | NewsChannel, iterable?: Iterable); + protected constructor(channel: TextChannel | NewsChannel, iterable?: Iterable); public channel: TextChannel | NewsChannel; public fetch(options: ThreadChannelResolvable, cacheOptions?: BaseFetchOptions): Promise; public fetch(options?: FetchThreadsOptions, cacheOptions?: { cache?: boolean }): Promise; From ee73916744dd3de61b936bfa8f89a71b9847a53e Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Sat, 17 Sep 2022 15:27:01 +0100 Subject: [PATCH 49/60] chore: update `ChannelType` usage --- .../src/managers/GuildTextThreadManager.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/discord.js/src/managers/GuildTextThreadManager.js b/packages/discord.js/src/managers/GuildTextThreadManager.js index 83f8fad66d8b..6726ff450c06 100644 --- a/packages/discord.js/src/managers/GuildTextThreadManager.js +++ b/packages/discord.js/src/managers/GuildTextThreadManager.js @@ -15,11 +15,11 @@ class GuildTextThreadManager extends ThreadManager { * @property {MessageResolvable} [startMessage] The message to start a thread from. * If this is defined, then the `type` of thread gets inferred automatically and cannot be changed. * @property {ThreadChannelTypes|number} [type] The type of thread to create. - * Defaults to {@link ChannelType.GuildPublicThread} if created in a {@link TextChannel} - * When creating threads in a {@link NewsChannel} this is ignored and is always - * {@link ChannelType.GuildNewsThread} + * Defaults to {@link ChannelType.PublicThread} if created in a {@link TextChannel} + * When creating threads in a {@link NewsChannel}, this is ignored and is always + * {@link ChannelType.AnnouncementThread} * @property {boolean} [invitable] Whether non-moderators can add other non-moderators to the thread - * Can only be set when type will be {@link ChannelType.GuildPrivateThread} + * Can only be set when type will be {@link ChannelType.PrivateThread} */ /** @@ -42,7 +42,7 @@ class GuildTextThreadManager extends ThreadManager { * .create({ * name: 'mod-talk', * autoArchiveDuration: ThreadAutoArchiveDuration.OneHour, - * type: ChannelType.GuildPrivateThread, + * type: ChannelType.PrivateThread, * reason: 'Needed a separate thread for moderation', * }) * .then(threadChannel => console.log(threadChannel)) @@ -61,12 +61,12 @@ class GuildTextThreadManager extends ThreadManager { throw new TypeError(ErrorCodes.InvalidType, 'type', 'ThreadChannelType or Number'); } let resolvedType = - this.channel.type === ChannelType.GuildNews ? ChannelType.GuildNewsThread : ChannelType.GuildPublicThread; + this.channel.type === ChannelType.GuildAnnouncement ? ChannelType.AnnouncementThread : ChannelType.PublicThread; let startMessageId; if (startMessage) { startMessageId = this.channel.messages.resolveId(startMessage); if (!startMessageId) throw new TypeError(ErrorCodes.InvalidType, 'startMessage', 'MessageResolvable'); - } else if (this.channel.type !== ChannelType.GuildNews) { + } else if (this.channel.type !== ChannelType.GuildAnnouncement) { resolvedType = type ?? resolvedType; } @@ -75,7 +75,7 @@ class GuildTextThreadManager extends ThreadManager { name, auto_archive_duration: autoArchiveDuration, type: resolvedType, - invitable: resolvedType === ChannelType.GuildPrivateThread ? invitable : undefined, + invitable: resolvedType === ChannelType.PrivateThread ? invitable : undefined, rate_limit_per_user: rateLimitPerUser, }, reason, From 376e344b76f18f3d3e6990656ab4ce717d24b6de Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Sat, 17 Sep 2022 15:41:39 +0100 Subject: [PATCH 50/60] Update index.d.ts --- packages/discord.js/typings/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 985345af82b6..d1ff286176e8 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -2030,7 +2030,7 @@ export class ModalSubmitInteraction extend export class NewsChannel extends BaseGuildTextChannel { public threads: GuildTextThreadManager; - public type: ChannelType.AnnouncementThread; + public type: ChannelType.GuildAnnouncement; public addFollower(channel: TextChannelResolvable, reason?: string): Promise; } From 606e299d275b900943f2bb0700edb4a82dbf46b0 Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Sat, 17 Sep 2022 16:00:14 +0100 Subject: [PATCH 51/60] docs: Update default reaction emoji property names Co-authored-by: Almeida --- packages/discord.js/src/structures/ForumChannel.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/discord.js/src/structures/ForumChannel.js b/packages/discord.js/src/structures/ForumChannel.js index 18fd01dbcdb4..bd09afd2bfd7 100644 --- a/packages/discord.js/src/structures/ForumChannel.js +++ b/packages/discord.js/src/structures/ForumChannel.js @@ -21,8 +21,8 @@ const { transformAPIGuildForumTag, transformAPIGuildDefaultReaction } = require( /** * @typedef {Object} DefaultReactionEmoji - * @property {?Snowflake} emojiId The id of a guild's custom emoji - * @property {?string} emojiName The unicode character of the emoji + * @property {?Snowflake} id The id of a guild's custom emoji + * @property {?string} name The unicode character of the emoji */ /** From 761786bc7c20d0ada47b61457ee3c96f0bd73f82 Mon Sep 17 00:00:00 2001 From: almeidx Date: Sat, 17 Sep 2022 16:04:59 +0100 Subject: [PATCH 52/60] fix: only `name` is required when editing tags - discord/discord-api-docs#5458 --- .../discord.js/src/managers/GuildChannelManager.js | 2 +- packages/discord.js/src/structures/ForumChannel.js | 11 ++++++++++- packages/discord.js/typings/index.d.ts | 6 ++++-- packages/discord.js/typings/index.test-d.ts | 9 +++++++++ 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/packages/discord.js/src/managers/GuildChannelManager.js b/packages/discord.js/src/managers/GuildChannelManager.js index 84a52e94e6f7..f4267508fea5 100644 --- a/packages/discord.js/src/managers/GuildChannelManager.js +++ b/packages/discord.js/src/managers/GuildChannelManager.js @@ -219,7 +219,7 @@ class GuildChannelManager extends CachedManager { * The default auto archive duration for all new threads in this channel * @property {?string} [rtcRegion] The RTC region of the channel * @property {?VideoQualityMode} [videoQualityMode] The camera video quality mode of the channel - * @property {GuildForumTag[]} [availableTags] The tags to set as available in a forum channel + * @property {GuildForumTagData[]} [availableTags] The tags to set as available in a forum channel * @property {DefaultReactionEmoji} [defaultReactionEmoji] The emoji to set as the default reaction emoji * @property {number} [defaultThreadRateLimitPerUser] The rate limit per user (slowmode) to set on forum posts * @property {string} [reason] Reason for editing this channel diff --git a/packages/discord.js/src/structures/ForumChannel.js b/packages/discord.js/src/structures/ForumChannel.js index bd09afd2bfd7..f41ece1945c4 100644 --- a/packages/discord.js/src/structures/ForumChannel.js +++ b/packages/discord.js/src/structures/ForumChannel.js @@ -19,6 +19,15 @@ const { transformAPIGuildForumTag, transformAPIGuildDefaultReaction } = require( * @property {?GuildForumTagEmoji} emoji The emoji of this tag */ +/** + * @typedef {Object} GuildForumTagData + * @property {Snowflake} [id] The id of the tag + * @property {string} name The name of the tag + * @property {boolean} [moderated] Whether this tag can only be added to or removed from threads + * by a member with the `ManageThreads` permission + * @property {?GuildForumTagEmoji} [emoji] The emoji of this tag + */ + /** * @typedef {Object} DefaultReactionEmoji * @property {?Snowflake} id The id of a guild's custom emoji @@ -79,7 +88,7 @@ class ForumChannel extends GuildChannel { /** * Sets the available tags for this forum channel - * @param {GuildForumTag[]} availableTags The tags to set as available in this channel + * @param {GuildForumTagData[]} availableTags The tags to set as available in this channel * @param {string} [reason] Reason for changing the available tags * @returns {Promise} */ diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index d1ff286176e8..55e9591d218f 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -2063,6 +2063,8 @@ export interface GuildForumTag { emoji: GuildForumTagEmoji | null; } +type GuildForumTagData = Partial & { name: string }; + export interface DefaultReactionEmoji { id: Snowflake | null; name: string | null; @@ -2075,7 +2077,7 @@ export class ForumChannel extends GuildChannel { public defaultReactionEmoji: DefaultReactionEmoji | null; public defaultThreadRateLimitPerUser: number | null; - public setAvailableTags(tags: GuildForumTag[], reason?: string): Promise; + public setAvailableTags(tags: GuildForumTagData[], reason?: string): Promise; public setDefaultReaction(emojiId: DefaultReactionEmoji, reason?: string): Promise; public setDefaultThreadRateLimitPerUser(rateLimit: number, reason?: string): Promise; } @@ -4889,7 +4891,7 @@ export interface GuildChannelEditOptions { defaultAutoArchiveDuration?: ThreadAutoArchiveDuration; rtcRegion?: string | null; videoQualityMode?: VideoQualityMode | null; - availableTags?: GuildForumTag[]; + availableTags?: GuildForumTagData[]; defaultReactionEmoji?: DefaultReactionEmoji; defaultThreadRateLimitPerUser?: number; reason?: string; diff --git a/packages/discord.js/typings/index.test-d.ts b/packages/discord.js/typings/index.test-d.ts index efd100f7b857..bb67c6093689 100644 --- a/packages/discord.js/typings/index.test-d.ts +++ b/packages/discord.js/typings/index.test-d.ts @@ -1979,3 +1979,12 @@ expectType>(webhookClient.fetchMessage(snowflake)); expectType>(interactionWebhook.send('content')); expectType>(interactionWebhook.editMessage(snowflake, 'content')); expectType>(interactionWebhook.fetchMessage(snowflake)); + +declare const forumChannel: ForumChannel; + +await forumChannel.edit({ + availableTags: [...forumChannel.availableTags, { name: 'tag' }], +}); + +await forumChannel.setAvailableTags([{ ...forumChannel.availableTags, name: 'tag' }]); +await forumChannel.setAvailableTags([{ name: 'tag' }]); From e5ca18adf2fb50dddfeb3b52bcc45916d4a4d128 Mon Sep 17 00:00:00 2001 From: almeidx Date: Sat, 17 Sep 2022 16:21:57 +0100 Subject: [PATCH 53/60] types: add tests for `channel.flags` --- packages/discord.js/typings/index.d.ts | 4 +++- packages/discord.js/typings/index.test-d.ts | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 55e9591d218f..775f58707ab2 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -1051,6 +1051,7 @@ export class DMChannel extends TextBasedChannelMixin(BaseChannel, false, [ 'setNSFW', ]) { private constructor(client: Client, data?: RawDMChannelData); + public flags: Readonly; public recipientId: Snowflake; public get recipient(): User | null; public type: ChannelType.DM; @@ -2063,7 +2064,7 @@ export interface GuildForumTag { emoji: GuildForumTagEmoji | null; } -type GuildForumTagData = Partial & { name: string }; +export type GuildForumTagData = Partial & { name: string }; export interface DefaultReactionEmoji { id: Snowflake | null; @@ -2563,6 +2564,7 @@ export class ThreadChannel extends TextBasedChannelMixin(BaseChannel, true, [ public get createdTimestamp(): number | null; public autoArchiveDuration: ThreadAutoArchiveDuration | null; public get editable(): boolean; + public flags: Readonly; public guild: Guild; public guildId: Snowflake; public get guildMembers(): Collection; diff --git a/packages/discord.js/typings/index.test-d.ts b/packages/discord.js/typings/index.test-d.ts index bb67c6093689..1fef7ceeda41 100644 --- a/packages/discord.js/typings/index.test-d.ts +++ b/packages/discord.js/typings/index.test-d.ts @@ -138,6 +138,7 @@ import { GuildAuditLogsTargetType, ModalSubmitInteraction, ForumChannel, + ChannelFlagsBitField, } from '.'; import { expectAssignable, expectNotAssignable, expectNotType, expectType } from 'tsd'; import type { ContextMenuCommandBuilder, SlashCommandBuilder } from '@discordjs/builders'; @@ -1980,6 +1981,7 @@ expectType>(interactionWebhook.send('content')); expectType>(interactionWebhook.editMessage(snowflake, 'content')); expectType>(interactionWebhook.fetchMessage(snowflake)); +declare const categoryChannel: CategoryChannel; declare const forumChannel: ForumChannel; await forumChannel.edit({ @@ -1988,3 +1990,15 @@ await forumChannel.edit({ await forumChannel.setAvailableTags([{ ...forumChannel.availableTags, name: 'tag' }]); await forumChannel.setAvailableTags([{ name: 'tag' }]); + +expectType>(textChannel.flags); +expectType>(voiceChannel.flags); +expectType>(stageChannel.flags); +expectType>(forumChannel.flags); +expectType>(dmChannel.flags); +expectType>(categoryChannel.flags); +expectType>(newsChannel.flags); +expectType>(categoryChannel.flags); +expectType>(threadChannel.flags); + +expectType(partialGroupDMChannel.flags); From b8f99de61a3cfefb6c421d5468e32138ecd7289f Mon Sep 17 00:00:00 2001 From: almeidx Date: Sat, 17 Sep 2022 16:28:35 +0100 Subject: [PATCH 54/60] fix: allow unsetting the default reaction emoji --- packages/discord.js/src/managers/GuildChannelManager.js | 6 ++---- packages/discord.js/src/structures/ForumChannel.js | 2 +- packages/discord.js/typings/index.d.ts | 4 ++-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/discord.js/src/managers/GuildChannelManager.js b/packages/discord.js/src/managers/GuildChannelManager.js index f4267508fea5..8176bd02bb36 100644 --- a/packages/discord.js/src/managers/GuildChannelManager.js +++ b/packages/discord.js/src/managers/GuildChannelManager.js @@ -220,7 +220,7 @@ class GuildChannelManager extends CachedManager { * @property {?string} [rtcRegion] The RTC region of the channel * @property {?VideoQualityMode} [videoQualityMode] The camera video quality mode of the channel * @property {GuildForumTagData[]} [availableTags] The tags to set as available in a forum channel - * @property {DefaultReactionEmoji} [defaultReactionEmoji] The emoji to set as the default reaction emoji + * @property {?DefaultReactionEmoji} [defaultReactionEmoji] The emoji to set as the default reaction emoji * @property {number} [defaultThreadRateLimitPerUser] The rate limit per user (slowmode) to set on forum posts * @property {string} [reason] Reason for editing this channel */ @@ -279,9 +279,7 @@ class GuildChannelManager extends CachedManager { default_auto_archive_duration: data.defaultAutoArchiveDuration, permission_overwrites, available_tags: data.availableTags?.map(availableTag => transformGuildForumTag(availableTag)), - default_reaction_emoji: data.defaultReactionEmoji - ? transformGuildDefaultReaction(data.defaultReactionEmoji) - : undefined, + default_reaction_emoji: data.defaultReactionEmoji && transformGuildDefaultReaction(data.defaultReactionEmoji), default_thread_rate_limit_per_user: data.defaultThreadRateLimitPerUser, }, reason: data.reason, diff --git a/packages/discord.js/src/structures/ForumChannel.js b/packages/discord.js/src/structures/ForumChannel.js index f41ece1945c4..22bf00eac978 100644 --- a/packages/discord.js/src/structures/ForumChannel.js +++ b/packages/discord.js/src/structures/ForumChannel.js @@ -98,7 +98,7 @@ class ForumChannel extends GuildChannel { /** * Sets the default reaction emoji for this channel - * @param {DefaultReactionEmoji} defaultReactionEmoji The emoji to set as the default reaction emoji + * @param {?DefaultReactionEmoji} defaultReactionEmoji The emoji to set as the default reaction emoji * @param {string} [reason] Reason for changing the default reaction emoji * @returns {Promise} */ diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 775f58707ab2..c861c88fcdb4 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -2079,7 +2079,7 @@ export class ForumChannel extends GuildChannel { public defaultThreadRateLimitPerUser: number | null; public setAvailableTags(tags: GuildForumTagData[], reason?: string): Promise; - public setDefaultReaction(emojiId: DefaultReactionEmoji, reason?: string): Promise; + public setDefaultReactionEmoji(emojiId: DefaultReactionEmoji | null, reason?: string): Promise; public setDefaultThreadRateLimitPerUser(rateLimit: number, reason?: string): Promise; } @@ -4894,7 +4894,7 @@ export interface GuildChannelEditOptions { rtcRegion?: string | null; videoQualityMode?: VideoQualityMode | null; availableTags?: GuildForumTagData[]; - defaultReactionEmoji?: DefaultReactionEmoji; + defaultReactionEmoji?: DefaultReactionEmoji | null; defaultThreadRateLimitPerUser?: number; reason?: string; } From ed9667a5985c23641087038b7744dc6a0c248836 Mon Sep 17 00:00:00 2001 From: almeidx Date: Sat, 17 Sep 2022 16:35:49 +0100 Subject: [PATCH 55/60] refactor: remove v13 remnants --- packages/discord.js/src/managers/GuildTextThreadManager.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/discord.js/src/managers/GuildTextThreadManager.js b/packages/discord.js/src/managers/GuildTextThreadManager.js index 6726ff450c06..9f1ac9b44e15 100644 --- a/packages/discord.js/src/managers/GuildTextThreadManager.js +++ b/packages/discord.js/src/managers/GuildTextThreadManager.js @@ -14,7 +14,7 @@ class GuildTextThreadManager extends ThreadManager { * @typedef {StartThreadOptions} ThreadCreateOptions * @property {MessageResolvable} [startMessage] The message to start a thread from. * If this is defined, then the `type` of thread gets inferred automatically and cannot be changed. - * @property {ThreadChannelTypes|number} [type] The type of thread to create. + * @property {ThreadChannelTypes} [type] The type of thread to create. * Defaults to {@link ChannelType.PublicThread} if created in a {@link TextChannel} * When creating threads in a {@link NewsChannel}, this is ignored and is always * {@link ChannelType.AnnouncementThread} @@ -57,9 +57,6 @@ class GuildTextThreadManager extends ThreadManager { reason, rateLimitPerUser, } = {}) { - if (type && typeof type !== 'string' && typeof type !== 'number') { - throw new TypeError(ErrorCodes.InvalidType, 'type', 'ThreadChannelType or Number'); - } let resolvedType = this.channel.type === ChannelType.GuildAnnouncement ? ChannelType.AnnouncementThread : ChannelType.PublicThread; let startMessageId; From 097db15d3c96162132705160a80a97a4b5ad3289 Mon Sep 17 00:00:00 2001 From: almeidx Date: Sat, 17 Sep 2022 16:42:01 +0100 Subject: [PATCH 56/60] docs: add missing closing tag --- packages/discord.js/src/structures/BaseChannel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/discord.js/src/structures/BaseChannel.js b/packages/discord.js/src/structures/BaseChannel.js index b44a6e402ef1..0e71cc3d7887 100644 --- a/packages/discord.js/src/structures/BaseChannel.js +++ b/packages/discord.js/src/structures/BaseChannel.js @@ -29,7 +29,7 @@ class BaseChannel extends Base { if ('flags' in data) { /** * The flags that are applied to the channel. - * This is only `null` in a {@link PartialGroupDMChannel}. In all other cases, it is not `null`. + * This is only `null` in a {@link PartialGroupDMChannel}. In all other cases, it is not `null`. * @type {?Readonly} */ this.flags = new ChannelFlagsBitField(data.flags).freeze(); From 9369a141b6d649f263faf517b27d3a772fe6d4cf Mon Sep 17 00:00:00 2001 From: almeidx Date: Sat, 17 Sep 2022 17:16:15 +0100 Subject: [PATCH 57/60] feat: add `rateLimitPerUser` --- .../discord.js/src/structures/ForumChannel.js | 20 +++++++++++++++++++ packages/discord.js/typings/index.d.ts | 2 ++ 2 files changed, 22 insertions(+) diff --git a/packages/discord.js/src/structures/ForumChannel.js b/packages/discord.js/src/structures/ForumChannel.js index 22bf00eac978..a19ab19a43b8 100644 --- a/packages/discord.js/src/structures/ForumChannel.js +++ b/packages/discord.js/src/structures/ForumChannel.js @@ -84,6 +84,16 @@ class ForumChannel extends GuildChannel { } else { this.defaultThreadRateLimitPerUser ??= null; } + + if ('rate_limit_per_user' in data) { + /** + * The rate limit per user (slowmode) for this channel. + * @type {?number} + */ + this.rateLimitPerUser = data.rate_limit_per_user; + } else { + this.rateLimitPerUser ??= null; + } } /** @@ -115,6 +125,16 @@ class ForumChannel extends GuildChannel { setDefaultThreadRateLimitPerUser(defaultThreadRateLimitPerUser, reason) { return this.edit({ defaultThreadRateLimitPerUser, reason }); } + + /** + * Sets the rate limit per user (slowmode) for this channel + * @param {?number} rateLimitPerUser The rate limit to set on this channel + * @param {string} [reason] Reason for changing the rate limit + * @returns {Promise} + */ + setRateLimitPerUser(rateLimitPerUser, reason) { + return this.edit({ rateLimitPerUser, reason }); + } } module.exports = ForumChannel; diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index c861c88fcdb4..3e5ec5acc0fe 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -2077,10 +2077,12 @@ export class ForumChannel extends GuildChannel { public availableTags: GuildForumTag[]; public defaultReactionEmoji: DefaultReactionEmoji | null; public defaultThreadRateLimitPerUser: number | null; + public rateLimitPerUser: number | null; public setAvailableTags(tags: GuildForumTagData[], reason?: string): Promise; public setDefaultReactionEmoji(emojiId: DefaultReactionEmoji | null, reason?: string): Promise; public setDefaultThreadRateLimitPerUser(rateLimit: number, reason?: string): Promise; + public setRateLimitPerUser(rateLimitPerUser: number | null, reason?: string): Promise; } export class PermissionOverwrites extends Base { From 231d7f095ce06166eb52aacfc6e453995bc71862 Mon Sep 17 00:00:00 2001 From: almeidx Date: Sat, 17 Sep 2022 17:20:55 +0100 Subject: [PATCH 58/60] feat: add missing properties for create guild channel - discord/discord-api-docs#5474 --- .../discord.js/src/managers/CategoryChannelChildManager.js | 3 +++ packages/discord.js/src/managers/GuildChannelManager.js | 4 ++++ packages/discord.js/typings/index.d.ts | 2 ++ 3 files changed, 9 insertions(+) diff --git a/packages/discord.js/src/managers/CategoryChannelChildManager.js b/packages/discord.js/src/managers/CategoryChannelChildManager.js index bd594fd40a4b..49c593b59684 100644 --- a/packages/discord.js/src/managers/CategoryChannelChildManager.js +++ b/packages/discord.js/src/managers/CategoryChannelChildManager.js @@ -50,6 +50,9 @@ class CategoryChannelChildManager extends DataManager { * @property {number} [rateLimitPerUser] The rate limit per user (slowmode) for the new channel in seconds * @property {string} [rtcRegion] The specific region of the new channel. * @property {VideoQualityMode} [videoQualityMode] The camera video quality mode of the voice channel + * @property {GuildForumTagData[]} [availableTags] The tags that can be used in this channel (forum only). + * @property {DefaultReactionEmoji} [defaultReactionEmoji] + * The emoji to show in the add reaction button on a thread in a guild forum channel. * @property {string} [reason] Reason for creating the new channel */ diff --git a/packages/discord.js/src/managers/GuildChannelManager.js b/packages/discord.js/src/managers/GuildChannelManager.js index 8176bd02bb36..7549dfc99296 100644 --- a/packages/discord.js/src/managers/GuildChannelManager.js +++ b/packages/discord.js/src/managers/GuildChannelManager.js @@ -138,6 +138,8 @@ class GuildChannelManager extends CachedManager { rateLimitPerUser, rtcRegion, videoQualityMode, + availableTags, + defaultReactionEmoji, reason, }) { parent &&= this.client.channels.resolveId(parent); @@ -157,6 +159,8 @@ class GuildChannelManager extends CachedManager { rate_limit_per_user: rateLimitPerUser, rtc_region: rtcRegion, video_quality_mode: videoQualityMode, + available_tags: availableTags?.map(availableTag => transformGuildForumTag(availableTag)), + default_reaction_emoji: defaultReactionEmoji && transformGuildDefaultReaction(defaultReactionEmoji), }, reason, }); diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 3e5ec5acc0fe..5cd71eca2aad 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -4218,6 +4218,8 @@ export interface CategoryCreateChannelOptions { position?: number; rtcRegion?: string; videoQualityMode?: VideoQualityMode; + availableTags?: GuildForumTagData[]; + defaultReactionEmoji?: DefaultReactionEmoji; reason?: string; } From 25af6b6c7ecc754c0d3694831458fd4ee87fdf48 Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Sat, 17 Sep 2022 22:15:26 +0100 Subject: [PATCH 59/60] refactor(GuildForumThreadManager): refactor message payload --- .../discord.js/src/managers/GuildForumThreadManager.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/discord.js/src/managers/GuildForumThreadManager.js b/packages/discord.js/src/managers/GuildForumThreadManager.js index ee49223e184f..d124e8b82ae3 100644 --- a/packages/discord.js/src/managers/GuildForumThreadManager.js +++ b/packages/discord.js/src/managers/GuildForumThreadManager.js @@ -53,10 +53,9 @@ class GuildForumThreadManager extends ThreadManager { throw new TypeError(ErrorCodes.GuildForumMessageRequired); } - const messagePayload = - message instanceof MessagePayload ? message.resolveBody() : MessagePayload.create(this, message).resolveBody(); - - const { body, files } = await messagePayload.resolveFiles(); + const { body, files } = await (message instanceof MessagePayload ? message : MessagePayload.create(this, message)) + .resolveBody() + .resolveFiles(); const data = await this.client.rest.post(Routes.threads(this.channel.id), { body: { From 45bd884b3f821b0416a73e20f040af41d378259f Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Sun, 18 Sep 2022 00:45:17 +0100 Subject: [PATCH 60/60] fix: handle magical `null` case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: A. Román --- packages/discord.js/src/structures/BaseChannel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/discord.js/src/structures/BaseChannel.js b/packages/discord.js/src/structures/BaseChannel.js index 0e71cc3d7887..d3096d969633 100644 --- a/packages/discord.js/src/structures/BaseChannel.js +++ b/packages/discord.js/src/structures/BaseChannel.js @@ -34,7 +34,7 @@ class BaseChannel extends Base { */ this.flags = new ChannelFlagsBitField(data.flags).freeze(); } else { - this.flags = new ChannelFlagsBitField(this.flags).freeze(); + this.flags ??= new ChannelFlagsBitField().freeze(); } /**