From ffdb197f988657100e2a9ff0ca17b759339a1dda Mon Sep 17 00:00:00 2001 From: Jaworek Date: Sat, 25 Feb 2023 16:03:18 +0100 Subject: [PATCH] feat(StageChannel): add messages (#9134) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(StageChannel): add messages * fix: missing implements jsdoc * Apply suggestions from code review Co-authored-by: MateoDeveloper <79017590+Mateo-tem@users.noreply.github.com> * Update packages/discord.js/src/util/Constants.js Co-authored-by: MateoDeveloper <79017590+Mateo-tem@users.noreply.github.com> * feat: use common class * Apply suggestions from code review Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com> * feat: add stage to text based channels + fix webhook.channel typings * fix: some fixes * Update packages/discord.js/src/structures/BaseGuildVoiceChannel.js Co-authored-by: Sugden <28943913+NotSugden@users.noreply.github.com> * Update packages/discord.js/src/structures/VoiceChannel.js Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com> * Update packages/discord.js/src/structures/interfaces/TextBasedChannel.js Co-authored-by: Aura Román * Update packages/discord.js/src/structures/BaseGuildVoiceChannel.js Co-authored-by: space --------- Co-authored-by: MateoDeveloper <79017590+Mateo-tem@users.noreply.github.com> Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com> Co-authored-by: Sugden <28943913+NotSugden@users.noreply.github.com> Co-authored-by: Aura Román Co-authored-by: space Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../src/client/actions/WebhooksUpdate.js | 3 +- .../src/managers/GuildChannelManager.js | 2 +- .../src/structures/BaseGuildVoiceChannel.js | 138 ++++++++++++++-- .../discord.js/src/structures/StageChannel.js | 46 +++++- .../discord.js/src/structures/VoiceChannel.js | 154 +++++------------- packages/discord.js/src/structures/Webhook.js | 2 +- .../structures/interfaces/TextBasedChannel.js | 2 +- packages/discord.js/src/util/Constants.js | 3 +- packages/discord.js/typings/index.d.ts | 39 +++-- packages/discord.js/typings/index.test-d.ts | 7 +- 10 files changed, 238 insertions(+), 158 deletions(-) diff --git a/packages/discord.js/src/client/actions/WebhooksUpdate.js b/packages/discord.js/src/client/actions/WebhooksUpdate.js index ab10cd244..914b03fb2 100644 --- a/packages/discord.js/src/client/actions/WebhooksUpdate.js +++ b/packages/discord.js/src/client/actions/WebhooksUpdate.js @@ -10,7 +10,8 @@ class WebhooksUpdate extends Action { /** * Emitted whenever a channel has its webhooks changed. * @event Client#webhookUpdate - * @param {TextChannel|NewsChannel|VoiceChannel|ForumChannel} channel The channel that had a webhook update + * @param {TextChannel|NewsChannel|VoiceChannel|StageChannel|ForumChannel} channel + * The channel that had a webhook update */ if (channel) client.emit(Events.WebhooksUpdate, channel); } diff --git a/packages/discord.js/src/managers/GuildChannelManager.js b/packages/discord.js/src/managers/GuildChannelManager.js index 3a64c5621..6c27eea8c 100644 --- a/packages/discord.js/src/managers/GuildChannelManager.js +++ b/packages/discord.js/src/managers/GuildChannelManager.js @@ -194,7 +194,7 @@ class GuildChannelManager extends CachedManager { /** * @typedef {ChannelWebhookCreateOptions} WebhookCreateOptions - * @property {TextChannel|NewsChannel|VoiceChannel|ForumChannel|Snowflake} channel + * @property {TextChannel|NewsChannel|VoiceChannel|StageChannel|ForumChannel|Snowflake} channel * The channel to create the webhook for */ diff --git a/packages/discord.js/src/structures/BaseGuildVoiceChannel.js b/packages/discord.js/src/structures/BaseGuildVoiceChannel.js index 8dbebe28c..de80dfeaa 100644 --- a/packages/discord.js/src/structures/BaseGuildVoiceChannel.js +++ b/packages/discord.js/src/structures/BaseGuildVoiceChannel.js @@ -3,12 +3,32 @@ const { Collection } = require('@discordjs/collection'); const { PermissionFlagsBits } = require('discord-api-types/v10'); const GuildChannel = require('./GuildChannel'); +const TextBasedChannel = require('./interfaces/TextBasedChannel'); +const MessageManager = require('../managers/MessageManager'); /** * Represents a voice-based guild channel on Discord. * @extends {GuildChannel} + * @implements {TextBasedChannel} */ class BaseGuildVoiceChannel extends GuildChannel { + 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); + + /** + * If the guild considers this channel NSFW + * @type {boolean} + */ + this.nsfw = Boolean(data.nsfw); + + this._patch(data); + } + _patch(data) { super._patch(data); @@ -35,6 +55,40 @@ class BaseGuildVoiceChannel extends GuildChannel { */ this.userLimit = data.user_limit; } + + if ('video_quality_mode' in data) { + /** + * The camera video quality mode of the channel. + * @type {?VideoQualityMode} + */ + this.videoQualityMode = data.video_quality_mode; + } else { + this.videoQualityMode ??= null; + } + + 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 ('messages' in data) { + for (const message of data.messages) this.messages._add(message); + } + + if ('rate_limit_per_user' in data) { + /** + * The rate limit per user (slowmode) for this channel in seconds + * @type {number} + */ + this.rateLimitPerUser = data.rate_limit_per_user; + } + + if ('nsfw' in data) { + this.nsfw = data.nsfw; + } } /** @@ -80,6 +134,44 @@ class BaseGuildVoiceChannel extends GuildChannel { ); } + /** + * Creates an invite to this guild channel. + * @param {InviteCreateOptions} [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. + * @param {boolean} [cache=true] Whether to cache the fetched invites + * @returns {Promise>} + */ + fetchInvites(cache = true) { + return this.guild.invites.fetch({ channelId: this.id, cache }); + } + + /** + * Sets the bitrate of the channel. + * @param {number} bitrate The new bitrate + * @param {string} [reason] Reason for changing the channel's bitrate + * @returns {Promise} + * @example + * // Set the bitrate of a voice channel + * channel.setBitrate(48_000) + * .then(channel => console.log(`Set bitrate to ${channel.bitrate}bps for ${channel.name}`)) + * .catch(console.error); + */ + setBitrate(bitrate, reason) { + return this.edit({ bitrate, reason }); + } + /** * Sets the RTC region of the channel. * @param {?string} rtcRegion The new region of the channel. Set to `null` to remove a specific region for the channel @@ -97,28 +189,46 @@ class BaseGuildVoiceChannel extends GuildChannel { } /** - * Creates an invite to this guild channel. - * @param {InviteCreateOptions} [options={}] The options for creating the invite - * @returns {Promise} + * Sets the user limit of the channel. + * @param {number} userLimit The new user limit + * @param {string} [reason] Reason for changing the user limit + * @returns {Promise} * @example - * // Create an invite to a channel - * channel.createInvite() - * .then(invite => console.log(`Created an invite with a code of ${invite.code}`)) + * // Set the user limit of a voice channel + * channel.setUserLimit(42) + * .then(channel => console.log(`Set user limit to ${channel.userLimit} for ${channel.name}`)) * .catch(console.error); */ - createInvite(options) { - return this.guild.invites.create(this.id, options); + setUserLimit(userLimit, reason) { + return this.edit({ userLimit, reason }); } /** - * 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>} + * Sets the camera video quality mode of the channel. + * @param {VideoQualityMode} videoQualityMode The new camera video quality mode. + * @param {string} [reason] Reason for changing the camera video quality mode. + * @returns {Promise} */ - fetchInvites(cache = true) { - return this.guild.invites.fetch({ channelId: this.id, cache }); + setVideoQualityMode(videoQualityMode, reason) { + return this.edit({ videoQualityMode, reason }); } + + // These are here only for documentation purposes - they are implemented by TextBasedChannel + /* eslint-disable no-empty-function */ + get lastMessage() {} + send() {} + sendTyping() {} + createMessageCollector() {} + awaitMessages() {} + createMessageComponentCollector() {} + awaitMessageComponent() {} + bulkDelete() {} + fetchWebhooks() {} + createWebhook() {} + setRateLimitPerUser() {} + setNSFW() {} } +TextBasedChannel.applyToClass(BaseGuildVoiceChannel, true, ['lastPinAt']); + module.exports = BaseGuildVoiceChannel; diff --git a/packages/discord.js/src/structures/StageChannel.js b/packages/discord.js/src/structures/StageChannel.js index 0f399c3b1..26614895e 100644 --- a/packages/discord.js/src/structures/StageChannel.js +++ b/packages/discord.js/src/structures/StageChannel.js @@ -41,11 +41,11 @@ class StageChannel extends BaseGuildVoiceChannel { * 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} + * @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}`)) + * stageChannel.setTopic('needs more rate limiting') + * .then(channel => console.log(`Channel's new topic is ${channel.topic}`)) * .catch(console.error); */ setTopic(topic, reason) { @@ -53,6 +53,21 @@ class StageChannel extends BaseGuildVoiceChannel { } } +/** + * Sets the bitrate of the channel. + * @method setBitrate + * @memberof StageChannel + * @instance + * @param {number} bitrate The new bitrate + * @param {string} [reason] Reason for changing the channel's bitrate + * @returns {Promise} + * @example + * // Set the bitrate of a voice channel + * stageChannel.setBitrate(48_000) + * .then(channel => console.log(`Set bitrate to ${channel.bitrate}bps for ${channel.name}`)) + * .catch(console.error); + */ + /** * Sets the RTC region of the channel. * @method setRTCRegion @@ -69,4 +84,29 @@ class StageChannel extends BaseGuildVoiceChannel { * stageChannel.setRTCRegion(null, 'We want to let Discord decide.'); */ +/** + * Sets the user limit of the channel. + * @method setUserLimit + * @memberof StageChannel + * @instance + * @param {number} userLimit The new user limit + * @param {string} [reason] Reason for changing the user limit + * @returns {Promise} + * @example + * // Set the user limit of a voice channel + * stageChannel.setUserLimit(42) + * .then(channel => console.log(`Set user limit to ${channel.userLimit} for ${channel.name}`)) + * .catch(console.error); + */ + +/** + * Sets the camera video quality mode of the channel. + * @method setVideoQualityMode + * @memberof StageChannel + * @instance + * @param {VideoQualityMode} videoQualityMode The new camera video quality mode. + * @param {string} [reason] Reason for changing the camera video quality mode. + * @returns {Promise} + */ + module.exports = StageChannel; diff --git a/packages/discord.js/src/structures/VoiceChannel.js b/packages/discord.js/src/structures/VoiceChannel.js index 1bfc5dae6..d4f33ca12 100644 --- a/packages/discord.js/src/structures/VoiceChannel.js +++ b/packages/discord.js/src/structures/VoiceChannel.js @@ -2,71 +2,12 @@ const { PermissionFlagsBits } = require('discord-api-types/v10'); const BaseGuildVoiceChannel = require('./BaseGuildVoiceChannel'); -const TextBasedChannel = require('./interfaces/TextBasedChannel'); -const MessageManager = require('../managers/MessageManager'); /** * Represents a guild voice channel on Discord. * @extends {BaseGuildVoiceChannel} - * @implements {TextBasedChannel} */ class VoiceChannel extends BaseGuildVoiceChannel { - 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); - - /** - * If the guild considers this channel NSFW - * @type {boolean} - */ - this.nsfw = Boolean(data.nsfw); - - this._patch(data); - } - - _patch(data) { - super._patch(data); - - if ('video_quality_mode' in data) { - /** - * The camera video quality mode of the channel. - * @type {?VideoQualityMode} - */ - this.videoQualityMode = data.video_quality_mode; - } else { - this.videoQualityMode ??= null; - } - - 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 ('messages' in data) { - for (const message of data.messages) this.messages._add(message); - } - - if ('rate_limit_per_user' in data) { - /** - * The rate limit per user (slowmode) for this channel in seconds - * @type {number} - */ - this.rateLimitPerUser = data.rate_limit_per_user; - } - - if ('nsfw' in data) { - this.nsfw = Boolean(data.nsfw); - } - } - /** * Whether the channel is joinable by the client user * @type {boolean} @@ -94,64 +35,22 @@ class VoiceChannel extends BaseGuildVoiceChannel { permissions.has(PermissionFlagsBits.Speak, false) ); } - - /** - * Sets the bitrate of the channel. - * @param {number} bitrate The new bitrate - * @param {string} [reason] Reason for changing the channel's bitrate - * @returns {Promise} - * @example - * // Set the bitrate of a voice channel - * voiceChannel.setBitrate(48_000) - * .then(vc => console.log(`Set bitrate to ${vc.bitrate}bps for ${vc.name}`)) - * .catch(console.error); - */ - setBitrate(bitrate, reason) { - return this.edit({ bitrate, reason }); - } - - /** - * Sets the user limit of the channel. - * @param {number} userLimit The new user limit - * @param {string} [reason] Reason for changing the user limit - * @returns {Promise} - * @example - * // Set the user limit of a voice channel - * voiceChannel.setUserLimit(42) - * .then(vc => console.log(`Set user limit to ${vc.userLimit} for ${vc.name}`)) - * .catch(console.error); - */ - setUserLimit(userLimit, reason) { - return this.edit({ userLimit, reason }); - } - - /** - * Sets the camera video quality mode of the channel. - * @param {VideoQualityMode} videoQualityMode The new camera video quality mode. - * @param {string} [reason] Reason for changing the camera video quality mode. - * @returns {Promise} - */ - setVideoQualityMode(videoQualityMode, reason) { - return this.edit({ videoQualityMode, reason }); - } - - // These are here only for documentation purposes - they are implemented by TextBasedChannel - /* eslint-disable no-empty-function */ - get lastMessage() {} - send() {} - sendTyping() {} - createMessageCollector() {} - awaitMessages() {} - createMessageComponentCollector() {} - awaitMessageComponent() {} - bulkDelete() {} - fetchWebhooks() {} - createWebhook() {} - setRateLimitPerUser() {} - setNSFW() {} } -TextBasedChannel.applyToClass(VoiceChannel, true, ['lastPinAt']); +/** + * Sets the bitrate of the channel. + * @method setBitrate + * @memberof VoiceChannel + * @instance + * @param {number} bitrate The new bitrate + * @param {string} [reason] Reason for changing the channel's bitrate + * @returns {Promise} + * @example + * // Set the bitrate of a voice channel + * voiceChannel.setBitrate(48_000) + * .then(channel => console.log(`Set bitrate to ${channel.bitrate}bps for ${channel.name}`)) + * .catch(console.error); + */ /** * Sets the RTC region of the channel. @@ -169,4 +68,29 @@ TextBasedChannel.applyToClass(VoiceChannel, true, ['lastPinAt']); * voiceChannel.setRTCRegion(null, 'We want to let Discord decide.'); */ +/** + * Sets the user limit of the channel. + * @method setUserLimit + * @memberof VoiceChannel + * @instance + * @param {number} userLimit The new user limit + * @param {string} [reason] Reason for changing the user limit + * @returns {Promise} + * @example + * // Set the user limit of a voice channel + * voiceChannel.setUserLimit(42) + * .then(channel => console.log(`Set user limit to ${channel.userLimit} for ${channel.name}`)) + * .catch(console.error); + */ + +/** + * Sets the camera video quality mode of the channel. + * @method setVideoQualityMode + * @memberof VoiceChannel + * @instance + * @param {VideoQualityMode} videoQualityMode The new camera video quality mode. + * @param {string} [reason] Reason for changing the camera video quality mode. + * @returns {Promise} + */ + module.exports = VoiceChannel; diff --git a/packages/discord.js/src/structures/Webhook.js b/packages/discord.js/src/structures/Webhook.js index 643938ebc..efc02218e 100644 --- a/packages/discord.js/src/structures/Webhook.js +++ b/packages/discord.js/src/structures/Webhook.js @@ -147,7 +147,7 @@ class Webhook { /** * The channel the webhook belongs to - * @type {?(TextChannel|VoiceChannel|NewsChannel|ForumChannel)} + * @type {?(TextChannel|VoiceChannel|StageChannel|NewsChannel|ForumChannel)} * @readonly */ get channel() { diff --git a/packages/discord.js/src/structures/interfaces/TextBasedChannel.js b/packages/discord.js/src/structures/interfaces/TextBasedChannel.js index 8de15805b..db7542b26 100644 --- a/packages/discord.js/src/structures/interfaces/TextBasedChannel.js +++ b/packages/discord.js/src/structures/interfaces/TextBasedChannel.js @@ -346,7 +346,7 @@ class TextBasedChannel { } /** - * Options used to create a {@link Webhook} in a {@link TextChannel} or a {@link NewsChannel}. + * Options used to create a {@link Webhook}. * @typedef {Object} ChannelWebhookCreateOptions * @property {string} name The name of the webhook * @property {?(BufferResolvable|Base64Resolvable)} [avatar] Avatar for the webhook diff --git a/packages/discord.js/src/util/Constants.js b/packages/discord.js/src/util/Constants.js index 7079c6038..6ad30d300 100644 --- a/packages/discord.js/src/util/Constants.js +++ b/packages/discord.js/src/util/Constants.js @@ -66,7 +66,8 @@ exports.NonSystemMessageTypes = [ * * NewsChannel * * ThreadChannel * * VoiceChannel - * @typedef {TextChannel|NewsChannel|ThreadChannel|VoiceChannel} GuildTextBasedChannel + * * StageChannel + * @typedef {TextChannel|NewsChannel|ThreadChannel|VoiceChannel|StageChannel} GuildTextBasedChannel */ /** diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 75f1d9bc2..80efc3e7c 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -633,17 +633,26 @@ export class BaseGuildTextChannel extends TextBasedChannelMixin(GuildChannel, tr public setType(type: ChannelType.GuildAnnouncement, reason?: string): Promise; } -export class BaseGuildVoiceChannel extends GuildChannel { +export class BaseGuildVoiceChannel extends TextBasedChannelMixin(GuildChannel, true, [ + 'lastPinTimestamp', + 'lastPinAt', +]) { public constructor(guild: Guild, data?: RawGuildChannelData); - public get members(): Collection; + public bitrate: number; public get full(): boolean; public get joinable(): boolean; + public get members(): Collection; + public nsfw: boolean; + public rateLimitPerUser: number | null; public rtcRegion: string | null; - public bitrate: number; public userLimit: number; + public videoQualityMode: VideoQualityMode | null; public createInvite(options?: InviteCreateOptions): Promise; - public setRTCRegion(rtcRegion: string | null, reason?: string): Promise; public fetchInvites(cache?: boolean): Promise>; + public setBitrate(bitrate: number, reason?: string): Promise; + public setRTCRegion(rtcRegion: string | null, reason?: string): Promise; + public setUserLimit(userLimit: number, reason?: string): Promise; + public setVideoQualityMode(videoQualityMode: VideoQualityMode, reason?: string): Promise; } export type EnumLike = Record; @@ -2726,9 +2735,9 @@ export { } from '@sapphire/snowflake'; export class StageChannel extends BaseGuildVoiceChannel { + public get stageInstance(): StageInstance | null; public topic: string | null; public type: ChannelType.GuildStageVoice; - public get stageInstance(): StageInstance | null; public createStageInstance(options: StageInstanceCreateOptions): Promise; public setTopic(topic: string): Promise; } @@ -3179,18 +3188,9 @@ export type ComponentData = | ModalActionRowComponentData | ActionRowData; -export class VoiceChannel extends TextBasedChannelMixin(BaseGuildVoiceChannel, true, [ - 'lastPinTimestamp', - 'lastPinAt', -]) { - public videoQualityMode: VideoQualityMode | null; +export class VoiceChannel extends BaseGuildVoiceChannel { public get speakable(): boolean; public type: ChannelType.GuildVoice; - public nsfw: boolean; - public rateLimitPerUser: number | null; - public setBitrate(bitrate: number, reason?: string): Promise; - public setUserLimit(userLimit: number, reason?: string): Promise; - public setVideoQualityMode(videoQualityMode: VideoQualityMode, reason?: string): Promise; } export class VoiceRegion { @@ -3245,7 +3245,7 @@ export class Webhook extends WebhookMixin() { public token: string | null; public type: WebhookType; public applicationId: Snowflake | null; - public get channel(): TextChannel | VoiceChannel | NewsChannel | ForumChannel | null; + public get channel(): TextChannel | VoiceChannel | NewsChannel | ForumChannel | StageChannel | null; public isUserCreated(): this is this & { type: WebhookType.Incoming; applicationId: null; @@ -4721,7 +4721,7 @@ export interface ChannelWebhookCreateOptions { } export interface WebhookCreateOptions extends ChannelWebhookCreateOptions { - channel: TextChannel | NewsChannel | VoiceChannel | ForumChannel | Snowflake; + channel: TextChannel | NewsChannel | VoiceChannel | StageChannel | ForumChannel | Snowflake; } export interface ClientEvents { @@ -6196,8 +6196,7 @@ export type Channel = export type TextBasedChannel = Exclude< Extract, - // TODO: Remove stage channel upon implementation of text-in-stage. - PartialGroupDMChannel | ForumChannel | StageChannel + PartialGroupDMChannel | ForumChannel >; export type TextBasedChannelTypes = TextBasedChannel['type']; @@ -6279,7 +6278,7 @@ export type WebhookClientOptions = Pick(TextBasedChannel); expectType< - ChannelType.GuildText | ChannelType.DM | ChannelType.GuildAnnouncement | ChannelType.GuildVoice | ThreadChannelType + | ChannelType.GuildText + | ChannelType.DM + | ChannelType.GuildAnnouncement + | ChannelType.GuildVoice + | ChannelType.GuildStageVoice + | ThreadChannelType >(TextBasedChannelTypes); expectType(VoiceBasedChannel); expectType(GuildBasedChannel);