From 86e0736726fb4ef13736510fa6d69f20383d5ea5 Mon Sep 17 00:00:00 2001 From: Vlad Frangu Date: Mon, 19 Jul 2021 22:00:20 +0300 Subject: [PATCH] chore: Get up to date *again* (#156) Co-authored-by: monbrey * Added `DiscordCertifiedModerator` flag to UserFlags * Updated types for Message Components * Added `disabled` to APISelectMenuCompponent * Cleaned up Buttons types, making them stricter based on the `style` you provide BREAKING CHANGE: `APISelectOption` has been renamed to `APISelectMenuOption` BREAKING CHANGE: APISelectMenuOption#default is now properly marked as optional * Updated OAuth2 Application types BREAKING CHANGE: `APIApplication#owner` is now marked as optional, per the docs * Correct APIAuditLogChangeKeyNick's key BREAKING CHANGE: This renames APIAuditLogChangeKeyNick's key from `mute` to `nick` * Add `application_id` to APIMessage * Correct type of `id` and `user_id` in APIThreadMember BREAKING CHANGE: The type of `id` and `user_id` in APIThreadMember are now marked as optional; read the TSDoc for when it's actually optional * Correctly version API route in RouteBases BREAKING CHANGE: This changes the `RouteBases.api` to be versioned based on the API version you're importing. **Make sure to update your code to handle that** * Added new guild features ref: https://github.com/discordjs/discord-api-types/pull/156/commits/4d36e533cffecbcce13e968a7803e5a68e021106 * Cleaned up interaction types BREAKING CHANGE: While this shouldn't be necessary, this is a warning that types for interactions HAVE changed and you may need to update your code. For the most part, the types *should* be the same, more accurate and strictly typed. You will also see that every type of interaction has a Guild/DM counterpart exported (ex: APIApplicationCommandGuildInteraction vs APIApplicationCommandInteraction, where the former has all the guild properties, while the latter has all properties that depend on context marked as optional). * Add TSD testing support in CI This is mostly useful for testing unions of types * Add message property to MessageComponent interactions --- .github/workflows/cicd.yml | 22 + deno/gateway/v8.ts | 4 +- deno/gateway/v9.ts | 4 +- deno/payloads/v8/_interactions/base.ts | 101 + .../v8/_interactions/messageComponents.ts | 38 + deno/payloads/v8/_interactions/responses.ts | 78 + .../v8/_interactions/slashCommands.ts | 273 + deno/payloads/v8/auditLog.ts | 2 +- deno/payloads/v8/channel.ts | 138 +- deno/payloads/v8/guild.ts | 24 + deno/payloads/v8/interactions.ts | 483 +- deno/payloads/v8/oauth2.ts | 18 +- deno/payloads/v8/user.ts | 1 + deno/payloads/v9/_interactions/base.ts | 101 + .../v9/_interactions/messageComponents.ts | 38 + deno/payloads/v9/_interactions/responses.ts | 78 + .../v9/_interactions/slashCommands.ts | 273 + deno/payloads/v9/auditLog.ts | 2 +- deno/payloads/v9/channel.ts | 146 +- deno/payloads/v9/guild.ts | 24 + deno/payloads/v9/interactions.ts | 483 +- deno/payloads/v9/oauth2.ts | 18 +- deno/payloads/v9/user.ts | 1 + deno/rest/v8/mod.ts | 2 +- deno/rest/v9/mod.ts | 2 +- deno/utils/v8.ts | 89 +- deno/utils/v9.ts | 89 +- gateway/v8.ts | 4 +- gateway/v9.ts | 4 +- package-lock.json | 8778 ++--------------- package.json | 35 +- payloads/v8/_interactions/base.ts | 101 + .../v8/_interactions/messageComponents.ts | 38 + payloads/v8/_interactions/responses.ts | 78 + payloads/v8/_interactions/slashCommands.ts | 273 + payloads/v8/auditLog.ts | 2 +- payloads/v8/channel.ts | 138 +- payloads/v8/guild.ts | 24 + payloads/v8/interactions.ts | 483 +- payloads/v8/oauth2.ts | 18 +- payloads/v8/user.ts | 1 + payloads/v9/_interactions/base.ts | 101 + .../v9/_interactions/messageComponents.ts | 38 + payloads/v9/_interactions/responses.ts | 78 + payloads/v9/_interactions/slashCommands.ts | 273 + payloads/v9/auditLog.ts | 2 +- payloads/v9/channel.ts | 146 +- payloads/v9/guild.ts | 24 + payloads/v9/interactions.ts | 483 +- payloads/v9/oauth2.ts | 18 +- payloads/v9/user.ts | 1 + rest/v8/index.ts | 2 +- rest/v9/index.ts | 2 +- tests/v9/interactions.test-d.ts | 46 + tsconfig.eslint.json | 3 +- utils/v8.ts | 89 +- utils/v9.ts | 89 +- 57 files changed, 3715 insertions(+), 10189 deletions(-) create mode 100644 deno/payloads/v8/_interactions/base.ts create mode 100644 deno/payloads/v8/_interactions/messageComponents.ts create mode 100644 deno/payloads/v8/_interactions/responses.ts create mode 100644 deno/payloads/v8/_interactions/slashCommands.ts create mode 100644 deno/payloads/v9/_interactions/base.ts create mode 100644 deno/payloads/v9/_interactions/messageComponents.ts create mode 100644 deno/payloads/v9/_interactions/responses.ts create mode 100644 deno/payloads/v9/_interactions/slashCommands.ts create mode 100644 payloads/v8/_interactions/base.ts create mode 100644 payloads/v8/_interactions/messageComponents.ts create mode 100644 payloads/v8/_interactions/responses.ts create mode 100644 payloads/v8/_interactions/slashCommands.ts create mode 100644 payloads/v9/_interactions/base.ts create mode 100644 payloads/v9/_interactions/messageComponents.ts create mode 100644 payloads/v9/_interactions/responses.ts create mode 100644 payloads/v9/_interactions/slashCommands.ts create mode 100644 tests/v9/interactions.test-d.ts diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index 8e2f7ba5..101df51c 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -61,3 +61,25 @@ jobs: git add --all . git commit -m "build: deno build for ${GITHUB_SHA}" || true git push || true + + tsd: + name: TSD checks + runs-on: ubuntu-latest + + needs: testing + if: needs.testing.result == 'success' + + steps: + - name: Checkout Project + uses: actions/checkout@v2 + + - name: Use Node.js v16 + uses: actions/setup-node@v2 + with: + node-version: 16 + + - name: Install Dependencies + run: npm ci + + - name: Run TSD + run: npm run test:types diff --git a/deno/gateway/v8.ts b/deno/gateway/v8.ts index 276afad1..b714f96f 100644 --- a/deno/gateway/v8.ts +++ b/deno/gateway/v8.ts @@ -314,9 +314,7 @@ export type GatewayApplicationCommandModifyDispatch = DataPayload< * https://discord.com/developers/docs/topics/gateway#application-command-update * https://discord.com/developers/docs/topics/gateway#application-command-delete */ -export interface GatewayApplicationCommandModifyDispatchData extends APIApplicationCommand { - guild_id?: string; -} +export type GatewayApplicationCommandModifyDispatchData = APIApplicationCommand; /** * https://discord.com/developers/docs/topics/gateway#application-command-create diff --git a/deno/gateway/v9.ts b/deno/gateway/v9.ts index 36488df3..26c03dbf 100644 --- a/deno/gateway/v9.ts +++ b/deno/gateway/v9.ts @@ -324,9 +324,7 @@ export type GatewayApplicationCommandModifyDispatch = DataPayload< * https://discord.com/developers/docs/topics/gateway#application-command-update * https://discord.com/developers/docs/topics/gateway#application-command-delete */ -export interface GatewayApplicationCommandModifyDispatchData extends APIApplicationCommand { - guild_id?: string; -} +export type GatewayApplicationCommandModifyDispatchData = APIApplicationCommand; /** * https://discord.com/developers/docs/topics/gateway#application-command-create diff --git a/deno/payloads/v8/_interactions/base.ts b/deno/payloads/v8/_interactions/base.ts new file mode 100644 index 00000000..c411bf84 --- /dev/null +++ b/deno/payloads/v8/_interactions/base.ts @@ -0,0 +1,101 @@ +import { Permissions, Snowflake } from '../../../globals.ts'; +import { InteractionType } from '../../v8.ts'; +import { APIMessage } from '../channel.ts'; +import { APIGuildMember } from '../guild.ts'; +import { APIUser } from '../user.ts'; + +/** + * https://discord.com/developers/docs/interactions/slash-commands#message-interaction-object-message-interaction-structure + */ +export interface APIMessageInteraction { + /** + * ID of the interaction + */ + id: Snowflake; + /** + * The type of interaction + */ + type: InteractionType; + /** + * The name of the ApplicationCommand + */ + name: string; + /** + * The user who invoked the interaction + */ + user: APIUser; +} + +/** + * https://discord.com/developers/docs/resources/guild#guild-member-object + */ +export interface APIInteractionGuildMember extends APIGuildMember { + permissions: Permissions; + user: APIUser; +} + +// INTERACTIONS RECEIVED + +/** + * https://discord.com/developers/docs/interactions/slash-commands#interaction-object + */ +export interface APIBaseInteraction { + /** + * ID of the interaction + */ + id: Snowflake; + /** + * ID of the application this interaction is for + */ + application_id: Snowflake; + /** + * The type of interaction + */ + type: Type; + /** + * The command data payload + */ + data?: Data; + /** + * The guild it was sent from + */ + guild_id?: Snowflake; + /** + * The channel it was sent from + */ + channel_id?: Snowflake; + /** + * Guild member data for the invoking user, including permissions + * + * **This is only sent when an interaction is invoked in a guild** + */ + member?: APIInteractionGuildMember; + /** + * User object for the invoking user, if invoked in a DM + */ + user?: APIUser; + /** + * A continuation token for responding to the interaction + */ + token: string; + /** + * Read-only property, always `1` + */ + version: 1; + /** + * For components, the message they were attached to + */ + message?: APIMessage; +} + +export type APIDMInteractionWrapper> = Omit< + Original, + 'member' | 'guild_id' +> & + Required>; + +export type APIGuildInteractionWrapper> = Omit< + Original, + 'user' +> & + Required>; diff --git a/deno/payloads/v8/_interactions/messageComponents.ts b/deno/payloads/v8/_interactions/messageComponents.ts new file mode 100644 index 00000000..c6032be5 --- /dev/null +++ b/deno/payloads/v8/_interactions/messageComponents.ts @@ -0,0 +1,38 @@ +import { ComponentType } from '../channel.ts'; +import { APIBaseInteraction, InteractionType } from '../interactions.ts'; +import { APIDMInteractionWrapper, APIGuildInteractionWrapper } from './base.ts'; + +export type APIMessageComponentInteraction = APIBaseInteraction< + InteractionType.MessageComponent, + APIMessageComponentInteractionData +> & + Required< + Pick< + APIBaseInteraction, + 'channel_id' | 'data' | 'message' + > + >; + +export type APIMessageComponentInteractionData = APIMessageButtonInteractionData | APIMessageSelectMenuInteractionData; + +export interface APIMessageComponentBaseInteractionData { + /** + * The `custom_id` of the component + */ + custom_id: string; + /** + * The type of the component + */ + component_type: CType; +} + +export type APIMessageButtonInteractionData = APIMessageComponentBaseInteractionData; + +export interface APIMessageSelectMenuInteractionData + extends APIMessageComponentBaseInteractionData { + values: string[]; +} + +export type APIMessageComponentDMInteraction = APIDMInteractionWrapper; + +export type APIMessageComponentGuildInteraction = APIGuildInteractionWrapper; diff --git a/deno/payloads/v8/_interactions/responses.ts b/deno/payloads/v8/_interactions/responses.ts new file mode 100644 index 00000000..3a36dda6 --- /dev/null +++ b/deno/payloads/v8/_interactions/responses.ts @@ -0,0 +1,78 @@ +import { MessageFlags } from '../mod.ts'; +import { RESTPostAPIWebhookWithTokenJSONBody } from '../../../v8.ts'; + +/** + * https://discord.com/developers/docs/interactions/slash-commands#interaction-object-interaction-request-type + */ +export enum InteractionType { + Ping = 1, + ApplicationCommand, + MessageComponent, +} + +/** + * https://discord.com/developers/docs/interactions/slash-commands#interaction-response-object + */ +export type APIInteractionResponse = + | APIInteractionResponsePong + | APIInteractionResponseChannelMessageWithSource + | APIInteractionResponseDeferredChannelMessageWithSource + | APIInteractionResponseDeferredMessageUpdate + | APIInteractionResponseUpdateMessage; + +export interface APIInteractionResponsePong { + type: InteractionResponseType.Pong; +} + +export interface APIInteractionResponseChannelMessageWithSource { + type: InteractionResponseType.ChannelMessageWithSource; + data: APIInteractionResponseCallbackData; +} + +export interface APIInteractionResponseDeferredChannelMessageWithSource { + type: InteractionResponseType.DeferredChannelMessageWithSource; + data?: Pick; +} + +export interface APIInteractionResponseDeferredMessageUpdate { + type: InteractionResponseType.DeferredMessageUpdate; +} + +export interface APIInteractionResponseUpdateMessage { + type: InteractionResponseType.UpdateMessage; + data?: APIInteractionResponseCallbackData; +} + +/** + * https://discord.com/developers/docs/interactions/slash-commands#interaction-response-object-interaction-callback-type + */ +export enum InteractionResponseType { + /** + * ACK a `Ping` + */ + Pong = 1, + /** + * Respond to an interaction with a message + */ + ChannelMessageWithSource = 4, + /** + * ACK an interaction and edit to a response later, the user sees a loading state + */ + DeferredChannelMessageWithSource, + /** + * ACK a button interaction and update it to a loading state + */ + DeferredMessageUpdate, + /** + * ACK a button interaction and edit the message to which the button was attached + */ + UpdateMessage, +} + +/** + * https://discord.com/developers/docs/interactions/slash-commands#interaction-response-object-interaction-application-command-callback-data-structure + */ +export type APIInteractionResponseCallbackData = Omit< + RESTPostAPIWebhookWithTokenJSONBody, + 'username' | 'avatar_url' +> & { flags?: MessageFlags }; diff --git a/deno/payloads/v8/_interactions/slashCommands.ts b/deno/payloads/v8/_interactions/slashCommands.ts new file mode 100644 index 00000000..ee80d3ec --- /dev/null +++ b/deno/payloads/v8/_interactions/slashCommands.ts @@ -0,0 +1,273 @@ +import { APIRole, APIUser } from '../mod.ts'; +import { Permissions, Snowflake } from '../../../globals.ts'; +import { APIPartialChannel } from '../channel.ts'; +import { APIGuildMember } from '../guild.ts'; +import { APIBaseInteraction, APIDMInteractionWrapper, APIGuildInteractionWrapper } from './base.ts'; +import { InteractionType } from './responses.ts'; + +/** + * https://discord.com/developers/docs/interactions/slash-commands#application-command-object + */ +export interface APIApplicationCommand { + /** + * Unique id of the command + */ + id: Snowflake; + /** + * Unique id of the parent application + */ + application_id: Snowflake; + /** + * Guild id of the command, if not global + */ + guild_id?: Snowflake; + /** + * 1-32 character name matching `^[\w-]{1,32}$` + */ + name: string; + /** + * 1-100 character description + */ + description: string; + /** + * The parameters for the command + */ + options?: APIApplicationCommandOption[]; + /** + * Whether the command is enabled by default when the app is added to a guild + * + * If missing, this property should be assumed as `true` + */ + default_permission?: boolean; +} + +interface APIApplicationCommandOptionBase { + type: + | ApplicationCommandOptionType.Boolean + | ApplicationCommandOptionType.User + | ApplicationCommandOptionType.Channel + | ApplicationCommandOptionType.Role + | ApplicationCommandOptionType.Mentionable; + name: string; + description: string; + default?: boolean; + required?: boolean; +} + +/** + * https://discord.com/developers/docs/interactions/slash-commands#application-command-object-application-command-option-structure + */ +export type APIApplicationCommandOption = + | APIApplicationCommandArgumentOptions + | APIApplicationCommandSubCommandOptions + | APIApplicationCommandOptionBase; + +/** + * This type is exported as a way to make it stricter for you when you're writing your commands + * + * If the option is a `SUB_COMMAND` or `SUB_COMMAND_GROUP` type, this nested options will be the parameters + */ +export interface APIApplicationCommandSubCommandOptions extends Omit { + type: ApplicationCommandOptionType.SubCommand | ApplicationCommandOptionType.SubCommandGroup; + options?: APIApplicationCommandOption[]; +} + +/** + * This type is exported as a way to make it stricter for you when you're writing your commands + * + * In contrast to `APIApplicationCommandSubCommandOptions`, these types cannot have an `options` array, + * but they can have a `choices` one + */ +export interface APIApplicationCommandArgumentOptions extends Omit { + type: ApplicationCommandOptionType.String | ApplicationCommandOptionType.Integer; + choices?: APIApplicationCommandOptionChoice[]; +} + +/** + * https://discord.com/developers/docs/interactions/slash-commands#application-command-object-application-command-option-type + */ +export enum ApplicationCommandOptionType { + SubCommand = 1, + SubCommandGroup, + String, + Integer, + Boolean, + User, + Channel, + Role, + Mentionable, +} + +/** + * https://discord.com/developers/docs/interactions/slash-commands#application-command-object-application-command-option-choice-structure + */ +export interface APIApplicationCommandOptionChoice { + name: string; + value: string | number; +} + +/** + * https://discord.com/developers/docs/interactions/slash-commands#interaction-object-interaction-structure + */ +export interface APIApplicationCommandInteractionData { + id: Snowflake; + name: string; + options?: APIApplicationCommandInteractionDataOption[]; + resolved?: { + users?: Record; + roles?: Record; + members?: Record; + channels?: Record; + }; +} + +/** + * https://discord.com/developers/docs/resources/channel#channel-object + */ +export interface APIInteractionDataResolvedChannel extends Required { + permissions: Permissions; +} + +/** + * https://discord.com/developers/docs/resources/guild#guild-member-object + */ +export interface APIInteractionDataResolvedGuildMember extends Omit { + permissions: Permissions; +} + +/** + * https://discord.com/developers/docs/interactions/slash-commands#interaction-object-application-command-interaction-data-option-structure + */ +export type APIApplicationCommandInteractionDataOption = + | ApplicationCommandInteractionDataOptionSubCommand + | ApplicationCommandInteractionDataOptionSubCommandGroup + | APIApplicationCommandInteractionDataOptionWithValues; + +export interface ApplicationCommandInteractionDataOptionSubCommand { + name: string; + type: ApplicationCommandOptionType.SubCommand; + options: APIApplicationCommandInteractionDataOptionWithValues[]; +} + +export interface ApplicationCommandInteractionDataOptionSubCommandGroup { + name: string; + type: ApplicationCommandOptionType.SubCommandGroup; + options: ApplicationCommandInteractionDataOptionSubCommand[]; +} + +export type APIApplicationCommandInteractionDataOptionWithValues = + | ApplicationCommandInteractionDataOptionString + | ApplicationCommandInteractionDataOptionRole + | ApplicationCommandInteractionDataOptionChannel + | ApplicationCommandInteractionDataOptionUser + | ApplicationCommandInteractionDataOptionMentionable + | ApplicationCommandInteractionDataOptionInteger + | ApplicationCommandInteractionDataOptionBoolean; + +export type ApplicationCommandInteractionDataOptionString = InteractionDataOptionBase< + ApplicationCommandOptionType.String, + string +>; + +export type ApplicationCommandInteractionDataOptionRole = InteractionDataOptionBase< + ApplicationCommandOptionType.Role, + Snowflake +>; + +export type ApplicationCommandInteractionDataOptionChannel = InteractionDataOptionBase< + ApplicationCommandOptionType.Channel, + Snowflake +>; + +export type ApplicationCommandInteractionDataOptionUser = InteractionDataOptionBase< + ApplicationCommandOptionType.User, + Snowflake +>; + +export type ApplicationCommandInteractionDataOptionMentionable = InteractionDataOptionBase< + ApplicationCommandOptionType.Mentionable, + Snowflake +>; + +export type ApplicationCommandInteractionDataOptionInteger = InteractionDataOptionBase< + ApplicationCommandOptionType.Integer, + number +>; + +export type ApplicationCommandInteractionDataOptionBoolean = InteractionDataOptionBase< + ApplicationCommandOptionType.Boolean, + boolean +>; + +interface InteractionDataOptionBase { + name: string; + type: T; + value: D; +} + +// PERMISSIONS + +/** + * https://discord.com/developers/docs/interactions/slash-commands#application-command-permissions-object-guild-application-command-permissions-structure + */ +export interface APIGuildApplicationCommandPermissions { + /** + * The id of the command + */ + id: Snowflake; + /** + * The id of the application the command belongs to + */ + application_id: Snowflake; + /** + * The id of the guild + */ + guild_id: Snowflake; + /** + * The permissions for the command in the guild + */ + permissions: APIApplicationCommandPermission[]; +} + +/** + * https://discord.com/developers/docs/interactions/slash-commands#application-command-permissions-object-application-command-permissions-structure + */ +export interface APIApplicationCommandPermission { + /** + * The id of the role or user + */ + id: Snowflake; + /** + * Role or user + */ + type: ApplicationCommandPermissionType; + /** + * `true` to allow, `false`, to disallow + */ + permission: boolean; +} + +/** + * https://discord.com/developers/docs/interactions/slash-commands#applicationcommandpermissiontype + */ +export enum ApplicationCommandPermissionType { + Role = 1, + User, +} + +// INTERACTIONS + +export type APIApplicationCommandInteraction = APIBaseInteraction< + InteractionType.ApplicationCommand, + APIApplicationCommandInteractionData +> & + Required< + Pick< + APIBaseInteraction, + 'channel_id' | 'data' + > + >; + +export type APIApplicationCommandDMInteraction = APIDMInteractionWrapper; + +export type APIApplicationCommandGuildInteraction = APIGuildInteractionWrapper; diff --git a/deno/payloads/v8/auditLog.ts b/deno/payloads/v8/auditLog.ts index 546d6cd7..73268ac3 100644 --- a/deno/payloads/v8/auditLog.ts +++ b/deno/payloads/v8/auditLog.ts @@ -544,7 +544,7 @@ export type APIAuditLogChangeKeyMute = AuditLogChangeData<'mute', boolean>; /** * Returned when a user's nick is changed */ -export type APIAuditLogChangeKeyNick = AuditLogChangeData<'mute', boolean>; +export type APIAuditLogChangeKeyNick = AuditLogChangeData<'nick', boolean>; /** * Returned when a user's avatar_hash is changed diff --git a/deno/payloads/v8/channel.ts b/deno/payloads/v8/channel.ts index 4cb60c80..65312b82 100644 --- a/deno/payloads/v8/channel.ts +++ b/deno/payloads/v8/channel.ts @@ -306,7 +306,11 @@ export interface APIMessage { */ application?: Partial; /** - * Reference data sent with crossposted messages and replies + * If the message is a response to an Interaction, this is the id of the interaction's application + */ + application_id?: Snowflake; + /** + * Reference data sent with crossposted messages, replies, pins, and thread starter messages * * See https://discord.com/developers/docs/resources/channel#message-object-message-reference-structure */ @@ -899,13 +903,13 @@ export interface APIAllowedMentions { } /** - * https://discord.com/developers/docs/interactions/message-components + * https://discord.com/developers/docs/interactions/message-components#component-object */ -export interface APIBaseComponent { +export interface APIBaseMessageComponent { /** * The type of the component */ - type: ComponentType; + type: T; } /** @@ -913,7 +917,7 @@ export interface APIBaseComponent { */ export enum ComponentType { /** - * ActionRow component + * Action Row component */ ActionRow = 1, /** @@ -927,13 +931,9 @@ export enum ComponentType { } /** - * https://discord.com/developers/docs/interactions/message-components#component-object + * https://discord.com/developers/docs/interactions/message-components#action-rows */ -export interface APIActionRowComponent extends APIBaseComponent { - /** - * The type of the component - */ - type: ComponentType.ActionRow; +export interface APIActionRowComponent extends APIBaseMessageComponent { /** * The components in the ActionRow */ @@ -941,73 +941,97 @@ export interface APIActionRowComponent extends APIBaseComponent { } /** - * https://discord.com/developers/docs/interactions/message-components#buttons-button-object + * https://discord.com/developers/docs/interactions/message-components#buttons */ -export interface APIButtonComponent extends APIBaseComponent { - /** - * The type of the component - */ - type: ComponentType.Button; +interface APIButtonComponentBase