feat(bot,rest,types): Add polls support (#3542)

* Add polls support

* Add default for limit on GetPollAnswerVotes

* Apply code rewiew suggestion

Co-authored-by: LTS20050703 <lts20050703@gmail.com>

---------

Co-authored-by: LTS20050703 <lts20050703@gmail.com>
This commit is contained in:
Fleny
2024-04-28 13:42:19 +02:00
committed by GitHub
parent 75332eecda
commit 6ad4e1d2e8
17 changed files with 443 additions and 1 deletions

View File

@@ -13,7 +13,7 @@ import type { AutoModerationActionExecution } from './transformers/automodAction
import type { AutoModerationRule } from './transformers/automodRule.js'
import type { Channel } from './transformers/channel.js'
import type { Emoji } from './transformers/emoji.js'
import { type Entitlement } from './transformers/entitlement.js'
import type { Entitlement } from './transformers/entitlement.js'
import type { Guild } from './transformers/guild.js'
import type { Integration } from './transformers/integration.js'
import type { Interaction } from './transformers/interaction.js'
@@ -247,4 +247,6 @@ export interface EventHandlers {
entitlementCreate: (entitlement: Entitlement) => unknown
entitlementUpdate: (entitlement: Entitlement) => unknown
entitlementDelete: (entitlement: Entitlement) => unknown
messagePollVoteAdd: (payload: { userId: bigint; channelId: bigint; messageId: bigint; guildId?: bigint; answerId: number }) => unknown
messagePollVoteRemove: (payload: { userId: bigint; channelId: bigint; messageId: bigint; guildId?: bigint; answerId: number }) => unknown
}

View File

@@ -69,6 +69,8 @@ export function createBotGatewayHandlers(
ENTITLEMENT_CREATE: options.ENTITLEMENT_CREATE ?? handlers.handleEntitlementCreate,
ENTITLEMENT_UPDATE: options.ENTITLEMENT_UPDATE ?? handlers.handleEntitlementUpdate,
ENTITLEMENT_DELETE: options.ENTITLEMENT_DELETE ?? handlers.handleEntitlementDelete,
MESSAGE_POLL_VOTE_ADD: options.MESSAGE_POLL_VOTE_ADD ?? handlers.handleMessagePollVoteAdd,
MESSAGE_POLL_VOTE_REMOVE: options.MESSAGE_POLL_VOTE_REMOVE ?? handlers.handleMessagePollVoteRemove,
}
}

View File

@@ -8,6 +8,7 @@ export * from './invites/index.js'
export * from './members/index.js'
export * from './messages/index.js'
export * from './misc/index.js'
export * from './poll/index.js'
export * from './roles/index.js'
export * from './voice/index.js'
export * from './webhooks/index.js'

View File

@@ -0,0 +1,16 @@
import type { DiscordGatewayPayload, DiscordPollVoteAdd } from '@discordeno/types'
import type { Bot } from '../../index.js'
export async function handleMessagePollVoteAdd(bot: Bot, data: DiscordGatewayPayload): Promise<void> {
if (!bot.events.messagePollVoteAdd) return
const payload = data.d as DiscordPollVoteAdd
bot.events.messagePollVoteAdd({
userId: bot.transformers.snowflake(payload.user_id),
channelId: bot.transformers.snowflake(payload.channel_id),
messageId: bot.transformers.snowflake(payload.message_id),
guildId: payload.guild_id ? bot.transformers.snowflake(payload.guild_id) : undefined,
answerId: payload.answer_id,
})
}

View File

@@ -0,0 +1,16 @@
import type { DiscordGatewayPayload, DiscordPollVoteRemove } from '@discordeno/types'
import type { Bot } from '../../index.js'
export async function handleMessagePollVoteRemove(bot: Bot, data: DiscordGatewayPayload): Promise<void> {
if (!bot.events.messagePollVoteRemove) return
const payload = data.d as DiscordPollVoteRemove
bot.events.messagePollVoteRemove({
userId: bot.transformers.snowflake(payload.user_id),
channelId: bot.transformers.snowflake(payload.channel_id),
messageId: bot.transformers.snowflake(payload.message_id),
guildId: payload.guild_id ? bot.transformers.snowflake(payload.guild_id) : undefined,
answerId: payload.answer_id,
})
}

View File

@@ -0,0 +1,2 @@
export * from './MESSAGE_POLL_VOTE_ADD.js'
export * from './MESSAGE_POLL_VOTE_REMOVE.js'

View File

@@ -31,6 +31,8 @@ import type {
DiscordInviteStageInstance,
DiscordMember,
DiscordMessage,
DiscordPoll,
DiscordPollMedia,
DiscordPresenceUpdate,
DiscordRole,
DiscordScheduledEvent,
@@ -85,6 +87,7 @@ import { transformInvite, type Invite } from './transformers/invite.js'
import { transformMember, type Member } from './transformers/member.js'
import { transformMessage, type Message } from './transformers/message.js'
import { transformGuildOnboarding, type GuildOnboarding } from './transformers/onboarding.js'
import { transformPoll, transformPollMedia, type Poll, type PollMedia } from './transformers/poll.js'
import { transformPresence, type PresenceUpdate } from './transformers/presence.js'
import { transformAllowedMentionsToDiscordAllowedMentions } from './transformers/reverse/allowedMentions.js'
import { transformCreateApplicationCommandToDiscordCreateApplicationCommand } from './transformers/reverse/createApplicationCommand.js'
@@ -165,6 +168,8 @@ export interface Transformers {
guildOnboarding: (bot: Bot, payload: DiscordGuildOnboarding, onboarding: GuildOnboarding) => any
entitlement: (bot: Bot, payload: DiscordEntitlement, entitlement: Entitlement) => any
sku: (bot: Bot, payload: DiscordSku, sku: Sku) => any
poll: (bot: Bot, payload: DiscordPoll, poll: Poll) => any
pollMedia: (bot: Bot, payload: DiscordPollMedia, pollMedia: PollMedia) => any
}
desiredProperties: {
attachment: {
@@ -506,6 +511,28 @@ export interface Transformers {
sessionId: boolean
userId: boolean
}
poll: {
question: boolean
answers: {
answerId: boolean
pollMedia: boolean
}
expiry: boolean
allowMultiselect: boolean
layoutType: boolean
results: {
isFinalized: boolean
answerCounts: {
id: boolean
count: boolean
meVoted: boolean
}
}
}
pollMedia: {
text: boolean
emoji: boolean
}
}
reverse: {
allowedMentions: (bot: Bot, payload: AllowedMentions) => DiscordAllowedMentions
@@ -569,6 +596,8 @@ export interface Transformers {
guildOnboarding: (bot: Bot, payload: DiscordGuildOnboarding) => GuildOnboarding
entitlement: (bot: Bot, payload: DiscordEntitlement) => Entitlement
sku: (bot: Bot, payload: DiscordSku) => Sku
poll: (bot: Bot, payload: DiscordPoll) => Poll
pollMedia: (bot: Bot, payload: DiscordPollMedia) => PollMedia
}
export interface CreateTransformerOptions {
@@ -719,6 +748,12 @@ export function createTransformers(options: Partial<Transformers>, opts?: Create
sku(bot, payload, sku) {
return sku
},
poll(bot, payload, poll) {
return poll
},
pollMedia(bot, payload, pollMedia) {
return pollMedia
},
},
desiredProperties: {
attachment: {
@@ -1060,6 +1095,28 @@ export function createTransformers(options: Partial<Transformers>, opts?: Create
sessionId: opts?.defaultDesiredPropertiesValue ?? false,
userId: opts?.defaultDesiredPropertiesValue ?? false,
},
poll: {
question: opts?.defaultDesiredPropertiesValue ?? false,
answers: {
answerId: opts?.defaultDesiredPropertiesValue ?? false,
pollMedia: opts?.defaultDesiredPropertiesValue ?? false,
},
expiry: opts?.defaultDesiredPropertiesValue ?? false,
layoutType: opts?.defaultDesiredPropertiesValue ?? false,
allowMultiselect: opts?.defaultDesiredPropertiesValue ?? false,
results: {
isFinalized: opts?.defaultDesiredPropertiesValue ?? false,
answerCounts: {
id: opts?.defaultDesiredPropertiesValue ?? false,
count: opts?.defaultDesiredPropertiesValue ?? false,
meVoted: opts?.defaultDesiredPropertiesValue ?? false,
},
},
},
pollMedia: {
text: opts?.defaultDesiredPropertiesValue ?? false,
emoji: opts?.defaultDesiredPropertiesValue ?? false,
},
},
reverse: {
allowedMentions: options.reverse?.allowedMentions ?? transformAllowedMentionsToDiscordAllowedMentions,
@@ -1123,5 +1180,7 @@ export function createTransformers(options: Partial<Transformers>, opts?: Create
guildOnboarding: options.guildOnboarding ?? transformGuildOnboarding,
entitlement: options.entitlement ?? transformEntitlement,
sku: options.sku ?? transformSku,
poll: options.poll ?? transformPoll,
pollMedia: options.pollMedia ?? transformPollMedia,
}
}

View File

@@ -0,0 +1,105 @@
import type { DiscordEmoji, DiscordPoll, DiscordPollLayoutType, DiscordPollMedia } from '@discordeno/types'
import type { Bot, Emoji } from '../index.js'
export function transformPoll(bot: Bot, payload: DiscordPoll): Poll {
const props = bot.transformers.desiredProperties.poll
const poll = {} as Poll
if (props.question && payload.question) poll.question = bot.transformers.pollMedia(bot, payload.question)
if (props.answers && payload.answers)
poll.answers = payload.answers.map((x) => ({ answerId: x.answer_id, pollMedia: bot.transformers.pollMedia(bot, x.poll_media) }))
if (props.expiry && payload.expiry) poll.expiry = Date.parse(payload.expiry)
if (props.allowMultiselect && payload.allow_multiselect) poll.allowMultiselect = payload.allow_multiselect
if (props.layoutType) poll.layoutType = payload.layout_type
if (props.results && payload.results) {
poll.results = {} as PollResult
if (props.results.isFinalized && payload.results.is_finalized) poll.results.isFinalized = payload.results.is_finalized
if (props.results.answerCounts && payload.results.answer_counts)
poll.results.answerCounts = payload.results.answer_counts.map((x) => ({ id: x.id, count: x.count, meVoted: x.me_voted }))
}
return bot.transformers.customizers.poll(bot, payload, poll)
}
export function transformPollMedia(bot: Bot, payload: DiscordPollMedia): PollMedia {
const props = bot.transformers.desiredProperties.pollMedia
const pollMedia = {} as PollMedia
if (props.text && payload.text) pollMedia.text = payload.text
if (props.emoji && payload.emoji) pollMedia.emoji = bot.transformers.emoji(bot, payload.emoji as DiscordEmoji)
return bot.transformers.customizers.pollMedia(bot, payload, pollMedia)
}
export interface Poll {
/** The question of the poll. Only `text` is supported. */
question: PollMedia
/** Each of the answers available in the poll. There is a maximum of 10 answers per poll. */
answers: PollAnswer[]
/**
* The time when the poll ends.
*
* @remarks
* `expiry` is marked as nullable to support non-expiring polls in the future, but all polls have an expiry currently.
*/
expiry: number | null
/** Whether a user can select multiple answers */
allowMultiselect: boolean
/** The layout type of the poll */
layoutType: DiscordPollLayoutType
/**
* The results of the poll
*
* @remarks
* This value will not be sent by discord under specific conditions where they don't fetch them on their backend. When this value is missing it should be interpreted as "Unknown results" and not as "No results"
* The results may not be totally accurate while the poll has not ended. When it ends discord will re-calculate all the results and set {@link DiscordPollResult.is_finalized} to true
*/
results?: PollResult
}
export interface PollMedia {
/**
* The text of the field
*
* @remarks
* `text` should always be non-null for both questions and answers, but this is subject to changes.
* The maximum length of `text` is 300 for the question, and 55 for any answer.
*/
text?: string
/**
* The emoji of the field
*
* @remarks
* When creating a poll answer with an emoji, one only needs to send either the `id` (custom emoji) or `name` (default emoji) as the only field.
*/
emoji?: Partial<Emoji>
}
export interface PollAnswer {
/**
* The id of the answer
*
* @remarks
* This id labels each answer. It starts at 1 and goes up sequentially. Discord recommend against depending on this sequence as it is an implementation detail.
*/
answerId: number
/** The data of the answer */
pollMedia: PollMedia
}
export interface PollResult {
/** Whether the votes have been precisely counted */
isFinalized: boolean
/** The counts for each answer */
answerCounts: PollAnswerCount[]
}
export interface PollAnswerCount {
/** The {@link PollAnswer.answerId | answerId} */
id: number
/** The number of votes for this answer */
count: number
/** Whether the current user voted for this answer */
meVoted: boolean
}

View File

@@ -207,6 +207,8 @@ export interface BotGatewayHandlerOptions {
ENTITLEMENT_CREATE: typeof handlers.handleEntitlementCreate
ENTITLEMENT_UPDATE: typeof handlers.handleEntitlementUpdate
ENTITLEMENT_DELETE: typeof handlers.handleEntitlementDelete
MESSAGE_POLL_VOTE_ADD: typeof handlers.handleMessagePollVoteAdd
MESSAGE_POLL_VOTE_REMOVE: typeof handlers.handleMessagePollVoteRemove
}
export enum MessageFlags {

View File

@@ -40,6 +40,7 @@ import {
type DiscordMemberWithUser,
type DiscordMessage,
type DiscordPartialGuild,
type DiscordPollResult,
type DiscordPrunedCount,
type DiscordRole,
type DiscordScheduledEvent,
@@ -1352,6 +1353,14 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
return await rest.post<DiscordChannel>(rest.routes.channels.threads.all(channelId), { body, reason })
},
async getPollAnswerVoters(channelId, messageId, answerId, options) {
return await rest.get<DiscordPollResult>(rest.routes.channels.polls.votes(channelId, messageId, answerId, options))
},
async endPoll(channelId, messageId) {
return await rest.post<DiscordMessage>(rest.routes.channels.polls.expire(channelId, messageId))
},
async syncGuildTemplate(guildId) {
return await rest.put<DiscordTemplate>(rest.routes.guilds.templates.all(guildId))
},

View File

@@ -218,6 +218,22 @@ export function createRoutes(): RestRoutes {
typing: (channelId) => {
return `/channels/${channelId}/typing`
},
polls: {
votes: (channelId, messageId, answerId, options) => {
let url = `/channels/${channelId}/polls/${messageId}/answers/${answerId}?`
if (options) {
if (options.after) url += `after=${options.after}`
if (options.limit) url += `&limit=${options.limit}`
}
return url
},
expire: (channelId, messageId) => {
return `/channels/${channelId}/polls/${messageId}/expire`
},
},
},
// Guild Endpoints

View File

@@ -36,6 +36,7 @@ import type {
CamelizedDiscordMessage,
CamelizedDiscordModifyGuildWelcomeScreen,
CamelizedDiscordPartialGuild,
CamelizedDiscordPollResult,
CamelizedDiscordPrunedCount,
CamelizedDiscordRole,
CamelizedDiscordScheduledEvent,
@@ -97,6 +98,7 @@ import type {
GetGuildPruneCountQuery,
GetInvite,
GetMessagesOptions,
GetPollAnswerVotes,
GetReactions,
GetScheduledEventUsers,
GetScheduledEvents,
@@ -2544,6 +2546,34 @@ export interface RestManager {
* @see {@link https://discord.com/developers/docs/resources/channel#start-thread-without-message}
*/
startThreadWithoutMessage: (channelId: BigString, options: StartThreadWithoutMessage, reason?: string) => Promise<CamelizedDiscordChannel>
/**
* Get a list of users that voted for this specific answer.
*
* @param channelId - The ID of the channel in which the message with the poll lives
* @param messageId - The ID of the message in which the poll lives
* @param answerId - The ID of the answer to get the users that voted that answer
* @param options - The options for the request
* @returns The list of users that voted for the specific answer.
*/
getPollAnswerVoters: (
channelId: BigString,
messageId: BigString,
answerId: number,
options?: GetPollAnswerVotes,
) => Promise<CamelizedDiscordPollResult>
/**
* Immediately ends the poll.
*
* @param channelId - The ID of the channel in which the message with the poll lives
* @param messageId - The ID of the message in which the poll lives
* @returns The message with the expired poll
*
* @remarks
* You cannot end polls from other users.
*
* Fires a _Message Update_ gateway event
*/
endPoll: (channelId: BigString, messageId: BigString) => Promise<CamelizedDiscordMessage>
/**
* Synchronises a template with the current state of a guild.
*

View File

@@ -6,6 +6,7 @@ import type {
GetGuildPruneCountQuery,
GetInvite,
GetMessagesOptions,
GetPollAnswerVotes,
GetReactions,
GetScheduledEventUsers,
GetUserGuilds,
@@ -103,6 +104,10 @@ export interface RestRoutes {
/** Route for handling a specific reaction on a message. */
message: (channelId: BigString, messageId: BigString, emoji: string, options?: GetReactions) => string
}
polls: {
votes: (channelId: BigString, messageId: BigString, answerId: number, options?: GetPollAnswerVotes) => string
expire: (channelId: BigString, messageId: BigString) => string
}
}
/** Routes for guild related endpoints. */
guilds: {

View File

@@ -58,6 +58,7 @@ import type {
DiscordFollowedChannel,
DiscordForumTag,
DiscordGatewayPayload,
DiscordGetAnswerVotesResponse,
DiscordGetGatewayBot,
DiscordGuild,
DiscordGuildApplicationCommandPermissions,
@@ -118,6 +119,11 @@ import type {
DiscordOptionalAuditEntryInfo,
DiscordOverwrite,
DiscordPartialGuild,
DiscordPoll,
DiscordPollAnswer,
DiscordPollAnswerCount,
DiscordPollMedia,
DiscordPollResult,
DiscordPresenceUpdate,
DiscordPrunedCount,
DiscordReaction,
@@ -227,6 +233,12 @@ export interface CamelizedDiscordChannelMention extends Camelize<DiscordChannelM
export interface CamelizedDiscordReaction extends Camelize<DiscordReaction> {}
export interface CamelizedDiscordMessageActivity extends Camelize<DiscordMessageActivity> {}
export interface CamelizedDiscordMessageReference extends Camelize<DiscordMessageReference> {}
export interface CamelizedDiscordPoll extends Camelize<DiscordPoll> {}
export interface CamelizedDiscordPollMedia extends Camelize<DiscordPollMedia> {}
export interface CamelizedDiscordPollAnswer extends Camelize<DiscordPollAnswer> {}
export interface CamelizedDiscordPollAnswerCount extends Camelize<DiscordPollAnswerCount> {}
export interface CamelizedDiscordPollResult extends Camelize<DiscordPollResult> {}
export interface CamelizedDiscordGetAnswerVotesResponse extends Camelize<DiscordGetAnswerVotesResponse> {}
export interface CamelizedDiscordSticker extends Camelize<DiscordSticker> {}
export interface CamelizedDiscordMessageInteraction extends Camelize<DiscordMessageInteraction> {}
export type CamelizedDiscordMessageComponents = Camelize<DiscordMessageComponents>

View File

@@ -1331,6 +1331,8 @@ export interface DiscordMessage {
sticker_items?: DiscordStickerItem[]
/** A generally increasing integer (there may be gaps or duplicates) that represents the approximate position of the message in a thread, it can be used to estimate the relative position of the message in a thread in company with `total_message_sent` on parent thread */
position?: number
/** The poll object */
poll?: DiscordPoll
}
/** https://discord.com/developers/docs/resources/channel#channel-mention-object */
@@ -1392,6 +1394,122 @@ export interface DiscordMessageReference {
fail_if_not_exists: boolean
}
/** https://discord.com/developers/docs/resources/poll#poll-object */
export interface DiscordPoll {
/** The question of the poll. Only `text` is supported. */
question: DiscordPollMedia
/** Each of the answers available in the poll. There is a maximum of 10 answers per poll. */
answers: DiscordPollAnswer[]
/**
* The time when the poll ends.
*
* @remarks
* `expiry` is marked as nullable to support non-expiring polls in the future, but all polls have an expiry currently.
*/
expiry: string | null
/** Whether a user can select multiple answers */
allow_multiselect: boolean
/** The layout type of the poll */
layout_type: DiscordPollLayoutType
/**
* The results of the poll
*
* @remarks
* This value will not be sent by discord under specific conditions where they don't fetch them on their backend. When this value is missing it should be interpreted as "Unknown results" and not as "No results"
* The results may not be totally accurate while the poll has not ended. When it ends discord will re-calculate all the results and set {@link DiscordPollResult.is_finalized} to true
*/
results?: DiscordPollResult
}
/** https://discord.com/developers/docs/resources/poll#layout-type */
export enum DiscordPollLayoutType {
/** The default layout */
Default = 1,
}
/** https://discord.com/developers/docs/resources/poll#poll-media-object */
export interface DiscordPollMedia {
/**
* The text of the field
*
* @remarks
* `text` should always be non-null for both questions and answers, but this is subject to changes.
* The maximum length of `text` is 300 for the question, and 55 for any answer.
*/
text?: string
/**
* The emoji of the field
*
* @remarks
* When creating a poll answer with an emoji, one only needs to send either the `id` (custom emoji) or `name` (default emoji) as the only field.
*/
emoji?: Partial<DiscordEmoji>
}
/** https://discord.com/developers/docs/resources/poll#poll-answer-object */
export interface DiscordPollAnswer {
/**
* The id of the answer
*
* @remarks
* This id labels each answer. It starts at 1 and goes up sequentially. Discord recommend against depending on this value as is a implementation detail.
*/
answer_id: number
/** The data of the answer */
poll_media: DiscordPollMedia
}
export interface DiscordPollAnswerCount {
/** The {@link DiscordPollAnswer.answer_id | answer_id} */
id: number
/** The number of votes for this answer */
count: number
/** Whether the current user voted for this answer */
me_voted: boolean
}
/** https://discord.com/developers/docs/resources/poll#poll-results-object */
export interface DiscordPollResult {
/** Whether the votes have been precisely counted */
is_finalized: boolean
/** The counts for each answer */
answer_counts: DiscordPollAnswerCount[]
}
/** https://discord.com/developers/docs/resources/poll#get-answer-voters-response-body */
export interface DiscordGetAnswerVotesResponse {
/** Users who voted for this answer */
users: DiscordUser[]
}
/** https://discord.com/developers/docs/topics/gateway-events#message-poll-vote-add */
export interface DiscordPollVoteAdd {
/** ID of the user. Usually a snowflake */
user_id: string
/** ID of the channel. Usually a snowflake */
channel_id: string
/** ID of the message. Usually a snowflake */
message_id: string
/** ID of the guild. Usually a snowflake */
guild_id?: string
/** ID of the answer. */
answer_id: number
}
/** https://discord.com/developers/docs/topics/gateway-events#message-poll-vote-remove */
export interface DiscordPollVoteRemove {
/** ID of the user. Usually a snowflake */
user_id: string
/** ID of the channel. Usually a snowflake */
channel_id: string
/** ID of the message. Usually a snowflake */
message_id: string
/** ID of the guild. Usually a snowflake */
guild_id?: string
/** ID of the answer. */
answer_id: number
}
/** https://discord.com/developers/docs/resources/sticker#sticker-object-sticker-structure */
export interface DiscordSticker {
/** [Id of the sticker](https://discord.com/developers/docs/reference#image-formatting) */

View File

@@ -12,6 +12,9 @@ import type {
DiscordGuildOnboardingPrompt,
DiscordInstallParams,
DiscordMessageFlag,
DiscordPollAnswer,
DiscordPollLayoutType,
DiscordPollMedia,
DiscordRole,
} from './discord.js'
import type {
@@ -79,6 +82,8 @@ export interface CreateMessageOptions {
flags?: DiscordMessageFlag
/** If true and nonce is present, it will be checked for uniqueness in the past few minutes. If another message was created by the same author with the same nonce, that message will be returned and no new message will be created. */
enforceNonce?: boolean
/** A poll object */
poll?: CreatePoll
}
export type MessageComponents = ActionRow[]
@@ -742,6 +747,8 @@ export interface ExecuteWebhook {
allowedMentions?: AllowedMentions
/** the components to include with the message */
components?: MessageComponents
/** A poll object */
poll?: CreatePoll
}
export interface GetWebhookMessageOptions {
@@ -1313,3 +1320,29 @@ export interface EditApplication {
*/
tags?: string[]
}
/** https://discord.com/developers/docs/resources/poll#poll-create-request-object */
export interface CreatePoll {
/** The question of the poll. Only `text` is supported. */
question: Camelize<DiscordPollMedia>
/** Each of the answers available in the poll, up to 10 */
answers: Array<Omit<Camelize<DiscordPollAnswer>, 'answerId'>>
/** Number of hours the poll should be open for, up to 7 days */
duration: number
/** Whether a user can select multiple answers */
allowMultiselect: boolean
/** The layout type of the poll */
layoutType?: DiscordPollLayoutType
}
/** https://discord.com/developers/docs/resources/poll#get-answer-voters-query-string-params */
export interface GetPollAnswerVotes {
/** Get users after this user ID */
after?: BigString
/**
* Max number of users to return (1-100)
*
* @default 25
*/
limit?: number
}

View File

@@ -671,6 +671,8 @@ export enum BitwisePermissionFlags {
USE_EXTERNAL_SOUNDS = 0x0000200000000000,
/** Allows sending voice messages */
SEND_VOICE_MESSAGES = 0x0000400000000000,
/** Allows sending polls */
SEND_POLLS = 0x0002000000000000,
}
export type PermissionStrings = keyof typeof BitwisePermissionFlags
@@ -799,6 +801,8 @@ export type GatewayDispatchEventNames =
| 'ENTITLEMENT_CREATE'
| 'ENTITLEMENT_UPDATE'
| 'ENTITLEMENT_DELETE'
| 'MESSAGE_POLL_VOTE_ADD'
| 'MESSAGE_POLL_VOTE_REMOVE'
export type GatewayEventNames = GatewayDispatchEventNames | 'READY' | 'RESUMED'
@@ -935,6 +939,16 @@ export enum GatewayIntents {
* - AUTO_MODERATION_ACTION_EXECUTION
*/
AutoModerationExecution = 1 << 21,
/**
* - MESSAGE_POLL_VOTE_ADD
* - MESSAGE_POLL_VOTE_REMOVE
*/
GuildMessagePolls = 1 << 24,
/**
* - MESSAGE_POLL_VOTE_ADD
* - MESSAGE_POLL_VOTE_REMOVE
*/
DirectMessagePolls = 1 << 25,
}
/** https://discord.com/developers/docs/topics/gateway#list-of-intents */