From b8f94bbbf7a63962ca9dd045b4bf2d09db7cd78a Mon Sep 17 00:00:00 2001 From: TTtie Date: Sun, 7 Jul 2024 01:14:49 +0000 Subject: [PATCH 01/14] feat: support polls Ref: https://github.com/discord/discord-api-docs/commit/df7d3652 --- lib/Client.js | 25 ++++++++++++++++++++ lib/Constants.js | 4 ++++ lib/rest/Endpoints.js | 2 ++ lib/structures/CommandInteraction.js | 2 ++ lib/structures/ComponentInteraction.js | 2 ++ lib/structures/Message.js | 29 ++++++++++++++++++++++++ lib/structures/ModalSubmitInteraction.js | 2 ++ lib/structures/PrivateChannel.js | 1 + lib/structures/TextChannel.js | 1 + lib/structures/TextVoiceChannel.js | 1 + lib/structures/ThreadChannel.js | 1 + 11 files changed, 70 insertions(+) diff --git a/lib/Client.js b/lib/Client.js index 3757f7c0..46b547b3 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -805,6 +805,7 @@ class Client extends EventEmitter { * @arg {String} [content.messageReference.guildID] The guild ID of the referenced message * @arg {String} content.messageReference.messageID The message ID of the referenced message. This cannot reference a system message * @arg {String | Number} [content.nonce] A value that can be used to check if the message was sent + * @arg {Object} [content.poll] A poll object. See [Discord's Documentation](https://discord.com/developers/docs/resources/poll#poll-create-request-object-poll-create-request-object-structure) for object structure * @arg {Array} [content.stickerIDs] An array of IDs corresponding to stickers to send * @arg {Boolean} [content.tts] Set the message TTS flag * @returns {Promise} @@ -1958,6 +1959,16 @@ class Client extends EventEmitter { return this.requestHandler.request("PATCH", Endpoints.WEBHOOK_MESSAGE(webhookID, token, messageID) + (qs ? "?" + qs : ""), false, options, files).then((response) => new Message(response, this)); } + /** + * Immediately ends a poll + * @param {String} channelID The ID of the channel the poll is in + * @param {String} messageID The ID of the message containing the poll + * @returns {Promise} + */ + endPoll(channelID, messageID) { + return this.requestHandler.request("POST", Endpoints.CHANNEL_POLL_EXPIRE(channelID, messageID), true).then((data) => new Message(data, this)); + } + /** * Execute a slack-style webhook * @arg {String} webhookID The ID of the webhook @@ -2615,6 +2626,20 @@ class Client extends EventEmitter { return this.requestHandler.request("GET", Endpoints.CHANNEL_PINS(channelID), true).then((messages) => messages.map((message) => new Message(message, this))); } + /** + * Gets a list of users that voted for an answer in a poll + * @param {String} channelID The ID of the channel the poll is in + * @param {String} messageID The ID of the message containing the poll + * @param {String} answerID The ID of the answer + * @param {Object} [options] Options for fetching the answer list + * @param {String} [options.after] Get users after this user ID + * @param {Number} [options.limit=100] The maximum number of users to get + * @returns {Promise>} + */ + getPollAnswerVoters(channelID, messageID, answerID, options = {}) { + return this.requestHandler.request("GET", Endpoints.CHANNEL_POLL_ANSWERS(channelID, messageID, answerID), true, options).then((data) => data.users.map((user) => new User(user, this))); + } + /** * Get the prune count for a guild * @arg {String} guildID The ID of the guild diff --git a/lib/Constants.js b/lib/Constants.js index 977d3d11..b994e4a3 100644 --- a/lib/Constants.js +++ b/lib/Constants.js @@ -600,6 +600,10 @@ Permissions.allVoice = Permissions.createInstantInvite Permissions.all = Permissions.allGuild | Permissions.allText | Permissions.allVoice; module.exports.Permissions = Permissions; +module.exports.PollTypes = { + DEFAULT: 1 +}; + module.exports.PremiumTiers = { NONE: 0, TIER_1: 1, diff --git a/lib/rest/Endpoints.js b/lib/rest/Endpoints.js index 7b8cf738..864c6c58 100644 --- a/lib/rest/Endpoints.js +++ b/lib/rest/Endpoints.js @@ -26,6 +26,8 @@ module.exports.CHANNEL_MESSAGES = (chanID) module.exports.CHANNEL_PERMISSION = (chanID, overID) => `/channels/${chanID}/permissions/${overID}`; module.exports.CHANNEL_PIN = (chanID, msgID) => `/channels/${chanID}/pins/${msgID}`; module.exports.CHANNEL_PINS = (chanID) => `/channels/${chanID}/pins`; +module.exports.CHANNEL_POLL_ANSWERS = (chanID, msgID, answerID) => `/channels/${chanID}/polls/${msgID}/answers/${answerID}`; +module.exports.CHANNEL_POLL_EXPIRE = (chanID, msgID) => `/channels/${chanID}/polls/${msgID}/expire`; module.exports.CHANNEL_TYPING = (chanID) => `/channels/${chanID}/typing`; module.exports.CHANNEL_WEBHOOKS = (chanID) => `/channels/${chanID}/webhooks`; module.exports.DISCOVERY_CATEGORIES = "/discovery/categories"; diff --git a/lib/structures/CommandInteraction.js b/lib/structures/CommandInteraction.js index fbe911d2..96ebe551 100644 --- a/lib/structures/CommandInteraction.js +++ b/lib/structures/CommandInteraction.js @@ -114,6 +114,7 @@ class CommandInteraction extends Interaction { * @arg {String} [content.content] A content string * @arg {Array} [options.embeds] An array of embed objects. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure * @arg {Number} [content.flags] A number representing the flags to apply. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for a list + * @arg {Object} [content.poll] A poll object. See [Discord's Documentation](https://discord.com/developers/docs/resources/poll#poll-create-request-object-poll-create-request-object-structure) for object structure * @arg {Boolean} [content.tts] Set the message TTS flag * @returns {Promise} */ @@ -148,6 +149,7 @@ class CommandInteraction extends Interaction { * @arg {String} [content.content] A content string * @arg {Array} [content.embeds] An array of embed objects. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure * @arg {Number} [content.flags] A number representing the flags to apply. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for a list + * @arg {Object} [content.poll] A poll object. See [Discord's Documentation](https://discord.com/developers/docs/resources/poll#poll-create-request-object-poll-create-request-object-structure) for object structure * @arg {Boolean} [content.tts] Set the message TTS flag * @returns {Promise} */ diff --git a/lib/structures/ComponentInteraction.js b/lib/structures/ComponentInteraction.js index fcddfa92..d1dd0cf7 100644 --- a/lib/structures/ComponentInteraction.js +++ b/lib/structures/ComponentInteraction.js @@ -103,6 +103,7 @@ class ComponentInteraction extends Interaction { * @arg {String} [content.content] A content string * @arg {Array} [options.embeds] An array of embed objects. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure * @arg {Number} [content.flags] A number representing the flags to apply. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for a list + * @arg {Object} [content.poll] A poll object. See [Discord's Documentation](https://discord.com/developers/docs/resources/poll#poll-create-request-object-poll-create-request-object-structure) for object structure * @arg {Boolean} [content.tts] Set the message TTS flag * @returns {Promise} */ @@ -137,6 +138,7 @@ class ComponentInteraction extends Interaction { * @arg {String} [content.content] A content string * @arg {Array} [content.embeds] An array of embed objects. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#embed-object) for object structure * @arg {Number} [content.flags] A number representing the flags to apply. See [Discord's Documentation](https://discord.com/developers/docs/resources/channel#message-object-message-flags) for a list + * @arg {Object} [content.poll] A poll object. See [Discord's Documentation](https://discord.com/developers/docs/resources/poll#poll-create-request-object-poll-create-request-object-structure) for object structure * @arg {Boolean} [content.tts] Set the message TTS flag * @returns {Promise} */ diff --git a/lib/structures/Message.js b/lib/structures/Message.js index fcdfe81d..78a115cf 100644 --- a/lib/structures/Message.js +++ b/lib/structures/Message.js @@ -483,6 +483,15 @@ class Message extends Base { */ this.position = data.position; } + + if(data.poll !== undefined) { + /** + * The poll data for the message. See [Discord's documentation](https://discord.com/developers/docs/resources/poll#poll-object-poll-object-structure) + * for more information about the structure. + * @type {Object?} + */ + this.poll = data.poll; + } } /** @@ -655,6 +664,14 @@ class Message extends Base { return this.#client.editWebhookMessage.call(this.#client, this.webhookID, token, this.id, options); } + /** + * Immediately ends a poll associated with this message + * @returns {Promise} + */ + endPoll() { + return this.#client.endPoll.call(this.#client, this.channel.id, this.id); + } + /** * Get a list of users who reacted with a specific reaction * @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji) @@ -671,6 +688,18 @@ class Message extends Base { return this.#client.getMessageReaction.call(this.#client, this.channel.id, this.id, reaction, options); } + /** + * Gets a list of users that voted for an answer in a poll + * @param {String} answerID The ID of the answer + * @param {Object} [options] Options for fetching the answer list + * @param {String} [options.after] Get users after this user ID + * @param {Number} [options.limit=100] The maximum number of users to get + * @returns {Promise>} + */ + getPollAnswerVoters(answerID, options) { + return this.#client.getPollAnswerVoters.call(this.#client, this.channel.id, this.id, answerID, options); + } + /** * Pin the message * @returns {Promise} diff --git a/lib/structures/ModalSubmitInteraction.js b/lib/structures/ModalSubmitInteraction.js index 1df60ee9..a8eb904b 100644 --- a/lib/structures/ModalSubmitInteraction.js +++ b/lib/structures/ModalSubmitInteraction.js @@ -48,6 +48,7 @@ class ModalSubmitInteraction extends Interaction { * @arg {String} [content.content] A content string * @arg {Array} [options.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure * @arg {Number} [content.flags] 64 for Ephemeral + * @arg {Object} [content.poll] A poll object. See [Discord's Documentation](https://discord.com/developers/docs/resources/poll#poll-create-request-object-poll-create-request-object-structure) for object structure * @arg {Boolean} [content.tts] Set the message TTS flag * @returns {Promise} */ @@ -82,6 +83,7 @@ class ModalSubmitInteraction extends Interaction { * @arg {String} [content.content] A content string * @arg {Array} [content.embeds] An array of embed objects. See [the official Discord API documentation entry](https://discord.com/developers/docs/resources/channel#embed-object) for object structure * @arg {Boolean} [content.flags] 64 for Ephemeral + * @arg {Object} [content.poll] A poll object. See [Discord's Documentation](https://discord.com/developers/docs/resources/poll#poll-create-request-object-poll-create-request-object-structure) for object structure * @arg {Boolean} [content.tts] Set the message TTS flag * @returns {Promise} */ diff --git a/lib/structures/PrivateChannel.js b/lib/structures/PrivateChannel.js index 33b1b451..27888d5c 100644 --- a/lib/structures/PrivateChannel.js +++ b/lib/structures/PrivateChannel.js @@ -68,6 +68,7 @@ class PrivateChannel extends Channel { * @arg {String} [content.messageReference.guildID] The guild ID of the referenced message * @arg {String} content.messageReference.messageID The message ID of the referenced message. This cannot reference a system message * @arg {String | Number} [content.nonce] A value that can be used to check if the message was sent + * @arg {Object} [content.poll] A poll object. See [Discord's Documentation](https://discord.com/developers/docs/resources/poll#poll-create-request-object-poll-create-request-object-structure) for object structure * @arg {Array} [content.stickerIDs] An array of IDs corresponding to stickers to send * @arg {Boolean} [content.tts] Set the message TTS flag * @returns {Promise} diff --git a/lib/structures/TextChannel.js b/lib/structures/TextChannel.js index 1acc37f9..8999ca36 100644 --- a/lib/structures/TextChannel.js +++ b/lib/structures/TextChannel.js @@ -128,6 +128,7 @@ class TextChannel extends GuildChannel { * @arg {String} [content.messageReference.guildID] The guild ID of the referenced message * @arg {String} content.messageReference.messageID The message ID of the referenced message. This cannot reference a system message * @arg {String | Number} [content.nonce] A value that can be used to check if the message was sent + * @arg {Object} [content.poll] A poll object. See [Discord's Documentation](https://discord.com/developers/docs/resources/poll#poll-create-request-object-poll-create-request-object-structure) for object structure * @arg {Array} [content.stickerIDs] An array of IDs corresponding to stickers to send * @arg {Boolean} [content.tts] Set the message TTS flag * @returns {Promise} diff --git a/lib/structures/TextVoiceChannel.js b/lib/structures/TextVoiceChannel.js index 22991ac0..cefcb67f 100644 --- a/lib/structures/TextVoiceChannel.js +++ b/lib/structures/TextVoiceChannel.js @@ -102,6 +102,7 @@ class TextVoiceChannel extends VoiceChannel { * @arg {String} [content.messageReference.guildID] The guild ID of the referenced message * @arg {String} content.messageReference.messageID The message ID of the referenced message. This cannot reference a system message * @arg {String | Number} [content.nonce] A unique value that can be used to check if the message was sent + * @arg {Object} [content.poll] A poll object. See [Discord's Documentation](https://discord.com/developers/docs/resources/poll#poll-create-request-object-poll-create-request-object-structure) for object structure * @arg {Array} [content.stickerIDs] An array of IDs corresponding to the stickers to send * @arg {Boolean} [content.tts] Set the message TTS flag * @returns {Promise} diff --git a/lib/structures/ThreadChannel.js b/lib/structures/ThreadChannel.js index b6af1567..0a29e918 100644 --- a/lib/structures/ThreadChannel.js +++ b/lib/structures/ThreadChannel.js @@ -120,6 +120,7 @@ class ThreadChannel extends GuildChannel { * @arg {String} [content.messageReference.guildID] The guild ID of the referenced message * @arg {String} content.messageReference.messageID The message ID of the referenced message. This cannot reference a system message * @arg {String | Number} [content.nonce] A value that can be used to check if the message was sent + * @arg {Object} [content.poll] A poll object. See [Discord's Documentation](https://discord.com/developers/docs/resources/poll#poll-create-request-object-poll-create-request-object-structure) for object structure * @arg {Array} [content.stickerIDs] An array of IDs corresponding to stickers to send * @arg {Boolean} [content.tts] Set the message TTS flag * @returns {Promise} From 3f9acbca0bfa018696f8afcf8bf50c139862253c Mon Sep 17 00:00:00 2001 From: TTtie Date: Sun, 7 Jul 2024 22:31:18 +0000 Subject: [PATCH 02/14] feat(Shard): add basic poll WS event processing --- lib/gateway/Shard.js | 48 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/lib/gateway/Shard.js b/lib/gateway/Shard.js index 451096ce..2ad56357 100644 --- a/lib/gateway/Shard.js +++ b/lib/gateway/Shard.js @@ -2312,6 +2312,54 @@ class Shard extends EventEmitter { }); break; } + case "MESSAGE_POLL_VOTE_ADD": { + const channel = this.client.getChannel(packet.d.channel_id); + let message = channel?.messages.get(packet.d.message_id); + const user = this.client.users.get(packet.d.user_id); + if(!message) { + message = { + id: packet.d.message_id, + channel: channel || {id: packet.d.channel_id} + }; + if(packet.d.guild_id) { + message.guildID = packet.d.guild_id; + message.channel.guild ??= {id: packet.d.guild_id}; + } + } + /** + * Fired when someone votes on a poll. If the poll allows multiple selection, this event will fire for each answer + * @event Client#messagePollVoteAdd + * @prop {Message | Object} message The message object. If the message is not cached, this will be an object with `id` and `channel` keys. If the channel is not cached, channel key will be an object with only an id. No other property is guaranteed + * @prop {User | Object} voter The user that voted. If the user is not cached, this will be an object with an `id` key. No other property is guaranteed + * @prop {String} answerID The ID of the answer the user voted for + */ + this.emit("messagePollVoteAdd", message, user ?? {id: packet.d.user_id}, packet.d.answer_id); + break; + } + case "MESSAGE_POLL_VOTE_REMOVE": { + const channel = this.client.getChannel(packet.d.channel_id); + let message = channel?.messages.get(packet.d.message_id); + const user = this.client.users.get(packet.d.user_id); + if(!message) { + message = { + id: packet.d.message_id, + channel: channel || {id: packet.d.channel_id} + }; + if(packet.d.guild_id) { + message.guildID = packet.d.guild_id; + message.channel.guild ??= {id: packet.d.guild_id}; + } + } + /** + * Fired when someone removes their vote on a poll. If the poll allows multiple selection, this event will fire for each answer + * @event Client#messagePollVoteRemove + * @prop {Message | Object} message The message object. If the message is not cached, this will be an object with `id` and `channel` keys. If the channel is not cached, channel key will be an object with only an id. No other property is guaranteed + * @prop {User | Object} voter The user that voted. If the user is not cached, this will be an object with an `id` key. No other property is guaranteed + * @prop {String} answerID The ID of the answer the user voted for + */ + this.emit("messagePollVoteRemove", message, user ?? {id: packet.d.user_id}, packet.d.answer_id); + break; + } default: { /** * Fired when the shard encounters an unknown packet From d8eb63f6cb5baac5b6d0ae02c9e7b84d7708ebfb Mon Sep 17 00:00:00 2001 From: TTtie Date: Thu, 11 Jul 2024 00:14:55 +0000 Subject: [PATCH 03/14] types: add basic poll typings --- index.d.ts | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 97507833..6f83a0a8 100644 --- a/index.d.ts +++ b/index.d.ts @@ -768,9 +768,10 @@ declare namespace Dysnomia { messageCreate: [message: Message]; messageDelete: [message: PossiblyUncachedMessage]; messageDeleteBulk: [messages: PossiblyUncachedMessage[]]; + messagePollVoteAdd: [message: PossiblyUncachedMessage, user: User | Uncached, answerID: string]; + messagePollVoteRemove: [message: PossiblyUncachedMessage, user: User | Uncached, answerID: string]; messageReactionAdd: [message: PossiblyUncachedMessage, emoji: PartialEmoji, reactor: Member | Uncached, isBurst: boolean]; messageReactionRemove: [message: PossiblyUncachedMessage, emoji: PartialEmoji, userID: string, isBurst: boolean]; - messageReactionRemoveAll: [message: PossiblyUncachedMessage]; messageReactionRemoveEmoji: [message: PossiblyUncachedMessage, emoji: PartialEmoji]; messageUpdate: [message: Message, oldMessage: OldMessage | null]; presenceUpdate: [other: Member, oldPresence: Presence | null]; @@ -1362,6 +1363,7 @@ declare namespace Dysnomia { flags?: number; messageReference?: MessageReferenceReply; nonce?: T extends "hasNonce" ? (string | number) : never; + poll?: unknown; // TODO: document poll create object stickerIDs?: string[]; tts?: boolean; } @@ -1466,6 +1468,17 @@ declare namespace Dysnomia { type?: ReactionTypes; } + interface GetPollAnswerVotersOptions { + after?: string; + limit?: number; + type?: ReactionTypes; + } + + interface GetPollAnswerVotersOptions { + after?: string; + limit?: number; + } + interface InteractionButton extends ButtonBase { custom_id: string; style: ButtonStyleNormal; @@ -2324,6 +2337,9 @@ declare namespace Dysnomia { allVoice: 40136803878673n; all: 1829587348619263n; }; + PollTypes: { + DEFAULT: 1; + }; PremiumTiers: { NONE: 0; TIER_1: 1; @@ -2768,6 +2784,7 @@ declare namespace Dysnomia { messageID: string, options: MessageWebhookContent ): Promise>; + endPoll(channelID: string, messageID: string): Promise; emit(event: K, ...args: ClientEvents[K]): boolean; emit(event: string, ...args: any[]): boolean; executeSlackWebhook(webhookID: string, token: string, options: Record & { auth?: boolean; threadID?: string }): Promise; @@ -2818,6 +2835,7 @@ declare namespace Dysnomia { getNitroStickerPacks(): Promise<{ sticker_packs: StickerPack[] }>; getOAuthApplication(): Promise; getPins(channelID: string): Promise; + getPollAnswerVoters(channelID: string, messageID: string, answerID: string, options?: GetPollAnswerVotersOptions): Promise; getPruneCount(guildID: string, options?: GetPruneOptions): Promise; getRESTChannel(channelID: string): Promise; getRESTGuild(guildID: string, withCounts?: boolean): Promise; @@ -3394,6 +3412,7 @@ declare namespace Dysnomia { messageReference: MessageReference | null; nonce?: string | number; pinned: boolean; + poll?: unknown; // TODO: document poll object position?: number; reactions: { [s: string]: { burstColors: string[]; count: number; countDetails: { burst: number; normal: number }; me: boolean; meBurst: boolean } }; referencedMessage?: Message | null; @@ -3413,6 +3432,8 @@ declare namespace Dysnomia { deleteWebhook(token: string): Promise; edit(content: MessageContent): Promise>; editWebhook(token: string, options: MessageWebhookContent): Promise>; + endPoll(): Promise>; + getPollAnswerVoters(answerID: string, options?: GetPollAnswerVotersOptions): Promise; getReaction(reaction: string, options?: GetMessageReactionOptions): Promise; pin(): Promise; removeReaction(reaction: string, userID?: string): Promise; From c74b28d59dcb37cfc229d9d1f033aea6a011c247 Mon Sep 17 00:00:00 2001 From: TTtie Date: Thu, 11 Jul 2024 00:18:24 +0000 Subject: [PATCH 04/14] lint: sort methods correctly --- index.d.ts | 2 +- lib/structures/Message.js | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/index.d.ts b/index.d.ts index 6f83a0a8..13394e82 100644 --- a/index.d.ts +++ b/index.d.ts @@ -2784,9 +2784,9 @@ declare namespace Dysnomia { messageID: string, options: MessageWebhookContent ): Promise>; - endPoll(channelID: string, messageID: string): Promise; emit(event: K, ...args: ClientEvents[K]): boolean; emit(event: string, ...args: any[]): boolean; + endPoll(channelID: string, messageID: string): Promise; executeSlackWebhook(webhookID: string, token: string, options: Record & { auth?: boolean; threadID?: string }): Promise; executeSlackWebhook(webhookID: string, token: string, options: Record & { auth?: boolean; threadID?: string; wait: true }): Promise>; executeWebhook(webhookID: string, token: string, options: WebhookPayload & { wait: true }): Promise>; diff --git a/lib/structures/Message.js b/lib/structures/Message.js index 78a115cf..75e2e3f4 100644 --- a/lib/structures/Message.js +++ b/lib/structures/Message.js @@ -672,6 +672,18 @@ class Message extends Base { return this.#client.endPoll.call(this.#client, this.channel.id, this.id); } + /** + * Gets a list of users that voted for an answer in a poll + * @param {String} answerID The ID of the answer + * @param {Object} [options] Options for fetching the answer list + * @param {String} [options.after] Get users after this user ID + * @param {Number} [options.limit=100] The maximum number of users to get + * @returns {Promise>} + */ + getPollAnswerVoters(answerID, options) { + return this.#client.getPollAnswerVoters.call(this.#client, this.channel.id, this.id, answerID, options); + } + /** * Get a list of users who reacted with a specific reaction * @arg {String} reaction The reaction (Unicode string if Unicode emoji, `emojiName:emojiID` if custom emoji) @@ -688,18 +700,6 @@ class Message extends Base { return this.#client.getMessageReaction.call(this.#client, this.channel.id, this.id, reaction, options); } - /** - * Gets a list of users that voted for an answer in a poll - * @param {String} answerID The ID of the answer - * @param {Object} [options] Options for fetching the answer list - * @param {String} [options.after] Get users after this user ID - * @param {Number} [options.limit=100] The maximum number of users to get - * @returns {Promise>} - */ - getPollAnswerVoters(answerID, options) { - return this.#client.getPollAnswerVoters.call(this.#client, this.channel.id, this.id, answerID, options); - } - /** * Pin the message * @returns {Promise} From 59801b6d117e17c2520f36216aaab43c69c7a3c8 Mon Sep 17 00:00:00 2001 From: TTtie Date: Thu, 18 Jul 2024 12:12:35 +0000 Subject: [PATCH 05/14] fix!: PollTypes -> PollLayoutTypes --- index.d.ts | 2 +- lib/Constants.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/index.d.ts b/index.d.ts index 13394e82..3c669bc5 100644 --- a/index.d.ts +++ b/index.d.ts @@ -2337,7 +2337,7 @@ declare namespace Dysnomia { allVoice: 40136803878673n; all: 1829587348619263n; }; - PollTypes: { + PollLayoutTypes: { DEFAULT: 1; }; PremiumTiers: { diff --git a/lib/Constants.js b/lib/Constants.js index b994e4a3..90f2df3c 100644 --- a/lib/Constants.js +++ b/lib/Constants.js @@ -600,7 +600,7 @@ Permissions.allVoice = Permissions.createInstantInvite Permissions.all = Permissions.allGuild | Permissions.allText | Permissions.allVoice; module.exports.Permissions = Permissions; -module.exports.PollTypes = { +module.exports.PollLayoutTypes = { DEFAULT: 1 }; From a9167ddcf8369f6eef73591d6fbfe32cf7135bef Mon Sep 17 00:00:00 2001 From: TTtie Date: Thu, 18 Jul 2024 12:16:02 +0000 Subject: [PATCH 06/14] types: add typings for poll objects --- index.d.ts | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/index.d.ts b/index.d.ts index 3c669bc5..39c7cdbd 100644 --- a/index.d.ts +++ b/index.d.ts @@ -154,6 +154,7 @@ declare namespace Dysnomia { type MessageActivityTypes = Constants["MessageActivityTypes"][keyof Constants["MessageActivityTypes"]]; type MessageContent = string | AdvancedMessageContent; type MFALevel = Constants["MFALevels"][keyof Constants["MFALevels"]]; + type PollLayoutTypes = Constants["PollLayoutTypes"][keyof Constants["PollLayoutTypes"]]; type PossiblyUncachedMessage = Message | { author?: User | Uncached; channel: TextableChannel | { id: string; guild?: Uncached }; guildID?: string; id: string }; type ReactionTypes = Constants["ReactionTypes"][keyof Constants["ReactionTypes"]]; type SelectMenu = BaseSelectMenu | ChannelSelectMenu | StringSelectMenu | UserSelectMenu | RoleSelectMenu | MentionableSelectMenu; @@ -1363,7 +1364,7 @@ declare namespace Dysnomia { flags?: number; messageReference?: MessageReferenceReply; nonce?: T extends "hasNonce" ? (string | number) : never; - poll?: unknown; // TODO: document poll create object + poll?: NewPoll; stickerIDs?: string[]; tts?: boolean; } @@ -1518,6 +1519,38 @@ declare namespace Dysnomia { messageID: string; failIfNotExists?: boolean; } + interface NewPoll { + question: PollMedia; + answers: PollAnswer[]; + duration?: number; + allow_multiselect?: boolean; + layout_type?: PollLayoutTypes; + } + interface Poll { + question: PollMedia; + answers: PollAnswer[]; + expiry: string | null; + allow_multiselect: boolean; + layout_type: PollLayoutTypes; + results?: PollResults; + } + interface PollAnswer { + answer_id: number; + poll_media: PollMedia; + } + interface PollAnswerCount { + id: number; + count: number; + me_voted: boolean; + } + interface PollMedia { + text?: string; + emoji?: PartialEmoji; + } + interface PollResults { + is_finalized: boolean; + answer_counts: PollAnswerCount[]; + } interface RoleSubscriptionData { isRenewal: boolean; roleSubscriptionListingID: string; @@ -3412,7 +3445,7 @@ declare namespace Dysnomia { messageReference: MessageReference | null; nonce?: string | number; pinned: boolean; - poll?: unknown; // TODO: document poll object + poll?: Poll; position?: number; reactions: { [s: string]: { burstColors: string[]; count: number; countDetails: { burst: number; normal: number }; me: boolean; meBurst: boolean } }; referencedMessage?: Message | null; From 25988fee0c976188d7f6f671c11775e251a85029 Mon Sep 17 00:00:00 2001 From: TTtie Date: Thu, 18 Jul 2024 12:19:43 +0000 Subject: [PATCH 07/14] lint --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 39c7cdbd..f03a4f3f 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1524,7 +1524,7 @@ declare namespace Dysnomia { answers: PollAnswer[]; duration?: number; allow_multiselect?: boolean; - layout_type?: PollLayoutTypes; + layout_type?: PollLayoutTypes; } interface Poll { question: PollMedia; From 1815ed5369410d821e518db6b41abd19edbb71e5 Mon Sep 17 00:00:00 2001 From: TTtie Date: Thu, 18 Jul 2024 12:32:55 +0000 Subject: [PATCH 08/14] fix(types): poll create object doesn't have an answer_id in answers --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index f03a4f3f..c4981c50 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1521,7 +1521,7 @@ declare namespace Dysnomia { } interface NewPoll { question: PollMedia; - answers: PollAnswer[]; + answers: (Omit)[]; duration?: number; allow_multiselect?: boolean; layout_type?: PollLayoutTypes; From cb14836374ae5427185b52b4be5e8ffd0d4dbdf6 Mon Sep 17 00:00:00 2001 From: TTtie Date: Thu, 18 Jul 2024 20:58:10 +0000 Subject: [PATCH 09/14] fix(types): remove invalid `after` option from `GetPollAnswerVotersOptions` --- index.d.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index c4981c50..af2eba6a 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1472,7 +1472,6 @@ declare namespace Dysnomia { interface GetPollAnswerVotersOptions { after?: string; limit?: number; - type?: ReactionTypes; } interface GetPollAnswerVotersOptions { From 58811c5182b8447140ce38022290b9397a825868 Mon Sep 17 00:00:00 2001 From: TTtie Date: Thu, 18 Jul 2024 20:58:38 +0000 Subject: [PATCH 10/14] fix(types): wait, this is actually here twice, for whatever reason --- index.d.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/index.d.ts b/index.d.ts index af2eba6a..b3ebea76 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1474,11 +1474,6 @@ declare namespace Dysnomia { limit?: number; } - interface GetPollAnswerVotersOptions { - after?: string; - limit?: number; - } - interface InteractionButton extends ButtonBase { custom_id: string; style: ButtonStyleNormal; From fa8530f15d043fa70174fccd40b84e3c25a3b313 Mon Sep 17 00:00:00 2001 From: TTtie Date: Thu, 18 Jul 2024 20:59:42 +0000 Subject: [PATCH 11/14] fix(types): fix-up merge --- index.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/index.d.ts b/index.d.ts index b3ebea76..592c910c 100644 --- a/index.d.ts +++ b/index.d.ts @@ -773,6 +773,7 @@ declare namespace Dysnomia { messagePollVoteRemove: [message: PossiblyUncachedMessage, user: User | Uncached, answerID: string]; messageReactionAdd: [message: PossiblyUncachedMessage, emoji: PartialEmoji, reactor: Member | Uncached, isBurst: boolean]; messageReactionRemove: [message: PossiblyUncachedMessage, emoji: PartialEmoji, userID: string, isBurst: boolean]; + messageReactionRemoveAll: [message: PossiblyUncachedMessage]; messageReactionRemoveEmoji: [message: PossiblyUncachedMessage, emoji: PartialEmoji]; messageUpdate: [message: Message, oldMessage: OldMessage | null]; presenceUpdate: [other: Member, oldPresence: Presence | null]; From 78b231937d6989f7e85bc994f4c838b72040983d Mon Sep 17 00:00:00 2001 From: TTtie Date: Fri, 19 Jul 2024 13:59:40 +0000 Subject: [PATCH 12/14] fix(types/docs): answerID is not a string --- index.d.ts | 4 ++-- lib/gateway/Shard.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/index.d.ts b/index.d.ts index 592c910c..efc44ca9 100644 --- a/index.d.ts +++ b/index.d.ts @@ -769,8 +769,8 @@ declare namespace Dysnomia { messageCreate: [message: Message]; messageDelete: [message: PossiblyUncachedMessage]; messageDeleteBulk: [messages: PossiblyUncachedMessage[]]; - messagePollVoteAdd: [message: PossiblyUncachedMessage, user: User | Uncached, answerID: string]; - messagePollVoteRemove: [message: PossiblyUncachedMessage, user: User | Uncached, answerID: string]; + messagePollVoteAdd: [message: PossiblyUncachedMessage, user: User | Uncached, answerID: number]; + messagePollVoteRemove: [message: PossiblyUncachedMessage, user: User | Uncached, answerID: number]; messageReactionAdd: [message: PossiblyUncachedMessage, emoji: PartialEmoji, reactor: Member | Uncached, isBurst: boolean]; messageReactionRemove: [message: PossiblyUncachedMessage, emoji: PartialEmoji, userID: string, isBurst: boolean]; messageReactionRemoveAll: [message: PossiblyUncachedMessage]; diff --git a/lib/gateway/Shard.js b/lib/gateway/Shard.js index 2ad56357..44ad21c6 100644 --- a/lib/gateway/Shard.js +++ b/lib/gateway/Shard.js @@ -2331,7 +2331,7 @@ class Shard extends EventEmitter { * @event Client#messagePollVoteAdd * @prop {Message | Object} message The message object. If the message is not cached, this will be an object with `id` and `channel` keys. If the channel is not cached, channel key will be an object with only an id. No other property is guaranteed * @prop {User | Object} voter The user that voted. If the user is not cached, this will be an object with an `id` key. No other property is guaranteed - * @prop {String} answerID The ID of the answer the user voted for + * @prop {Number} answerID The ID of the answer the user voted for */ this.emit("messagePollVoteAdd", message, user ?? {id: packet.d.user_id}, packet.d.answer_id); break; @@ -2355,7 +2355,7 @@ class Shard extends EventEmitter { * @event Client#messagePollVoteRemove * @prop {Message | Object} message The message object. If the message is not cached, this will be an object with `id` and `channel` keys. If the channel is not cached, channel key will be an object with only an id. No other property is guaranteed * @prop {User | Object} voter The user that voted. If the user is not cached, this will be an object with an `id` key. No other property is guaranteed - * @prop {String} answerID The ID of the answer the user voted for + * @prop {Number} answerID The ID of the answer the user voted for */ this.emit("messagePollVoteRemove", message, user ?? {id: packet.d.user_id}, packet.d.answer_id); break; From 9177f0e637508f24848b9aa510bfff66b0dfdb78 Mon Sep 17 00:00:00 2001 From: TTtie Date: Fri, 19 Jul 2024 14:05:58 +0000 Subject: [PATCH 13/14] fix(docs/types): also use Number for answerID in getPollAnswerVoters --- index.d.ts | 4 ++-- lib/Client.js | 2 +- lib/structures/Message.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/index.d.ts b/index.d.ts index efc44ca9..4a029af0 100644 --- a/index.d.ts +++ b/index.d.ts @@ -2863,7 +2863,7 @@ declare namespace Dysnomia { getNitroStickerPacks(): Promise<{ sticker_packs: StickerPack[] }>; getOAuthApplication(): Promise; getPins(channelID: string): Promise; - getPollAnswerVoters(channelID: string, messageID: string, answerID: string, options?: GetPollAnswerVotersOptions): Promise; + getPollAnswerVoters(channelID: string, messageID: string, answerID: number, options?: GetPollAnswerVotersOptions): Promise; getPruneCount(guildID: string, options?: GetPruneOptions): Promise; getRESTChannel(channelID: string): Promise; getRESTGuild(guildID: string, withCounts?: boolean): Promise; @@ -3461,7 +3461,7 @@ declare namespace Dysnomia { edit(content: MessageContent): Promise>; editWebhook(token: string, options: MessageWebhookContent): Promise>; endPoll(): Promise>; - getPollAnswerVoters(answerID: string, options?: GetPollAnswerVotersOptions): Promise; + getPollAnswerVoters(answerID: number, options?: GetPollAnswerVotersOptions): Promise; getReaction(reaction: string, options?: GetMessageReactionOptions): Promise; pin(): Promise; removeReaction(reaction: string, userID?: string): Promise; diff --git a/lib/Client.js b/lib/Client.js index 46b547b3..c2a0fb6e 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -2630,7 +2630,7 @@ class Client extends EventEmitter { * Gets a list of users that voted for an answer in a poll * @param {String} channelID The ID of the channel the poll is in * @param {String} messageID The ID of the message containing the poll - * @param {String} answerID The ID of the answer + * @param {Number} answerID The ID of the answer * @param {Object} [options] Options for fetching the answer list * @param {String} [options.after] Get users after this user ID * @param {Number} [options.limit=100] The maximum number of users to get diff --git a/lib/structures/Message.js b/lib/structures/Message.js index 75e2e3f4..7c6cb65d 100644 --- a/lib/structures/Message.js +++ b/lib/structures/Message.js @@ -674,7 +674,7 @@ class Message extends Base { /** * Gets a list of users that voted for an answer in a poll - * @param {String} answerID The ID of the answer + * @param {Number} answerID The ID of the answer * @param {Object} [options] Options for fetching the answer list * @param {String} [options.after] Get users after this user ID * @param {Number} [options.limit=100] The maximum number of users to get From ad0c2679569d9d35ea41848f1344352f7f3cb73c Mon Sep 17 00:00:00 2001 From: TTtie Date: Fri, 19 Jul 2024 14:09:34 +0000 Subject: [PATCH 14/14] refactor!: put answerID before user in poll vote events --- index.d.ts | 4 ++-- lib/gateway/Shard.js | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/index.d.ts b/index.d.ts index 4a029af0..07f7d2bc 100644 --- a/index.d.ts +++ b/index.d.ts @@ -769,8 +769,8 @@ declare namespace Dysnomia { messageCreate: [message: Message]; messageDelete: [message: PossiblyUncachedMessage]; messageDeleteBulk: [messages: PossiblyUncachedMessage[]]; - messagePollVoteAdd: [message: PossiblyUncachedMessage, user: User | Uncached, answerID: number]; - messagePollVoteRemove: [message: PossiblyUncachedMessage, user: User | Uncached, answerID: number]; + messagePollVoteAdd: [message: PossiblyUncachedMessage, answerID: number, user: User | Uncached]; + messagePollVoteRemove: [message: PossiblyUncachedMessage, answerID: number, user: User | Uncached]; messageReactionAdd: [message: PossiblyUncachedMessage, emoji: PartialEmoji, reactor: Member | Uncached, isBurst: boolean]; messageReactionRemove: [message: PossiblyUncachedMessage, emoji: PartialEmoji, userID: string, isBurst: boolean]; messageReactionRemoveAll: [message: PossiblyUncachedMessage]; diff --git a/lib/gateway/Shard.js b/lib/gateway/Shard.js index 44ad21c6..b03dffb7 100644 --- a/lib/gateway/Shard.js +++ b/lib/gateway/Shard.js @@ -2330,10 +2330,10 @@ class Shard extends EventEmitter { * Fired when someone votes on a poll. If the poll allows multiple selection, this event will fire for each answer * @event Client#messagePollVoteAdd * @prop {Message | Object} message The message object. If the message is not cached, this will be an object with `id` and `channel` keys. If the channel is not cached, channel key will be an object with only an id. No other property is guaranteed - * @prop {User | Object} voter The user that voted. If the user is not cached, this will be an object with an `id` key. No other property is guaranteed * @prop {Number} answerID The ID of the answer the user voted for + * @prop {User | Object} voter The user that voted. If the user is not cached, this will be an object with an `id` key. No other property is guaranteed */ - this.emit("messagePollVoteAdd", message, user ?? {id: packet.d.user_id}, packet.d.answer_id); + this.emit("messagePollVoteAdd", message, packet.d.answer_id, user ?? {id: packet.d.user_id}); break; } case "MESSAGE_POLL_VOTE_REMOVE": { @@ -2354,10 +2354,10 @@ class Shard extends EventEmitter { * Fired when someone removes their vote on a poll. If the poll allows multiple selection, this event will fire for each answer * @event Client#messagePollVoteRemove * @prop {Message | Object} message The message object. If the message is not cached, this will be an object with `id` and `channel` keys. If the channel is not cached, channel key will be an object with only an id. No other property is guaranteed - * @prop {User | Object} voter The user that voted. If the user is not cached, this will be an object with an `id` key. No other property is guaranteed * @prop {Number} answerID The ID of the answer the user voted for + * @prop {User | Object} voter The user that voted. If the user is not cached, this will be an object with an `id` key. No other property is guaranteed */ - this.emit("messagePollVoteRemove", message, user ?? {id: packet.d.user_id}, packet.d.answer_id); + this.emit("messagePollVoteRemove", message, packet.d.answer_id, user ?? {id: packet.d.user_id}); break; } default: {