From 5be471b47dd65616e6b3ee8afdc4a395ef60e1cc Mon Sep 17 00:00:00 2001 From: monbrey Date: Thu, 5 Aug 2021 06:55:31 +1000 Subject: [PATCH] refactor(Channels): fix incorrectly shared properties (#6262) Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com> --- src/structures/BaseGuildTextChannel.js | 239 ++++++++++++++++++++++++ src/structures/BaseGuildVoiceChannel.js | 24 +++ src/structures/GuildChannel.js | 60 +----- src/structures/NewsChannel.js | 13 +- src/structures/StageChannel.js | 15 ++ src/structures/StoreChannel.js | 24 +++ src/structures/TextChannel.js | 176 +---------------- typings/index.d.ts | 65 +++---- 8 files changed, 341 insertions(+), 275 deletions(-) create mode 100644 src/structures/BaseGuildTextChannel.js diff --git a/src/structures/BaseGuildTextChannel.js b/src/structures/BaseGuildTextChannel.js new file mode 100644 index 000000000..9571d239c --- /dev/null +++ b/src/structures/BaseGuildTextChannel.js @@ -0,0 +1,239 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const GuildChannel = require('./GuildChannel'); +const Webhook = require('./Webhook'); +const TextBasedChannel = require('./interfaces/TextBasedChannel'); +const MessageManager = require('../managers/MessageManager'); +const ThreadManager = require('../managers/ThreadManager'); +const DataResolver = require('../util/DataResolver'); + +/** + * Represents a text-based guild channel on Discord. + * @extends {GuildChannel} + * @implements {TextBasedChannel} + */ +class BaseGuildTextChannel extends GuildChannel { + /** + * @param {Guild} guild The guild the text channel is part of + * @param {APIChannel} data The data for the text channel + * @param {Client} [client] A safety parameter for the client that instantiated this + */ + constructor(guild, data, client) { + super(guild, data, client, false); + + /** + * A manager of the messages sent to this channel + * @type {MessageManager} + */ + this.messages = new MessageManager(this); + + /** + * A manager of the threads belonging to this channel + * @type {ThreadManager} + */ + this.threads = new ThreadManager(this); + + /** + * If the guild considers this channel NSFW + * @type {boolean} + */ + this.nsfw = Boolean(data.nsfw); + } + + _patch(data) { + super._patch(data); + + if ('topic' in data) { + /** + * The topic of the text channel + * @type {?string} + */ + this.topic = data.topic; + } + + if ('nsfw' in data) { + this.nsfw = Boolean(data.nsfw); + } + + if ('last_message_id' in data) { + /** + * The last message id sent in the channel, if one was sent + * @type {?Snowflake} + */ + this.lastMessageId = data.last_message_id; + } + + if ('last_pin_timestamp' in data) { + /** + * The timestamp when the last pinned message was pinned, if there was one + * @type {?number} + */ + this.lastPinTimestamp = data.last_pin_timestamp ? new Date(data.last_pin_timestamp).getTime() : null; + } + + if ('default_auto_archive_duration' in data) { + /** + * The default auto archive duration for newly created threads in this channel + * @type {?ThreadAutoArchiveDuration} + */ + this.defaultAutoArchiveDuration = data.default_auto_archive_duration; + } + + if ('messages' in data) { + for (const message of data.messages) this.messages._add(message); + } + } + + /** + * Sets the default auto archive duration for all newly created threads in this channel. + * @param {ThreadAutoArchiveDuration} defaultAutoArchiveDuration The new default auto archive duration + * @param {string} [reason] Reason for changing the channel's default auto archive duration + * @returns {Promise} + */ + setDefaultAutoArchiveDuration(defaultAutoArchiveDuration, reason) { + return this.edit({ defaultAutoArchiveDuration }, reason); + } + + /** + * Sets whether this channel is flagged as NSFW. + * @param {boolean} nsfw Whether the channel should be considered NSFW + * @param {string} [reason] Reason for changing the channel's NSFW flag + * @returns {Promise} + */ + setNSFW(nsfw, reason) { + return this.edit({ nsfw }, reason); + } + + /** + * Sets the type of this channel (only conversion between text and news is supported) + * @param {string} type The new channel type + * @param {string} [reason] Reason for changing the channel's type + * @returns {Promise} + */ + setType(type, reason) { + return this.edit({ type }, reason); + } + + /** + * Fetches all webhooks for the channel. + * @returns {Promise>} + * @example + * // Fetch webhooks + * channel.fetchWebhooks() + * .then(hooks => console.log(`This channel has ${hooks.size} hooks`)) + * .catch(console.error); + */ + async fetchWebhooks() { + const data = await this.client.api.channels[this.id].webhooks.get(); + const hooks = new Collection(); + for (const hook of data) hooks.set(hook.id, new Webhook(this.client, hook)); + return hooks; + } + + /** + * Options used to create a {@link Webhook} for {@link TextChannel} and {@link NewsChannel}. + * @typedef {Object} ChannelWebhookCreateOptions + * @property {BufferResolvable|Base64Resolvable} [avatar] Avatar for the webhook + * @property {string} [reason] Reason for creating the webhook + */ + + /** + * Creates a webhook for the channel. + * @param {string} name The name of the webhook + * @param {ChannelWebhookCreateOptions} [options] Options for creating the webhook + * @returns {Promise} Returns the created Webhook + * @example + * // Create a webhook for the current channel + * channel.createWebhook('Snek', { + * avatar: 'https://i.imgur.com/mI8XcpG.jpg', + * reason: 'Needed a cool new Webhook' + * }) + * .then(console.log) + * .catch(console.error) + */ + async createWebhook(name, { avatar, reason } = {}) { + if (typeof avatar === 'string' && !avatar.startsWith('data:')) { + avatar = await DataResolver.resolveImage(avatar); + } + const data = await this.client.api.channels[this.id].webhooks.post({ + data: { + name, + avatar, + }, + reason, + }); + return new Webhook(this.client, data); + } + + /** + * Sets a new topic for the guild channel. + * @param {?string} topic The new topic for the guild channel + * @param {string} [reason] Reason for changing the guild channel's topic + * @returns {Promise} + * @example + * // Set a new channel topic + * channel.setTopic('needs more rate limiting') + * .then(newChannel => console.log(`Channel's new topic is ${newChannel.topic}`)) + * .catch(console.error); + */ + setTopic(topic, reason) { + return this.edit({ topic }, reason); + } + + /** + * Options used to create an invite to a guild channel. + * @typedef {Object} CreateInviteOptions + * @property {boolean} [temporary=false] Whether members that joined via the invite should be automatically + * kicked after 24 hours if they have not yet received a role + * @property {number} [maxAge=86400] How long the invite should last (in seconds, 0 for forever) + * @property {number} [maxUses=0] Maximum number of uses + * @property {boolean} [unique=false] Create a unique invite, or use an existing one with similar settings + * @property {UserResolvable} [targetUser] The user whose stream to display for this invite, + * required if `targetType` is 1, the user must be streaming in the channel + * @property {ApplicationResolvable} [targetApplication] The embedded application to open for this invite, + * required if `targetType` is 2, the application must have the `EMBEDDED` flag + * @property {TargetType} [targetType] The type of the target for this voice channel invite + * @property {string} [reason] The reason for creating the invite + */ + + /** + * Creates an invite to this guild channel. + * @param {CreateInviteOptions} [options={}] The options for creating the invite + * @returns {Promise} + * @example + * // Create an invite to a channel + * channel.createInvite() + * .then(invite => console.log(`Created an invite with a code of ${invite.code}`)) + * .catch(console.error); + */ + createInvite(options) { + return this.guild.invites.create(this.id, options); + } + + /** + * Fetches a collection of invites to this guild channel. + * Resolves with a collection mapping invites by their codes. + * @param {boolean} [cache=true] Whether or not to cache the fetched invites + * @returns {Promise>} + */ + fetchInvites(cache = true) { + return this.guild.invites.fetch({ channelId: this.id, cache }); + } + + // These are here only for documentation purposes - they are implemented by TextBasedChannel + /* eslint-disable no-empty-function */ + get lastMessage() {} + get lastPinAt() {} + send() {} + sendTyping() {} + createMessageCollector() {} + awaitMessages() {} + createMessageComponentCollector() {} + awaitMessageComponent() {} + bulkDelete() {} +} + +TextBasedChannel.applyToClass(BaseGuildTextChannel, true); + +module.exports = BaseGuildTextChannel; diff --git a/src/structures/BaseGuildVoiceChannel.js b/src/structures/BaseGuildVoiceChannel.js index 31893b109..d678fd2b0 100644 --- a/src/structures/BaseGuildVoiceChannel.js +++ b/src/structures/BaseGuildVoiceChannel.js @@ -80,6 +80,30 @@ class BaseGuildVoiceChannel extends GuildChannel { setRTCRegion(region) { return this.edit({ rtcRegion: region }); } + + /** + * Creates an invite to this guild channel. + * @param {CreateInviteOptions} [options={}] The options for creating the invite + * @returns {Promise} + * @example + * // Create an invite to a channel + * channel.createInvite() + * .then(invite => console.log(`Created an invite with a code of ${invite.code}`)) + * .catch(console.error); + */ + createInvite(options) { + return this.guild.invites.create(this.id, options); + } + + /** + * Fetches a collection of invites to this guild channel. + * Resolves with a collection mapping invites by their codes. + * @param {boolean} [cache=true] Whether or not to cache the fetched invites + * @returns {Promise>} + */ + fetchInvites(cache = true) { + return this.guild.invites.fetch({ channelId: this.id, cache }); + } } module.exports = BaseGuildVoiceChannel; diff --git a/src/structures/GuildChannel.js b/src/structures/GuildChannel.js index 1e5c5ce49..b706ffa39 100644 --- a/src/structures/GuildChannel.js +++ b/src/structures/GuildChannel.js @@ -24,8 +24,9 @@ class GuildChannel extends Channel { * @param {Guild} guild The guild the guild channel is part of * @param {APIChannel} data The data for the guild channel * @param {Client} [client] A safety parameter for the client that instantiated this + * @param {boolean} [immediatePatch=true] Control variable for patching */ - constructor(guild, data, client) { + constructor(guild, data, client, immediatePatch = true) { super(guild?.client ?? client, data, false); /** @@ -47,7 +48,7 @@ class GuildChannel extends Channel { */ this.permissionOverwrites = new PermissionOverwriteManager(this); - this._patch(data); + if (data && immediatePatch) this._patch(data); } _patch(data) { @@ -395,21 +396,6 @@ class GuildChannel extends Channel { ); } - /** - * Sets a new topic for the guild channel. - * @param {?string} topic The new topic for the guild channel - * @param {string} [reason] Reason for changing the guild channel's topic - * @returns {Promise} - * @example - * // Set a new channel topic - * channel.setTopic('needs more rate limiting') - * .then(newChannel => console.log(`Channel's new topic is ${newChannel.topic}`)) - * .catch(console.error); - */ - setTopic(topic, reason) { - return this.edit({ topic }, reason); - } - /** * Options used to set position of a channel. * @typedef {Object} SetChannelPositionOptions @@ -452,46 +438,6 @@ class GuildChannel extends Channel { * @typedef {Application|Snowflake} ApplicationResolvable */ - /** - * Options used to create an invite to a guild channel. - * @typedef {Object} CreateInviteOptions - * @property {boolean} [temporary=false] Whether members that joined via the invite should be automatically - * kicked after 24 hours if they have not yet received a role - * @property {number} [maxAge=86400] How long the invite should last (in seconds, 0 for forever) - * @property {number} [maxUses=0] Maximum number of uses - * @property {boolean} [unique=false] Create a unique invite, or use an existing one with similar settings - * @property {UserResolvable} [targetUser] The user whose stream to display for this invite, - * required if `targetType` is 1, the user must be streaming in the channel - * @property {ApplicationResolvable} [targetApplication] The embedded application to open for this invite, - * required if `targetType` is 2, the application must have the `EMBEDDED` flag - * @property {TargetType} [targetType] The type of the target for this voice channel invite - * @property {string} [reason] The reason for creating the invite - */ - - /** - * Creates an invite to this guild channel. - * @param {CreateInviteOptions} [options={}] The options for creating the invite - * @returns {Promise} - * @example - * // Create an invite to a channel - * channel.createInvite() - * .then(invite => console.log(`Created an invite with a code of ${invite.code}`)) - * .catch(console.error); - */ - createInvite(options) { - return this.guild.invites.create(this.id, options); - } - - /** - * Fetches a collection of invites to this guild channel. - * Resolves with a collection mapping invites by their codes. - * @param {boolean} [cache=true] Whether or not to cache the fetched invites - * @returns {Promise>} - */ - fetchInvites(cache = true) { - return this.guild.invites.fetch({ channelId: this.id, cache }); - } - /** * Options used to clone a guild channel. * @typedef {GuildChannelCreateOptions} GuildChannelCloneOptions diff --git a/src/structures/NewsChannel.js b/src/structures/NewsChannel.js index 453141b9c..b5d6f2fc3 100644 --- a/src/structures/NewsChannel.js +++ b/src/structures/NewsChannel.js @@ -1,20 +1,13 @@ 'use strict'; -const TextChannel = require('./TextChannel'); +const BaseGuildTextChannel = require('./BaseGuildTextChannel'); const { Error } = require('../errors'); /** * Represents a guild news channel on Discord. - * @extends {TextChannel} + * @extends {BaseGuildTextChannel} */ -class NewsChannel extends TextChannel { - _patch(data) { - super._patch(data); - - // News channels don't have a rate limit per user, remove it - this.rateLimitPerUser = undefined; - } - +class NewsChannel extends BaseGuildTextChannel { /** * Adds the target to this channel's followers. * @param {GuildChannelResolvable} channel The channel where the webhook should be created diff --git a/src/structures/StageChannel.js b/src/structures/StageChannel.js index 50347da56..bce5e76c7 100644 --- a/src/structures/StageChannel.js +++ b/src/structures/StageChannel.js @@ -37,6 +37,21 @@ class StageChannel extends BaseGuildVoiceChannel { return this.guild.stageInstances.create(this.id, options); } + /** + * Sets a new topic for the guild channel. + * @param {?string} topic The new topic for the guild channel + * @param {string} [reason] Reason for changing the guild channel's topic + * @returns {Promise} + * @example + * // Set a new channel topic + * channel.setTopic('needs more rate limiting') + * .then(newChannel => console.log(`Channel's new topic is ${newChannel.topic}`)) + * .catch(console.error); + */ + setTopic(topic, reason) { + return this.edit({ topic }, reason); + } + /** * Sets the RTC region of the channel. * @name StageChannel#setRTCRegion diff --git a/src/structures/StoreChannel.js b/src/structures/StoreChannel.js index 26aea9306..a5fcc2ab5 100644 --- a/src/structures/StoreChannel.js +++ b/src/structures/StoreChannel.js @@ -29,6 +29,30 @@ class StoreChannel extends GuildChannel { this.nsfw = Boolean(data.nsfw); } } + + /** + * Creates an invite to this guild channel. + * @param {CreateInviteOptions} [options={}] The options for creating the invite + * @returns {Promise} + * @example + * // Create an invite to a channel + * channel.createInvite() + * .then(invite => console.log(`Created an invite with a code of ${invite.code}`)) + * .catch(console.error); + */ + createInvite(options) { + return this.guild.invites.create(this.id, options); + } + + /** + * Fetches a collection of invites to this guild channel. + * Resolves with a collection mapping invites by their codes. + * @param {boolean} [cache=true] Whether or not to cache the fetched invites + * @returns {Promise>} + */ + fetchInvites(cache = true) { + return this.guild.invites.fetch({ channelId: this.id, cache }); + } } module.exports = StoreChannel; diff --git a/src/structures/TextChannel.js b/src/structures/TextChannel.js index 7b0a2df88..2a342fff1 100644 --- a/src/structures/TextChannel.js +++ b/src/structures/TextChannel.js @@ -1,111 +1,26 @@ 'use strict'; -const { Collection } = require('@discordjs/collection'); -const GuildChannel = require('./GuildChannel'); -const Webhook = require('./Webhook'); -const TextBasedChannel = require('./interfaces/TextBasedChannel'); -const MessageManager = require('../managers/MessageManager'); -const ThreadManager = require('../managers/ThreadManager'); -const DataResolver = require('../util/DataResolver'); +const BaseGuildTextChannel = require('./BaseGuildTextChannel'); /** * Represents a guild text channel on Discord. - * @extends {GuildChannel} - * @implements {TextBasedChannel} + * @extends {BaseGuildTextChannel} */ -class TextChannel extends GuildChannel { - /** - * @param {Guild} guild The guild the text channel is part of - * @param {APIChannel} data The data for the text channel - * @param {Client} [client] A safety parameter for the client that instantiated this - */ - constructor(guild, data, client) { - super(guild, data, client); - /** - * A manager of the messages sent to this channel - * @type {MessageManager} - */ - this.messages = new MessageManager(this); - - /** - * A manager of the threads belonging to this channel - * @type {ThreadManager} - */ - this.threads = new ThreadManager(this); - - /** - * If the guild considers this channel NSFW - * @type {boolean} - */ - this.nsfw = Boolean(data.nsfw); - } - +class TextChannel extends BaseGuildTextChannel { _patch(data) { super._patch(data); - if ('topic' in data) { - /** - * The topic of the text channel - * @type {?string} - */ - this.topic = data.topic; - } - - if ('nsfw' in data) { - this.nsfw = Boolean(data.nsfw); - } - - if ('last_message_id' in data) { - /** - * The last message id sent in the channel, if one was sent - * @type {?Snowflake} - */ - this.lastMessageId = data.last_message_id; - } - if ('rate_limit_per_user' in data) { /** * The ratelimit per user for this channel in seconds - * It is not currently possible to set a rate limit per user on a `NewsChannel`. * @type {number} */ this.rateLimitPerUser = data.rate_limit_per_user; } - - if ('last_pin_timestamp' in data) { - /** - * The timestamp when the last pinned message was pinned, if there was one - * @type {?number} - */ - this.lastPinTimestamp = data.last_pin_timestamp ? new Date(data.last_pin_timestamp).getTime() : null; - } - - if ('default_auto_archive_duration' in data) { - /** - * The default auto archive duration for newly created threads in this channel - * @type {?ThreadAutoArchiveDuration} - */ - this.defaultAutoArchiveDuration = data.default_auto_archive_duration; - } - - if ('messages' in data) { - for (const message of data.messages) this.messages._add(message); - } - } - - /** - * Sets the default auto archive duration for all newly created threads in this channel. - * @param {ThreadAutoArchiveDuration} defaultAutoArchiveDuration The new default auto archive duration - * @param {string} [reason] Reason for changing the channel's default auto archive duration - * @returns {Promise} - */ - setDefaultAutoArchiveDuration(defaultAutoArchiveDuration, reason) { - return this.edit({ defaultAutoArchiveDuration }, reason); } /** * Sets the rate limit per user for this channel. - * It is not currently possible to set the rate limit per user on a `NewsChannel`. * @param {number} rateLimitPerUser The new ratelimit in seconds * @param {string} [reason] Reason for changing the channel's ratelimits * @returns {Promise} @@ -113,91 +28,6 @@ class TextChannel extends GuildChannel { setRateLimitPerUser(rateLimitPerUser, reason) { return this.edit({ rateLimitPerUser }, reason); } - - /** - * Sets whether this channel is flagged as NSFW. - * @param {boolean} nsfw Whether the channel should be considered NSFW - * @param {string} [reason] Reason for changing the channel's NSFW flag - * @returns {Promise} - */ - setNSFW(nsfw, reason) { - return this.edit({ nsfw }, reason); - } - - /** - * Sets the type of this channel (only conversion between text and news is supported) - * @param {string} type The new channel type - * @param {string} [reason] Reason for changing the channel's type - * @returns {Promise} - */ - setType(type, reason) { - return this.edit({ type }, reason); - } - - /** - * Fetches all webhooks for the channel. - * @returns {Promise>} - * @example - * // Fetch webhooks - * channel.fetchWebhooks() - * .then(hooks => console.log(`This channel has ${hooks.size} hooks`)) - * .catch(console.error); - */ - async fetchWebhooks() { - const data = await this.client.api.channels[this.id].webhooks.get(); - const hooks = new Collection(); - for (const hook of data) hooks.set(hook.id, new Webhook(this.client, hook)); - return hooks; - } - - /** - * Options used to create a {@link Webhook} for {@link TextChannel} and {@link NewsChannel}. - * @typedef {Object} ChannelWebhookCreateOptions - * @property {BufferResolvable|Base64Resolvable} [avatar] Avatar for the webhook - * @property {string} [reason] Reason for creating the webhook - */ - - /** - * Creates a webhook for the channel. - * @param {string} name The name of the webhook - * @param {ChannelWebhookCreateOptions} [options] Options for creating the webhook - * @returns {Promise} Returns the created Webhook - * @example - * // Create a webhook for the current channel - * channel.createWebhook('Snek', { - * avatar: 'https://i.imgur.com/mI8XcpG.jpg', - * reason: 'Needed a cool new Webhook' - * }) - * .then(console.log) - * .catch(console.error) - */ - async createWebhook(name, { avatar, reason } = {}) { - if (typeof avatar === 'string' && !avatar.startsWith('data:')) { - avatar = await DataResolver.resolveImage(avatar); - } - const data = await this.client.api.channels[this.id].webhooks.post({ - data: { - name, - avatar, - }, - reason, - }); - return new Webhook(this.client, data); - } - - // These are here only for documentation purposes - they are implemented by TextBasedChannel - /* eslint-disable no-empty-function */ - get lastMessage() {} - get lastPinAt() {} - send() {} - sendTyping() {} - createMessageCollector() {} - awaitMessages() {} - createMessageComponentCollector() {} - awaitMessageComponent() {} - bulkDelete() {} } -TextBasedChannel.applyToClass(TextChannel, true); - module.exports = TextChannel; diff --git a/typings/index.d.ts b/typings/index.d.ts index 46d47f0eb..67a9a35fb 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -267,6 +267,27 @@ export class BaseGuildEmoji extends Emoji { public requiresColons: boolean | null; } +export class BaseGuildTextChannel extends TextBasedChannel(GuildChannel) { + public constructor(guild: Guild, data?: RawGuildChannelData, client?: Client, immediatePatch?: boolean); + public defaultAutoArchiveDuration?: ThreadAutoArchiveDuration; + public messages: MessageManager; + public nsfw: boolean; + public threads: ThreadManager; + public topic: string | null; + public createInvite(options?: CreateInviteOptions): Promise; + public createWebhook(name: string, options?: ChannelWebhookCreateOptions): Promise; + public fetchInvites(cache?: boolean): Promise>; + public setDefaultAutoArchiveDuration( + defaultAutoArchiveDuration: ThreadAutoArchiveDuration, + reason?: string, + ): Promise; + public setNSFW(nsfw: boolean, reason?: string): Promise; + public setTopic(topic: string | null, reason?: string): Promise; + public setType(type: Pick, reason?: string): Promise; + public setType(type: Pick, reason?: string): Promise; + public fetchWebhooks(): Promise>; +} + export class BaseGuildVoiceChannel extends GuildChannel { public constructor(guild: Guild, data?: RawGuildChannelData); public readonly members: Collection; @@ -275,7 +296,9 @@ export class BaseGuildVoiceChannel extends GuildChannel { public rtcRegion: string | null; public bitrate: number; public userLimit: number; + public createInvite(options?: CreateInviteOptions): Promise; public setRTCRegion(region: string | null): Promise; + public fetchInvites(cache?: boolean): Promise>; } export class BaseMessageComponent { @@ -746,7 +769,7 @@ export class GuildBan extends Base { } export class GuildChannel extends Channel { - public constructor(guild: Guild, data?: RawGuildChannelData, client?: Client); + public constructor(guild: Guild, data?: RawGuildChannelData, client?: Client, immediatePatch?: boolean); private memberPermissions(member: GuildMember): Readonly; private rolePermissions(role: Role): Readonly; @@ -766,17 +789,14 @@ export class GuildChannel extends Channel { public type: Exclude; public readonly viewable: boolean; public clone(options?: GuildChannelCloneOptions): Promise; - public createInvite(options?: CreateInviteOptions): Promise; public edit(data: ChannelData, reason?: string): Promise; public equals(channel: GuildChannel): boolean; - public fetchInvites(cache?: boolean): Promise>; public lockPermissions(): Promise; public permissionsFor(memberOrRole: GuildMember | Role): Readonly; public permissionsFor(memberOrRole: GuildMemberResolvable | RoleResolvable): Readonly | null; public setName(name: string, reason?: string): Promise; public setParent(channel: CategoryChannelResolvable | null, options?: SetParentOptions): Promise; public setPosition(position: number, options?: SetChannelPositionOptions): Promise; - public setTopic(topic: string | null, reason?: string): Promise; public isText(): this is TextChannel | NewsChannel; } @@ -1349,22 +1369,8 @@ export class MessageSelectMenu extends BaseMessageComponent { public toJSON(): unknown; } -export class NewsChannel extends TextBasedChannel(GuildChannel) { - public constructor(guild: Guild, data?: RawGuildChannelData); - public defaultAutoArchiveDuration?: ThreadAutoArchiveDuration; - public messages: MessageManager; - public nsfw: boolean; - public threads: ThreadManager; - public topic: string | null; +export class NewsChannel extends BaseGuildTextChannel { public type: 'GUILD_NEWS'; - public createWebhook(name: string, options?: ChannelWebhookCreateOptions): Promise; - public setDefaultAutoArchiveDuration( - defaultAutoArchiveDuration: ThreadAutoArchiveDuration, - reason?: string, - ): Promise; - public setNSFW(nsfw: boolean, reason?: string): Promise; - public setType(type: Pick, reason?: string): Promise; - public fetchWebhooks(): Promise>; public addFollower(channel: GuildChannelResolvable, reason?: string): Promise; } @@ -1629,6 +1635,7 @@ export class StageChannel extends BaseGuildVoiceChannel { public type: 'GUILD_STAGE_VOICE'; public readonly stageInstance: StageInstance | null; public createStageInstance(options: StageInstanceCreateOptions): Promise; + public setTopic(topic: string): Promise; } export class StageInstance extends Base { @@ -1692,6 +1699,8 @@ export class StickerPack extends Base { export class StoreChannel extends GuildChannel { public constructor(guild: Guild, data?: RawGuildChannelData, client?: Client); + public createInvite(options?: CreateInviteOptions): Promise; + public fetchInvites(cache?: boolean): Promise>; public nsfw: boolean; public type: 'GUILD_STORE'; } @@ -1729,24 +1738,10 @@ export class TeamMember extends Base { public toString(): UserMention; } -export class TextChannel extends TextBasedChannel(GuildChannel) { - public constructor(guild: Guild, data?: RawGuildChannelData, client?: Client); - public defaultAutoArchiveDuration?: ThreadAutoArchiveDuration; - public messages: MessageManager; - public nsfw: boolean; - public type: 'GUILD_TEXT'; +export class TextChannel extends BaseGuildTextChannel { public rateLimitPerUser: number; - public threads: ThreadManager; - public topic: string | null; - public createWebhook(name: string, options?: ChannelWebhookCreateOptions): Promise; - public setDefaultAutoArchiveDuration( - defaultAutoArchiveDuration: ThreadAutoArchiveDuration, - reason?: string, - ): Promise; - public setNSFW(nsfw: boolean, reason?: string): Promise; + public type: 'GUILD_TEXT'; public setRateLimitPerUser(rateLimitPerUser: number, reason?: string): Promise; - public setType(type: Pick, reason?: string): Promise; - public fetchWebhooks(): Promise>; } export class ThreadChannel extends TextBasedChannel(Channel) {