Merge pull request #138 from DjDeveloperr/design-fix
BREAKING: Split up Interaction structure into different types
This commit is contained in:
		
						commit
						b686c02cdc
					
				
					 20 changed files with 636 additions and 477 deletions
				
			
		
							
								
								
									
										30
									
								
								deploy.ts
									
										
									
									
									
								
							
							
						
						
									
										30
									
								
								deploy.ts
									
										
									
									
									
								
							|  | @ -1,15 +1,20 @@ | |||
| import { Interaction } from './mod.ts' | ||||
| import { | ||||
|   SlashCommandsManager, | ||||
|   SlashClient, | ||||
|   SlashCommandHandlerCallback, | ||||
|   SlashCommandHandler | ||||
| } from './src/interactions/mod.ts' | ||||
| import { InteractionResponseType, InteractionType } from './src/types/slash.ts' | ||||
| import { | ||||
|   InteractionResponseType, | ||||
|   InteractionType | ||||
| } from './src/types/interactions.ts' | ||||
| 
 | ||||
| export interface DeploySlashInitOptions { | ||||
|   env?: boolean | ||||
|   publicKey?: string | ||||
|   token?: string | ||||
|   path?: string | ||||
| } | ||||
| 
 | ||||
| /** Current Slash Client being used to handle commands */ | ||||
|  | @ -37,8 +42,12 @@ let commands: SlashCommandsManager | |||
|  * | ||||
|  * @param options Initialization options | ||||
|  */ | ||||
| export function init(options: { env: boolean }): void | ||||
| export function init(options: { publicKey: string; token?: string }): void | ||||
| export function init(options: { env: boolean; path?: string }): void | ||||
| export function init(options: { | ||||
|   publicKey: string | ||||
|   token?: string | ||||
|   path?: string | ||||
| }): void | ||||
| export function init(options: DeploySlashInitOptions): void { | ||||
|   if (client !== undefined) throw new Error('Already initialized') | ||||
|   if (options.env === true) { | ||||
|  | @ -60,6 +69,9 @@ export function init(options: DeploySlashInitOptions): void { | |||
|     respondWith: CallableFunction | ||||
|     request: Request | ||||
|   }): Promise<void> => { | ||||
|     if (options.path !== undefined) { | ||||
|       if (new URL(evt.request.url).pathname !== options.path) return | ||||
|     } | ||||
|     try { | ||||
|       // we have to wrap because there are some weird scope errors
 | ||||
|       const d = await client.verifyFetchEvent({ | ||||
|  | @ -124,8 +136,18 @@ export function handle( | |||
|   client.handle(cmd, handler) | ||||
| } | ||||
| 
 | ||||
| export function interactions(cb: (i: Interaction) => any): void { | ||||
|   client.on('interaction', cb) | ||||
| } | ||||
| 
 | ||||
| export { commands, client } | ||||
| export * from './src/types/slash.ts' | ||||
| export * from './src/types/slashCommands.ts' | ||||
| export * from './src/types/interactions.ts' | ||||
| export * from './src/structures/slash.ts' | ||||
| export * from './src/interactions/mod.ts' | ||||
| export * from './src/types/channel.ts' | ||||
| export * from './src/types/messageComponents.ts' | ||||
| export * from './src/structures/interactions.ts' | ||||
| export * from './src/structures/messageComponents.ts' | ||||
| export * from './src/structures/message.ts' | ||||
| export * from './src/structures/embed.ts' | ||||
|  |  | |||
							
								
								
									
										5
									
								
								mod.ts
									
										
									
									
									
								
							
							
						
						
									
										5
									
								
								mod.ts
									
										
									
									
									
								
							|  | @ -39,7 +39,9 @@ export { GuildChannelsManager } from './src/managers/guildChannels.ts' | |||
| export { GuildManager } from './src/managers/guilds.ts' | ||||
| export * from './src/structures/base.ts' | ||||
| export * from './src/structures/slash.ts' | ||||
| export * from './src/types/slash.ts' | ||||
| export * from './src/structures/interactions.ts' | ||||
| export * from './src/types/slashCommands.ts' | ||||
| export * from './src/types/interactions.ts' | ||||
| export { GuildEmojisManager } from './src/managers/guildEmojis.ts' | ||||
| export { MembersManager } from './src/managers/members.ts' | ||||
| export { MessageReactionsManager } from './src/managers/messageReactions.ts' | ||||
|  | @ -191,4 +193,5 @@ export { | |||
|   isVoiceChannel, | ||||
|   default as getChannelByType | ||||
| } from './src/utils/channel.ts' | ||||
| export * from './src/utils/interactions.ts' | ||||
| export * from "./src/utils/command.ts" | ||||
|  | @ -1,17 +1,31 @@ | |||
| /* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */ | ||||
| import { Guild } from '../../structures/guild.ts' | ||||
| import { Member } from '../../structures/member.ts' | ||||
| import { | ||||
|   Interaction, | ||||
|   InteractionApplicationCommandResolved, | ||||
|   InteractionChannel | ||||
|   SlashCommandInteraction | ||||
| } from '../../structures/slash.ts' | ||||
| import { | ||||
|   Interaction, | ||||
|   InteractionChannel | ||||
| } from '../../structures/interactions.ts' | ||||
| import { GuildTextBasedChannel } from '../../structures/guildTextChannel.ts' | ||||
| import { InteractionPayload } from '../../types/slash.ts' | ||||
| import { | ||||
|   InteractionPayload, | ||||
|   InteractionType | ||||
| } from '../../types/interactions.ts' | ||||
| import { UserPayload } from '../../types/user.ts' | ||||
| import { Permissions } from '../../utils/permissions.ts' | ||||
| import type { Gateway, GatewayEventHandler } from '../mod.ts' | ||||
| import { User } from '../../structures/user.ts' | ||||
| import { Role } from '../../structures/role.ts' | ||||
| import { RolePayload } from '../../types/role.ts' | ||||
| import { | ||||
|   InteractionApplicationCommandData, | ||||
|   InteractionChannelPayload | ||||
| } from '../../types/slashCommands.ts' | ||||
| import { Message } from '../../structures/message.ts' | ||||
| import { TextChannel } from '../../structures/textChannel.ts' | ||||
| 
 | ||||
| export const interactionCreate: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|  | @ -26,13 +40,22 @@ export const interactionCreate: GatewayEventHandler = async ( | |||
|   const guild = | ||||
|     d.guild_id === undefined | ||||
|       ? undefined | ||||
|       : await gateway.client.guilds.get(d.guild_id) | ||||
|       : (await gateway.client.guilds.get(d.guild_id)) ?? | ||||
|         new Guild(gateway.client, { unavailable: true, id: d.guild_id } as any) | ||||
| 
 | ||||
|   if (d.member !== undefined) | ||||
|     await guild?.members.set(d.member.user.id, d.member) | ||||
|   const member = | ||||
|     d.member !== undefined | ||||
|       ? (((await guild?.members.get(d.member.user.id)) as unknown) as Member) | ||||
|       ? (await guild?.members.get(d.member.user.id))! ?? | ||||
|         new Member( | ||||
|           gateway.client, | ||||
|           d.member!, | ||||
|           new User(gateway.client, d.member.user), | ||||
|           // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
 | ||||
|           guild!, | ||||
|           new Permissions(d.member.permissions) | ||||
|         ) | ||||
|       : undefined | ||||
|   if (d.user !== undefined) await gateway.client.users.set(d.user.id, d.user) | ||||
|   const dmUser = | ||||
|  | @ -41,9 +64,9 @@ export const interactionCreate: GatewayEventHandler = async ( | |||
|   const user = member !== undefined ? member.user : dmUser | ||||
|   if (user === undefined) return | ||||
| 
 | ||||
|   const channel = | ||||
|     (await gateway.client.channels.get<GuildTextBasedChannel>(d.channel_id)) ?? | ||||
|     (await gateway.client.channels.fetch<GuildTextBasedChannel>(d.channel_id)) | ||||
|   const channel = await gateway.client.channels.get<GuildTextBasedChannel>( | ||||
|     d.channel_id | ||||
|   ) | ||||
| 
 | ||||
|   const resolved: InteractionApplicationCommandResolved = { | ||||
|     users: {}, | ||||
|  | @ -52,9 +75,11 @@ export const interactionCreate: GatewayEventHandler = async ( | |||
|     roles: {} | ||||
|   } | ||||
| 
 | ||||
|   if (d.data?.resolved !== undefined) { | ||||
|     for (const [id, data] of Object.entries(d.data.resolved.users ?? {})) { | ||||
|       await gateway.client.users.set(id, data) | ||||
|   if ((d.data as InteractionApplicationCommandData)?.resolved !== undefined) { | ||||
|     for (const [id, data] of Object.entries( | ||||
|       (d.data as any)?.resolved.users ?? {} | ||||
|     )) { | ||||
|       await gateway.client.users.set(id, data as UserPayload) | ||||
|       resolved.users[id] = ((await gateway.client.users.get( | ||||
|         id | ||||
|       )) as unknown) as User | ||||
|  | @ -62,49 +87,87 @@ export const interactionCreate: GatewayEventHandler = async ( | |||
|         resolved.users[id].member = resolved.members[id] | ||||
|     } | ||||
| 
 | ||||
|     for (const [id, data] of Object.entries(d.data.resolved.members ?? {})) { | ||||
|     for (const [id, data] of Object.entries( | ||||
|       (d.data as InteractionApplicationCommandData)?.resolved?.members ?? {} | ||||
|     )) { | ||||
|       const roles = await guild?.roles.array() | ||||
|       let permissions = new Permissions(Permissions.DEFAULT) | ||||
|       if (roles !== undefined) { | ||||
|         const mRoles = roles.filter( | ||||
|           (r) => (data?.roles?.includes(r.id) as boolean) || r.id === guild?.id | ||||
|           (r) => | ||||
|             ((data as any)?.roles?.includes(r.id) as boolean) || | ||||
|             r.id === guild?.id | ||||
|         ) | ||||
|         permissions = new Permissions(mRoles.map((r) => r.permissions)) | ||||
|       } | ||||
|       data.user = (d.data.resolved.users?.[id] as unknown) as UserPayload | ||||
|       ;(data as any).user = ((d.data as any).resolved.users?.[ | ||||
|         id | ||||
|       ] as unknown) as UserPayload | ||||
|       resolved.members[id] = new Member( | ||||
|         gateway.client, | ||||
|         data, | ||||
|         data as any, | ||||
|         resolved.users[id], | ||||
|         guild as Guild, | ||||
|         permissions | ||||
|       ) | ||||
|     } | ||||
| 
 | ||||
|     for (const [id, data] of Object.entries(d.data.resolved.roles ?? {})) { | ||||
|     for (const [id, data] of Object.entries( | ||||
|       (d.data as InteractionApplicationCommandData).resolved?.roles ?? {} | ||||
|     )) { | ||||
|       if (guild !== undefined) { | ||||
|         await guild.roles.set(id, data) | ||||
|         await guild.roles.set(id, data as RolePayload) | ||||
|         resolved.roles[id] = ((await guild.roles.get(id)) as unknown) as Role | ||||
|       } else { | ||||
|         resolved.roles[id] = new Role( | ||||
|           gateway.client, | ||||
|           data, | ||||
|           data as any, | ||||
|           (guild as unknown) as Guild | ||||
|         ) | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     for (const [id, data] of Object.entries(d.data.resolved.channels ?? {})) { | ||||
|       resolved.channels[id] = new InteractionChannel(gateway.client, data) | ||||
|     for (const [id, data] of Object.entries( | ||||
|       (d.data as InteractionApplicationCommandData).resolved?.channels ?? {} | ||||
|     )) { | ||||
|       resolved.channels[id] = new InteractionChannel( | ||||
|         gateway.client, | ||||
|         data as InteractionChannelPayload | ||||
|       ) | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   const interaction = new Interaction(gateway.client, d, { | ||||
|   let message: Message | undefined | ||||
|   if (d.message !== undefined) { | ||||
|     const channel = (await gateway.client.channels.get<TextChannel>( | ||||
|       d.message.channel_id | ||||
|     ))! | ||||
|     message = new Message( | ||||
|       gateway.client, | ||||
|       d.message, | ||||
|       channel, | ||||
|       new User(gateway.client, d.message.author) | ||||
|     ) | ||||
|   } | ||||
| 
 | ||||
|   let interaction | ||||
|   if (d.type === InteractionType.APPLICATION_COMMAND) { | ||||
|     interaction = new SlashCommandInteraction(gateway.client, d, { | ||||
|       member, | ||||
|       guild, | ||||
|       channel, | ||||
|       user, | ||||
|       resolved | ||||
|     }) | ||||
|   } else { | ||||
|     interaction = new Interaction(gateway.client, d, { | ||||
|       member, | ||||
|       guild, | ||||
|       channel, | ||||
|       user, | ||||
|       message | ||||
|     }) | ||||
|   } | ||||
| 
 | ||||
|   gateway.client.emit('interactionCreate', interaction) | ||||
| } | ||||
|  |  | |||
|  | @ -59,7 +59,8 @@ import type { | |||
|   EveryTextChannelTypes | ||||
| } from '../../utils/channel.ts' | ||||
| import { interactionCreate } from './interactionCreate.ts' | ||||
| import type { Interaction } from '../../structures/slash.ts' | ||||
| import type { Interaction } from '../../structures/interactions.ts' | ||||
| import type { SlashCommandInteraction } from '../../structures/slash.ts' | ||||
| import type { CommandContext } from '../../commands/command.ts' | ||||
| import type { RequestMethods } from '../../rest/types.ts' | ||||
| import type { PartialInvitePayload } from '../../types/invite.ts' | ||||
|  | @ -358,11 +359,12 @@ export type ClientEvents = { | |||
|    * @param channel Channel of which Webhooks were updated | ||||
|    */ | ||||
|   webhooksUpdate: [guild: Guild, channel: GuildTextBasedChannel] | ||||
| 
 | ||||
|   /** | ||||
|    * An Interaction was created | ||||
|    * @param interaction Created interaction object | ||||
|    */ | ||||
|   interactionCreate: [interaction: Interaction] | ||||
|   interactionCreate: [interaction: Interaction | SlashCommandInteraction] | ||||
| 
 | ||||
|   /** | ||||
|    * When debug message was made | ||||
|  |  | |||
|  | @ -1,13 +1,14 @@ | |||
| import { | ||||
|   Interaction, | ||||
|   SlashCommandInteraction, | ||||
|   InteractionApplicationCommandResolved | ||||
| } from '../structures/slash.ts' | ||||
| import { Interaction } from '../structures/interactions.ts' | ||||
| import { | ||||
|   InteractionPayload, | ||||
|   InteractionResponsePayload, | ||||
|   InteractionType, | ||||
|   SlashCommandOptionType | ||||
| } from '../types/slash.ts' | ||||
|   InteractionType | ||||
| } from '../types/interactions.ts' | ||||
| import { SlashCommandOptionType } from '../types/slashCommands.ts' | ||||
| import type { Client } from '../client/mod.ts' | ||||
| import { RESTManager } from '../rest/mod.ts' | ||||
| import { SlashModule } from './slashModule.ts' | ||||
|  | @ -17,7 +18,9 @@ import { HarmonyEventEmitter } from '../utils/events.ts' | |||
| import { encodeText, decodeText } from '../utils/encoding.ts' | ||||
| import { SlashCommandsManager } from './slashCommand.ts' | ||||
| 
 | ||||
| export type SlashCommandHandlerCallback = (interaction: Interaction) => unknown | ||||
| export type SlashCommandHandlerCallback = ( | ||||
|   interaction: SlashCommandInteraction | ||||
| ) => unknown | ||||
| export interface SlashCommandHandler { | ||||
|   name: string | ||||
|   guild?: string | ||||
|  | @ -165,7 +168,9 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> { | |||
|   } | ||||
| 
 | ||||
|   /** Get Handler for an Interaction. Supports nested sub commands and sub command groups. */ | ||||
|   private _getCommand(i: Interaction): SlashCommandHandler | undefined { | ||||
|   private _getCommand( | ||||
|     i: SlashCommandInteraction | ||||
|   ): SlashCommandHandler | undefined { | ||||
|     return this.getHandlers().find((e) => { | ||||
|       const hasGroupOrParent = e.group !== undefined || e.parent !== undefined | ||||
|       const groupMatched = | ||||
|  | @ -196,28 +201,28 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> { | |||
|   } | ||||
| 
 | ||||
|   /** Process an incoming Interaction */ | ||||
|   private async _process(interaction: Interaction): Promise<void> { | ||||
|   private async _process( | ||||
|     interaction: Interaction | SlashCommandInteraction | ||||
|   ): Promise<void> { | ||||
|     if (!this.enabled) return | ||||
| 
 | ||||
|     if ( | ||||
|       interaction.type !== InteractionType.APPLICATION_COMMAND || | ||||
|       interaction.data === undefined | ||||
|     ) | ||||
|       return | ||||
|     if (interaction.type !== InteractionType.APPLICATION_COMMAND) return | ||||
| 
 | ||||
|     const cmd = | ||||
|       this._getCommand(interaction) ?? | ||||
|       this._getCommand(interaction as SlashCommandInteraction) ?? | ||||
|       this.getHandlers().find((e) => e.name === '*') | ||||
|     if (cmd?.group !== undefined) | ||||
|       interaction.data.options = interaction.data.options[0].options ?? [] | ||||
|       (interaction as SlashCommandInteraction).data.options = | ||||
|         (interaction as SlashCommandInteraction).data.options[0].options ?? [] | ||||
|     if (cmd?.parent !== undefined) | ||||
|       interaction.data.options = interaction.data.options[0].options ?? [] | ||||
|       (interaction as SlashCommandInteraction).data.options = | ||||
|         (interaction as SlashCommandInteraction).data.options[0].options ?? [] | ||||
| 
 | ||||
|     if (cmd === undefined) return | ||||
| 
 | ||||
|     await this.emit('interaction', interaction) | ||||
|     try { | ||||
|       await cmd.handler(interaction) | ||||
|       await cmd.handler(interaction as SlashCommandInteraction) | ||||
|     } catch (e) { | ||||
|       await this.emit('interactionError', e) | ||||
|     } | ||||
|  | @ -266,13 +271,15 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> { | |||
|       const payload: InteractionPayload = JSON.parse(decodeText(rawbody)) | ||||
| 
 | ||||
|       // TODO: Maybe fix all this hackery going on here?
 | ||||
|       const res = new Interaction(this as any, payload, { | ||||
|       let res | ||||
|       if (payload.type === InteractionType.APPLICATION_COMMAND) { | ||||
|         res = new SlashCommandInteraction(this as any, payload, { | ||||
|           // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
 | ||||
|           user: new User(this as any, (payload.member?.user ?? payload.user)!), | ||||
|           member: payload.member as any, | ||||
|           guild: payload.guild_id as any, | ||||
|           channel: payload.channel_id as any, | ||||
|         resolved: ((payload.data | ||||
|           resolved: (((payload.data as any) | ||||
|             ?.resolved as unknown) as InteractionApplicationCommandResolved) ?? { | ||||
|             users: {}, | ||||
|             members: {}, | ||||
|  | @ -280,6 +287,15 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> { | |||
|             channels: {} | ||||
|           } | ||||
|         }) | ||||
|       } else { | ||||
|         res = new Interaction(this as any, payload, { | ||||
|           // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
 | ||||
|           user: new User(this as any, (payload.member?.user ?? payload.user)!), | ||||
|           member: payload.member as any, | ||||
|           guild: payload.guild_id as any, | ||||
|           channel: payload.channel_id as any | ||||
|         }) | ||||
|       } | ||||
|       res._httpRespond = async (d: InteractionResponsePayload | FormData) => | ||||
|         await req.respond({ | ||||
|           status: 200, | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ import { | |||
|   SlashCommandOptionType, | ||||
|   SlashCommandPartial, | ||||
|   SlashCommandPayload | ||||
| } from '../types/slash.ts' | ||||
| } from '../types/slashCommands.ts' | ||||
| import { Collection } from '../utils/collection.ts' | ||||
| import type { SlashClient, SlashCommandHandlerCallback } from './slashClient.ts' | ||||
| 
 | ||||
|  |  | |||
|  | @ -1 +0,0 @@ | |||
| export {} | ||||
|  | @ -12,8 +12,6 @@ import type { | |||
| import { CHANNEL } from '../types/endpoint.ts' | ||||
| import getChannelByType from '../utils/channel.ts' | ||||
| import { BaseManager } from './base.ts' | ||||
| // Deno is bugged
 | ||||
| import {} from './_util.ts' | ||||
| 
 | ||||
| export type AllMessageOptions = MessageOptions | Embed | ||||
| 
 | ||||
|  |  | |||
|  | @ -30,11 +30,11 @@ import type { | |||
|   InviteWithMetadataPayload | ||||
| } from '../types/invite.ts' | ||||
| import type { RoleModifyPayload, RolePayload } from '../types/role.ts' | ||||
| import type { InteractionResponsePayload } from '../types/interactions.ts' | ||||
| import type { | ||||
|   InteractionResponsePayload, | ||||
|   SlashCommandPartial, | ||||
|   SlashCommandPayload | ||||
| } from '../types/slash.ts' | ||||
| } from '../types/slashCommands.ts' | ||||
| import type { TemplatePayload } from '../types/template.ts' | ||||
| import type { UserPayload } from '../types/user.ts' | ||||
| import type { VoiceRegion } from '../types/voice.ts' | ||||
|  |  | |||
|  | @ -13,7 +13,7 @@ export class DiscordAPIError extends Error { | |||
|     this.message = | ||||
|       typeof error === 'string' | ||||
|         ? `${error} ` | ||||
|         : `\n${error.method.toUpperCase()} ${error.url.slice(7)} returned ${ | ||||
|         : `\n${error.method.toUpperCase()} ${error.url} returned ${ | ||||
|             error.status | ||||
|           }\n(${error.code ?? 'unknown'}) ${error.message}${ | ||||
|             fmt.length === 0 | ||||
|  |  | |||
							
								
								
									
										348
									
								
								src/structures/interactions.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										348
									
								
								src/structures/interactions.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,348 @@ | |||
| import type { Client } from '../client/client.ts' | ||||
| import { | ||||
|   AllowedMentionsPayload, | ||||
|   ChannelTypes, | ||||
|   EmbedPayload, | ||||
|   MessageOptions | ||||
| } from '../types/channel.ts' | ||||
| import { INTERACTION_CALLBACK, WEBHOOK_MESSAGE } from '../types/endpoint.ts' | ||||
| import { | ||||
|   InteractionPayload, | ||||
|   InteractionResponseFlags, | ||||
|   InteractionResponsePayload, | ||||
|   InteractionResponseType, | ||||
|   InteractionType | ||||
| } from '../types/interactions.ts' | ||||
| import { | ||||
|   InteractionApplicationCommandData, | ||||
|   InteractionChannelPayload | ||||
| } from '../types/slashCommands.ts' | ||||
| import { Permissions } from '../utils/permissions.ts' | ||||
| import { SnowflakeBase } from './base.ts' | ||||
| import { Channel } from './channel.ts' | ||||
| import { Embed } from './embed.ts' | ||||
| import { Guild } from './guild.ts' | ||||
| import { GuildTextChannel } from './guildTextChannel.ts' | ||||
| import { Member } from './member.ts' | ||||
| import { Message } from './message.ts' | ||||
| import { TextChannel } from './textChannel.ts' | ||||
| import { User } from './user.ts' | ||||
| 
 | ||||
| interface WebhookMessageOptions extends MessageOptions { | ||||
|   embeds?: Array<Embed | EmbedPayload> | ||||
|   name?: string | ||||
|   avatar?: string | ||||
| } | ||||
| 
 | ||||
| type AllWebhookMessageOptions = string | WebhookMessageOptions | ||||
| 
 | ||||
| /** Interaction Message related Options */ | ||||
| export interface InteractionMessageOptions { | ||||
|   content?: string | ||||
|   embeds?: Array<Embed | EmbedPayload> | ||||
|   tts?: boolean | ||||
|   flags?: number | InteractionResponseFlags[] | ||||
|   allowedMentions?: AllowedMentionsPayload | ||||
|   /** Whether the Message Response should be Ephemeral (only visible to User) or not */ | ||||
|   ephemeral?: boolean | ||||
| } | ||||
| 
 | ||||
| export interface InteractionResponse extends InteractionMessageOptions { | ||||
|   /** Type of Interaction Response */ | ||||
|   type?: InteractionResponseType | ||||
| } | ||||
| 
 | ||||
| /** Represents a Channel Object for an Option in Slash Command */ | ||||
| export class InteractionChannel extends SnowflakeBase { | ||||
|   /** Name of the Channel */ | ||||
|   name: string | ||||
|   /** Channel Type */ | ||||
|   type: ChannelTypes | ||||
|   permissions: Permissions | ||||
| 
 | ||||
|   constructor(client: Client, data: InteractionChannelPayload) { | ||||
|     super(client) | ||||
|     this.id = data.id | ||||
|     this.name = data.name | ||||
|     this.type = data.type | ||||
|     this.permissions = new Permissions(data.permissions) | ||||
|   } | ||||
| 
 | ||||
|   /** Resolve to actual Channel object if present in Cache */ | ||||
|   async resolve<T = Channel>(): Promise<T | undefined> { | ||||
|     return this.client.channels.get<T>(this.id) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export class InteractionUser extends User { | ||||
|   member?: Member | ||||
| } | ||||
| 
 | ||||
| export class Interaction extends SnowflakeBase { | ||||
|   /** Type of Interaction */ | ||||
|   type: InteractionType | ||||
|   /** Interaction Token */ | ||||
|   token: string | ||||
|   /** Interaction ID */ | ||||
|   id: string | ||||
|   /** Channel in which Interaction was initiated */ | ||||
|   channel?: TextChannel | GuildTextChannel | ||||
|   /** Guild in which Interaction was initiated */ | ||||
|   guild?: Guild | ||||
|   /** Member object of who initiated the Interaction */ | ||||
|   member?: Member | ||||
|   /** User object of who invoked Interaction */ | ||||
|   user: User | ||||
|   /** Whether we have responded to Interaction or not */ | ||||
|   responded: boolean = false | ||||
|   /** Whether response was deferred or not */ | ||||
|   deferred: boolean = false | ||||
|   _httpRespond?: (d: InteractionResponsePayload) => unknown | ||||
|   _httpResponded?: boolean | ||||
|   applicationID: string | ||||
|   /** Data sent with Interaction. Only applies to Application Command */ | ||||
|   data?: InteractionApplicationCommandData | ||||
|   message?: Message | ||||
| 
 | ||||
|   constructor( | ||||
|     client: Client, | ||||
|     data: InteractionPayload, | ||||
|     others: { | ||||
|       channel?: TextChannel | GuildTextChannel | ||||
|       guild?: Guild | ||||
|       member?: Member | ||||
|       user: User | ||||
|       message?: Message | ||||
|     } | ||||
|   ) { | ||||
|     super(client) | ||||
|     this.type = data.type | ||||
|     this.token = data.token | ||||
|     this.member = others.member | ||||
|     this.id = data.id | ||||
|     this.applicationID = data.application_id | ||||
|     this.user = others.user | ||||
|     this.data = data.data | ||||
|     this.guild = others.guild | ||||
|     this.channel = others.channel | ||||
|     this.message = others.message | ||||
|   } | ||||
| 
 | ||||
|   /** Respond to an Interaction */ | ||||
|   async respond(data: InteractionResponse): Promise<Interaction> { | ||||
|     if (this.responded) throw new Error('Already responded to Interaction') | ||||
|     let flags = 0 | ||||
|     if (data.ephemeral === true) flags |= InteractionResponseFlags.EPHEMERAL | ||||
|     if (data.flags !== undefined) { | ||||
|       if (Array.isArray(data.flags)) | ||||
|         flags = data.flags.reduce((p, a) => p | a, flags) | ||||
|       else if (typeof data.flags === 'number') flags |= data.flags | ||||
|     } | ||||
|     const payload: InteractionResponsePayload = { | ||||
|       type: data.type ?? InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, | ||||
|       data: | ||||
|         data.type === undefined || | ||||
|         data.type === InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE | ||||
|           ? { | ||||
|               content: data.content ?? '', | ||||
|               embeds: data.embeds, | ||||
|               tts: data.tts ?? false, | ||||
|               flags, | ||||
|               allowed_mentions: data.allowedMentions ?? undefined | ||||
|             } | ||||
|           : undefined | ||||
|     } | ||||
| 
 | ||||
|     if (this._httpRespond !== undefined && this._httpResponded !== true) { | ||||
|       this._httpResponded = true | ||||
|       await this._httpRespond(payload) | ||||
|     } else | ||||
|       await this.client.rest.post( | ||||
|         INTERACTION_CALLBACK(this.id, this.token), | ||||
|         payload | ||||
|       ) | ||||
|     this.responded = true | ||||
| 
 | ||||
|     return this | ||||
|   } | ||||
| 
 | ||||
|   /** Defer the Interaction i.e. let the user know bot is processing and will respond later. You only have 15 minutes to edit the response! */ | ||||
|   async defer(ephemeral = false): Promise<Interaction> { | ||||
|     await this.respond({ | ||||
|       type: InteractionResponseType.DEFERRED_CHANNEL_MESSAGE, | ||||
|       flags: ephemeral ? 1 << 6 : 0 | ||||
|     }) | ||||
|     this.deferred = true | ||||
|     return this | ||||
|   } | ||||
| 
 | ||||
|   /** Reply with a Message to the Interaction */ | ||||
|   async reply(content: string): Promise<Interaction> | ||||
|   async reply(options: InteractionMessageOptions): Promise<Interaction> | ||||
|   async reply( | ||||
|     content: string, | ||||
|     options: InteractionMessageOptions | ||||
|   ): Promise<Interaction> | ||||
|   async reply( | ||||
|     content: string | InteractionMessageOptions, | ||||
|     messageOptions?: InteractionMessageOptions | ||||
|   ): Promise<Interaction> { | ||||
|     let options: InteractionMessageOptions | undefined = | ||||
|       typeof content === 'object' ? content : messageOptions | ||||
|     if ( | ||||
|       typeof content === 'object' && | ||||
|       messageOptions !== undefined && | ||||
|       options !== undefined | ||||
|     ) | ||||
|       Object.assign(options, messageOptions) | ||||
|     if (options === undefined) options = {} | ||||
|     if (typeof content === 'string') Object.assign(options, { content }) | ||||
| 
 | ||||
|     if (this.deferred && this.responded) { | ||||
|       await this.editResponse({ | ||||
|         content: options.content, | ||||
|         embeds: options.embeds, | ||||
|         flags: options.flags, | ||||
|         allowedMentions: options.allowedMentions | ||||
|       }) | ||||
|     } else | ||||
|       await this.respond( | ||||
|         Object.assign(options, { | ||||
|           type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE | ||||
|         }) | ||||
|       ) | ||||
| 
 | ||||
|     return this | ||||
|   } | ||||
| 
 | ||||
|   /** Edit the original Interaction response */ | ||||
|   async editResponse(data: { | ||||
|     content?: string | ||||
|     embeds?: Array<Embed | EmbedPayload> | ||||
|     flags?: number | number[] | ||||
|     allowedMentions?: AllowedMentionsPayload | ||||
|   }): Promise<Interaction> { | ||||
|     const url = WEBHOOK_MESSAGE(this.applicationID, this.token, '@original') | ||||
|     await this.client.rest.patch(url, { | ||||
|       content: data.content ?? '', | ||||
|       embeds: data.embeds ?? [], | ||||
|       flags: | ||||
|         typeof data.flags === 'object' | ||||
|           ? data.flags.reduce((p, a) => p | a, 0) | ||||
|           : data.flags, | ||||
|       allowed_mentions: data.allowedMentions | ||||
|     }) | ||||
|     return this | ||||
|   } | ||||
| 
 | ||||
|   /** Delete the original Interaction Response */ | ||||
|   async deleteResponse(): Promise<Interaction> { | ||||
|     const url = WEBHOOK_MESSAGE(this.applicationID, this.token, '@original') | ||||
|     await this.client.rest.delete(url) | ||||
|     return this | ||||
|   } | ||||
| 
 | ||||
|   get url(): string { | ||||
|     return `https://discord.com/api/v8/webhooks/${this.applicationID}/${this.token}` | ||||
|   } | ||||
| 
 | ||||
|   /** Send a followup message */ | ||||
|   async send( | ||||
|     text?: string | AllWebhookMessageOptions, | ||||
|     option?: AllWebhookMessageOptions | ||||
|   ): Promise<Message> { | ||||
|     if (typeof text === 'object') { | ||||
|       option = text | ||||
|       text = undefined | ||||
|     } | ||||
| 
 | ||||
|     if (text === undefined && option === undefined) { | ||||
|       throw new Error('Either text or option is necessary.') | ||||
|     } | ||||
| 
 | ||||
|     if (option instanceof Embed) | ||||
|       option = { | ||||
|         embeds: [option] | ||||
|       } | ||||
| 
 | ||||
|     const payload: any = { | ||||
|       content: text, | ||||
|       embeds: | ||||
|         (option as WebhookMessageOptions)?.embed !== undefined | ||||
|           ? [(option as WebhookMessageOptions).embed] | ||||
|           : (option as WebhookMessageOptions)?.embeds !== undefined | ||||
|           ? (option as WebhookMessageOptions).embeds | ||||
|           : undefined, | ||||
|       file: (option as WebhookMessageOptions)?.file, | ||||
|       files: (option as WebhookMessageOptions)?.files, | ||||
|       tts: (option as WebhookMessageOptions)?.tts, | ||||
|       allowed_mentions: (option as WebhookMessageOptions)?.allowedMentions | ||||
|     } | ||||
| 
 | ||||
|     if ((option as WebhookMessageOptions)?.name !== undefined) { | ||||
|       payload.username = (option as WebhookMessageOptions)?.name | ||||
|     } | ||||
| 
 | ||||
|     if ((option as WebhookMessageOptions)?.avatar !== undefined) { | ||||
|       payload.avatar = (option as WebhookMessageOptions)?.avatar | ||||
|     } | ||||
| 
 | ||||
|     if ( | ||||
|       payload.embeds !== undefined && | ||||
|       payload.embeds instanceof Array && | ||||
|       payload.embeds.length > 10 | ||||
|     ) | ||||
|       throw new Error( | ||||
|         `Cannot send more than 10 embeds through Interaction Webhook` | ||||
|       ) | ||||
| 
 | ||||
|     const resp = await this.client.rest.post(`${this.url}?wait=true`, payload) | ||||
| 
 | ||||
|     const res = new Message( | ||||
|       this.client, | ||||
|       resp, | ||||
|       (this as unknown) as TextChannel, | ||||
|       (this as unknown) as User | ||||
|     ) | ||||
|     await res.mentions.fromPayload(resp) | ||||
|     return res | ||||
|   } | ||||
| 
 | ||||
|   /** Edit a Followup message */ | ||||
|   async editMessage( | ||||
|     msg: Message | string, | ||||
|     data: { | ||||
|       content?: string | ||||
|       embeds?: Array<Embed | EmbedPayload> | ||||
|       file?: any | ||||
|       allowed_mentions?: { | ||||
|         parse?: string | ||||
|         roles?: string[] | ||||
|         users?: string[] | ||||
|         everyone?: boolean | ||||
|       } | ||||
|     } | ||||
|   ): Promise<Interaction> { | ||||
|     await this.client.rest.patch( | ||||
|       WEBHOOK_MESSAGE( | ||||
|         this.applicationID, | ||||
|         this.token ?? this.client.token, | ||||
|         typeof msg === 'string' ? msg : msg.id | ||||
|       ), | ||||
|       data | ||||
|     ) | ||||
|     return this | ||||
|   } | ||||
| 
 | ||||
|   /** Delete a follow-up Message */ | ||||
|   async deleteMessage(msg: Message | string): Promise<Interaction> { | ||||
|     await this.client.rest.delete( | ||||
|       WEBHOOK_MESSAGE( | ||||
|         this.applicationID, | ||||
|         this.token ?? this.client.token, | ||||
|         typeof msg === 'string' ? msg : msg.id | ||||
|       ) | ||||
|     ) | ||||
|     return this | ||||
|   } | ||||
| } | ||||
|  | @ -20,7 +20,7 @@ import type { Guild } from './guild.ts' | |||
| import { MessageReactionsManager } from '../managers/messageReactions.ts' | ||||
| import { MessageSticker } from './messageSticker.ts' | ||||
| import type { Emoji } from './emoji.ts' | ||||
| import type { InteractionType } from '../types/slash.ts' | ||||
| import type { InteractionType } from '../types/interactions.ts' | ||||
| import { encodeText } from '../utils/encoding.ts' | ||||
| 
 | ||||
| type AllMessageOptions = MessageOptions | Embed | ||||
|  |  | |||
|  | @ -1,80 +1,22 @@ | |||
| import type { Client } from '../client/mod.ts' | ||||
| import type { | ||||
|   AllowedMentionsPayload, | ||||
|   ChannelTypes, | ||||
|   EmbedPayload, | ||||
|   MessageOptions | ||||
| } from '../types/channel.ts' | ||||
| import { INTERACTION_CALLBACK, WEBHOOK_MESSAGE } from '../types/endpoint.ts' | ||||
| import { InteractionPayload } from '../types/interactions.ts' | ||||
| import { | ||||
|   InteractionApplicationCommandData, | ||||
|   InteractionApplicationCommandOption, | ||||
|   InteractionChannelPayload, | ||||
|   InteractionPayload, | ||||
|   InteractionResponseFlags, | ||||
|   InteractionResponsePayload, | ||||
|   InteractionResponseType, | ||||
|   InteractionType, | ||||
|   SlashCommandOptionType | ||||
| } from '../types/slash.ts' | ||||
| } from '../types/slashCommands.ts' | ||||
| import type { Dict } from '../utils/dict.ts' | ||||
| import { Permissions } from '../utils/permissions.ts' | ||||
| import { SnowflakeBase } from './base.ts' | ||||
| import type { Channel } from './channel.ts' | ||||
| import { Embed } from './embed.ts' | ||||
| import type { Guild } from './guild.ts' | ||||
| import type { GuildTextChannel } from './guildTextChannel.ts' | ||||
| import type { Member } from './member.ts' | ||||
| import { Message } from './message.ts' | ||||
| import type { Role } from './role.ts' | ||||
| import type { TextChannel } from './textChannel.ts' | ||||
| import { User } from './user.ts' | ||||
| 
 | ||||
| interface WebhookMessageOptions extends MessageOptions { | ||||
|   embeds?: Array<Embed | EmbedPayload> | ||||
|   name?: string | ||||
|   avatar?: string | ||||
| } | ||||
| 
 | ||||
| type AllWebhookMessageOptions = string | WebhookMessageOptions | ||||
| 
 | ||||
| /** Interaction Message related Options */ | ||||
| export interface InteractionMessageOptions { | ||||
|   content?: string | ||||
|   embeds?: Array<Embed | EmbedPayload> | ||||
|   tts?: boolean | ||||
|   flags?: number | InteractionResponseFlags[] | ||||
|   allowedMentions?: AllowedMentionsPayload | ||||
|   /** Whether the Message Response should be Ephemeral (only visible to User) or not */ | ||||
|   ephemeral?: boolean | ||||
| } | ||||
| 
 | ||||
| export interface InteractionResponse extends InteractionMessageOptions { | ||||
|   /** Type of Interaction Response */ | ||||
|   type?: InteractionResponseType | ||||
| } | ||||
| 
 | ||||
| /** Represents a Channel Object for an Option in Slash Command */ | ||||
| export class InteractionChannel extends SnowflakeBase { | ||||
|   /** Name of the Channel */ | ||||
|   name: string | ||||
|   /** Channel Type */ | ||||
|   type: ChannelTypes | ||||
|   permissions: Permissions | ||||
| 
 | ||||
|   constructor(client: Client, data: InteractionChannelPayload) { | ||||
|     super(client) | ||||
|     this.id = data.id | ||||
|     this.name = data.name | ||||
|     this.type = data.type | ||||
|     this.permissions = new Permissions(data.permissions) | ||||
|   } | ||||
| 
 | ||||
|   /** Resolve to actual Channel object if present in Cache */ | ||||
|   async resolve<T = Channel>(): Promise<T | undefined> { | ||||
|     return this.client.channels.get<T>(this.id) | ||||
|   } | ||||
| } | ||||
| import { | ||||
|   InteractionUser, | ||||
|   InteractionChannel, | ||||
|   Interaction | ||||
| } from './interactions.ts' | ||||
| 
 | ||||
| export interface InteractionApplicationCommandResolved { | ||||
|   users: Dict<InteractionUser> | ||||
|  | @ -83,36 +25,11 @@ export interface InteractionApplicationCommandResolved { | |||
|   roles: Dict<Role> | ||||
| } | ||||
| 
 | ||||
| export class InteractionUser extends User { | ||||
|   member?: Member | ||||
| } | ||||
| 
 | ||||
| export class Interaction extends SnowflakeBase { | ||||
|   /** Type of Interaction */ | ||||
|   type: InteractionType | ||||
|   /** Interaction Token */ | ||||
|   token: string | ||||
|   /** Interaction ID */ | ||||
|   id: string | ||||
| export class SlashCommandInteraction extends Interaction { | ||||
|   /** Data sent with Interaction. Only applies to Application Command */ | ||||
|   data?: InteractionApplicationCommandData | ||||
|   /** Channel in which Interaction was initiated */ | ||||
|   channel?: TextChannel | GuildTextChannel | ||||
|   /** Guild in which Interaction was initiated */ | ||||
|   guild?: Guild | ||||
|   /** Member object of who initiated the Interaction */ | ||||
|   member?: Member | ||||
|   /** User object of who invoked Interaction */ | ||||
|   user: User | ||||
|   /** Whether we have responded to Interaction or not */ | ||||
|   responded: boolean = false | ||||
|   data: InteractionApplicationCommandData | ||||
|   /** Resolved data for Snowflakes in Slash Command Arguments */ | ||||
|   resolved: InteractionApplicationCommandResolved | ||||
|   /** Whether response was deferred or not */ | ||||
|   deferred: boolean = false | ||||
|   _httpRespond?: (d: InteractionResponsePayload) => unknown | ||||
|   _httpResponded?: boolean | ||||
|   applicationID: string | ||||
| 
 | ||||
|   constructor( | ||||
|     client: Client, | ||||
|  | @ -125,26 +42,19 @@ export class Interaction extends SnowflakeBase { | |||
|       resolved: InteractionApplicationCommandResolved | ||||
|     } | ||||
|   ) { | ||||
|     super(client) | ||||
|     this.type = data.type | ||||
|     this.token = data.token | ||||
|     this.member = others.member | ||||
|     this.id = data.id | ||||
|     this.applicationID = data.application_id | ||||
|     this.user = others.user | ||||
|     this.data = data.data | ||||
|     this.guild = others.guild | ||||
|     this.channel = others.channel | ||||
|     super(client, data, others) | ||||
|     // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
 | ||||
|     this.data = data.data as InteractionApplicationCommandData | ||||
|     this.resolved = others.resolved | ||||
|   } | ||||
| 
 | ||||
|   /** Name of the Command Used (may change with future additions to Interactions!) */ | ||||
|   get name(): string | undefined { | ||||
|     return this.data?.name | ||||
|   get name(): string { | ||||
|     return this.data.name | ||||
|   } | ||||
| 
 | ||||
|   get options(): InteractionApplicationCommandOption[] { | ||||
|     return this.data?.options ?? [] | ||||
|     return this.data.options ?? [] | ||||
|   } | ||||
| 
 | ||||
|   /** Get an option by name */ | ||||
|  | @ -162,222 +72,4 @@ export class Interaction extends SnowflakeBase { | |||
|       return this.resolved.channels[op.value] as any | ||||
|     else return op.value | ||||
|   } | ||||
| 
 | ||||
|   /** Respond to an Interaction */ | ||||
|   async respond(data: InteractionResponse): Promise<Interaction> { | ||||
|     if (this.responded) throw new Error('Already responded to Interaction') | ||||
|     let flags = 0 | ||||
|     if (data.ephemeral === true) flags |= InteractionResponseFlags.EPHEMERAL | ||||
|     if (data.flags !== undefined) { | ||||
|       if (Array.isArray(data.flags)) | ||||
|         flags = data.flags.reduce((p, a) => p | a, flags) | ||||
|       else if (typeof data.flags === 'number') flags |= data.flags | ||||
|     } | ||||
|     const payload: InteractionResponsePayload = { | ||||
|       type: data.type ?? InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, | ||||
|       data: | ||||
|         data.type === undefined || | ||||
|         data.type === InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE | ||||
|           ? { | ||||
|               content: data.content ?? '', | ||||
|               embeds: data.embeds, | ||||
|               tts: data.tts ?? false, | ||||
|               flags, | ||||
|               allowed_mentions: data.allowedMentions ?? undefined | ||||
|             } | ||||
|           : undefined | ||||
|     } | ||||
| 
 | ||||
|     if (this._httpRespond !== undefined && this._httpResponded !== true) { | ||||
|       this._httpResponded = true | ||||
|       await this._httpRespond(payload) | ||||
|     } else | ||||
|       await this.client.rest.post( | ||||
|         INTERACTION_CALLBACK(this.id, this.token), | ||||
|         payload | ||||
|       ) | ||||
|     this.responded = true | ||||
| 
 | ||||
|     return this | ||||
|   } | ||||
| 
 | ||||
|   /** Defer the Interaction i.e. let the user know bot is processing and will respond later. You only have 15 minutes to edit the response! */ | ||||
|   async defer(ephemeral = false): Promise<Interaction> { | ||||
|     await this.respond({ | ||||
|       type: InteractionResponseType.DEFERRED_CHANNEL_MESSAGE, | ||||
|       flags: ephemeral ? 1 << 6 : 0 | ||||
|     }) | ||||
|     this.deferred = true | ||||
|     return this | ||||
|   } | ||||
| 
 | ||||
|   /** Reply with a Message to the Interaction */ | ||||
|   async reply(content: string): Promise<Interaction> | ||||
|   async reply(options: InteractionMessageOptions): Promise<Interaction> | ||||
|   async reply( | ||||
|     content: string, | ||||
|     options: InteractionMessageOptions | ||||
|   ): Promise<Interaction> | ||||
|   async reply( | ||||
|     content: string | InteractionMessageOptions, | ||||
|     messageOptions?: InteractionMessageOptions | ||||
|   ): Promise<Interaction> { | ||||
|     let options: InteractionMessageOptions | undefined = | ||||
|       typeof content === 'object' ? content : messageOptions | ||||
|     if ( | ||||
|       typeof content === 'object' && | ||||
|       messageOptions !== undefined && | ||||
|       options !== undefined | ||||
|     ) | ||||
|       Object.assign(options, messageOptions) | ||||
|     if (options === undefined) options = {} | ||||
|     if (typeof content === 'string') Object.assign(options, { content }) | ||||
| 
 | ||||
|     if (this.deferred && this.responded) { | ||||
|       await this.editResponse({ | ||||
|         content: options.content, | ||||
|         embeds: options.embeds, | ||||
|         flags: options.flags, | ||||
|         allowedMentions: options.allowedMentions | ||||
|       }) | ||||
|     } else | ||||
|       await this.respond( | ||||
|         Object.assign(options, { | ||||
|           type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE | ||||
|         }) | ||||
|       ) | ||||
| 
 | ||||
|     return this | ||||
|   } | ||||
| 
 | ||||
|   /** Edit the original Interaction response */ | ||||
|   async editResponse(data: { | ||||
|     content?: string | ||||
|     embeds?: Array<Embed | EmbedPayload> | ||||
|     flags?: number | number[] | ||||
|     allowedMentions?: AllowedMentionsPayload | ||||
|   }): Promise<Interaction> { | ||||
|     const url = WEBHOOK_MESSAGE(this.applicationID, this.token, '@original') | ||||
|     await this.client.rest.patch(url, { | ||||
|       content: data.content ?? '', | ||||
|       embeds: data.embeds ?? [], | ||||
|       flags: | ||||
|         typeof data.flags === 'object' | ||||
|           ? data.flags.reduce((p, a) => p | a, 0) | ||||
|           : data.flags, | ||||
|       allowed_mentions: data.allowedMentions | ||||
|     }) | ||||
|     return this | ||||
|   } | ||||
| 
 | ||||
|   /** Delete the original Interaction Response */ | ||||
|   async deleteResponse(): Promise<Interaction> { | ||||
|     const url = WEBHOOK_MESSAGE(this.applicationID, this.token, '@original') | ||||
|     await this.client.rest.delete(url) | ||||
|     return this | ||||
|   } | ||||
| 
 | ||||
|   get url(): string { | ||||
|     return `https://discord.com/api/v8/webhooks/${this.applicationID}/${this.token}` | ||||
|   } | ||||
| 
 | ||||
|   /** Send a followup message */ | ||||
|   async send( | ||||
|     text?: string | AllWebhookMessageOptions, | ||||
|     option?: AllWebhookMessageOptions | ||||
|   ): Promise<Message> { | ||||
|     if (typeof text === 'object') { | ||||
|       option = text | ||||
|       text = undefined | ||||
|     } | ||||
| 
 | ||||
|     if (text === undefined && option === undefined) { | ||||
|       throw new Error('Either text or option is necessary.') | ||||
|     } | ||||
| 
 | ||||
|     if (option instanceof Embed) | ||||
|       option = { | ||||
|         embeds: [option] | ||||
|       } | ||||
| 
 | ||||
|     const payload: any = { | ||||
|       content: text, | ||||
|       embeds: | ||||
|         (option as WebhookMessageOptions)?.embed !== undefined | ||||
|           ? [(option as WebhookMessageOptions).embed] | ||||
|           : (option as WebhookMessageOptions)?.embeds !== undefined | ||||
|           ? (option as WebhookMessageOptions).embeds | ||||
|           : undefined, | ||||
|       file: (option as WebhookMessageOptions)?.file, | ||||
|       files: (option as WebhookMessageOptions)?.files, | ||||
|       tts: (option as WebhookMessageOptions)?.tts, | ||||
|       allowed_mentions: (option as WebhookMessageOptions)?.allowedMentions | ||||
|     } | ||||
| 
 | ||||
|     if ((option as WebhookMessageOptions)?.name !== undefined) { | ||||
|       payload.username = (option as WebhookMessageOptions)?.name | ||||
|     } | ||||
| 
 | ||||
|     if ((option as WebhookMessageOptions)?.avatar !== undefined) { | ||||
|       payload.avatar = (option as WebhookMessageOptions)?.avatar | ||||
|     } | ||||
| 
 | ||||
|     if ( | ||||
|       payload.embeds !== undefined && | ||||
|       payload.embeds instanceof Array && | ||||
|       payload.embeds.length > 10 | ||||
|     ) | ||||
|       throw new Error( | ||||
|         `Cannot send more than 10 embeds through Interaction Webhook` | ||||
|       ) | ||||
| 
 | ||||
|     const resp = await this.client.rest.post(`${this.url}?wait=true`, payload) | ||||
| 
 | ||||
|     const res = new Message( | ||||
|       this.client, | ||||
|       resp, | ||||
|       (this as unknown) as TextChannel, | ||||
|       (this as unknown) as User | ||||
|     ) | ||||
|     await res.mentions.fromPayload(resp) | ||||
|     return res | ||||
|   } | ||||
| 
 | ||||
|   /** Edit a Followup message */ | ||||
|   async editMessage( | ||||
|     msg: Message | string, | ||||
|     data: { | ||||
|       content?: string | ||||
|       embeds?: Array<Embed | EmbedPayload> | ||||
|       file?: any | ||||
|       allowed_mentions?: { | ||||
|         parse?: string | ||||
|         roles?: string[] | ||||
|         users?: string[] | ||||
|         everyone?: boolean | ||||
|       } | ||||
|     } | ||||
|   ): Promise<Interaction> { | ||||
|     await this.client.rest.patch( | ||||
|       WEBHOOK_MESSAGE( | ||||
|         this.applicationID, | ||||
|         this.token ?? this.client.token, | ||||
|         typeof msg === 'string' ? msg : msg.id | ||||
|       ), | ||||
|       data | ||||
|     ) | ||||
|     return this | ||||
|   } | ||||
| 
 | ||||
|   /** Delete a follow-up Message */ | ||||
|   async deleteMessage(msg: Message | string): Promise<Interaction> { | ||||
|     await this.client.rest.delete( | ||||
|       WEBHOOK_MESSAGE( | ||||
|         this.applicationID, | ||||
|         this.token ?? this.client.token, | ||||
|         typeof msg === 'string' ? msg : msg.id | ||||
|       ) | ||||
|     ) | ||||
|     return this | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ import type { Role } from '../structures/role.ts' | |||
| import type { Permissions } from '../utils/permissions.ts' | ||||
| import type { EmojiPayload } from './emoji.ts' | ||||
| import type { MemberPayload } from './guild.ts' | ||||
| import type { InteractionType } from './slash.ts' | ||||
| import type { InteractionType } from './interactions.ts' | ||||
| import type { UserPayload } from './user.ts' | ||||
| 
 | ||||
| export interface ChannelPayload { | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ import type { | |||
|   ClientStatus | ||||
| } from './presence.ts' | ||||
| import type { RolePayload } from './role.ts' | ||||
| import type { SlashCommandPayload } from './slash.ts' | ||||
| import type { SlashCommandPayload } from './slashCommands.ts' | ||||
| import type { UserPayload } from './user.ts' | ||||
| 
 | ||||
| /** | ||||
|  |  | |||
							
								
								
									
										77
									
								
								src/types/interactions.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/types/interactions.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,77 @@ | |||
| import { | ||||
|   AllowedMentionsPayload, | ||||
|   EmbedPayload, | ||||
|   MessagePayload | ||||
| } from './channel.ts' | ||||
| import type { MemberPayload } from './guild.ts' | ||||
| import type { InteractionApplicationCommandData } from './slashCommands.ts' | ||||
| import type { UserPayload } from './user.ts' | ||||
| 
 | ||||
| export enum InteractionType { | ||||
|   /** Ping sent by the API (HTTP-only) */ | ||||
|   PING = 1, | ||||
|   /** Slash Command Interaction */ | ||||
|   APPLICATION_COMMAND = 2 | ||||
| } | ||||
| 
 | ||||
| export interface InteractionMemberPayload extends MemberPayload { | ||||
|   /** Permissions of the Member who initiated Interaction (Guild-only) */ | ||||
|   permissions: string | ||||
| } | ||||
| 
 | ||||
| export interface InteractionPayload { | ||||
|   /** Type of the Interaction */ | ||||
|   type: InteractionType | ||||
|   /** Token of the Interaction to respond */ | ||||
|   token: string | ||||
|   /** Member object of user who invoked */ | ||||
|   member?: InteractionMemberPayload | ||||
|   /** User who initiated Interaction (only in DMs) */ | ||||
|   user?: UserPayload | ||||
|   /** ID of the Interaction */ | ||||
|   id: string | ||||
|   /** | ||||
|    * Data sent with the interaction. Undefined only when Interaction is PING (http-only).* | ||||
|    */ | ||||
|   data?: InteractionApplicationCommandData | ||||
|   /** ID of the Guild in which Interaction was invoked */ | ||||
|   guild_id?: string | ||||
|   /** ID of the Channel in which Interaction was invoked */ | ||||
|   channel_id?: string | ||||
|   /** Application ID of the Client who received interaction */ | ||||
|   application_id: string | ||||
|   /** Message ID if the Interaction was of type MESSAGE_COMPONENT */ | ||||
|   message?: MessagePayload | ||||
| } | ||||
| 
 | ||||
| export enum InteractionResponseType { | ||||
|   /** Just ack a ping, Http-only. */ | ||||
|   PONG = 1, | ||||
|   /** Send a channel message as response. */ | ||||
|   CHANNEL_MESSAGE_WITH_SOURCE = 4, | ||||
|   /** Let the user know bot is processing ("thinking") and you can edit the response later */ | ||||
|   DEFERRED_CHANNEL_MESSAGE = 5 | ||||
| } | ||||
| 
 | ||||
| export interface InteractionResponsePayload { | ||||
|   /** Type of the response */ | ||||
|   type: InteractionResponseType | ||||
|   /** Data to be sent with response. Optional for types: Pong, Acknowledge, Ack with Source */ | ||||
|   data?: InteractionResponseDataPayload | ||||
| } | ||||
| 
 | ||||
| export interface InteractionResponseDataPayload { | ||||
|   tts?: boolean | ||||
|   /** Text content of the Response (Message) */ | ||||
|   content: string | ||||
|   /** Upto 10 Embed Objects to send with Response */ | ||||
|   embeds?: EmbedPayload[] | ||||
|   /** Allowed Mentions object */ | ||||
|   allowed_mentions?: AllowedMentionsPayload | ||||
|   flags?: number | ||||
| } | ||||
| 
 | ||||
| export enum InteractionResponseFlags { | ||||
|   /** A Message which is only visible to Interaction User. */ | ||||
|   EPHEMERAL = 1 << 6 | ||||
| } | ||||
|  | @ -1,9 +1,5 @@ | |||
| import type { Dict } from '../utils/dict.ts' | ||||
| import type { | ||||
|   AllowedMentionsPayload, | ||||
|   ChannelTypes, | ||||
|   EmbedPayload | ||||
| } from './channel.ts' | ||||
| import type { ChannelTypes } from './channel.ts' | ||||
| import type { MemberPayload } from './guild.ts' | ||||
| import type { RolePayload } from './role.ts' | ||||
| import type { UserPayload } from './user.ts' | ||||
|  | @ -44,40 +40,6 @@ export interface InteractionApplicationCommandData { | |||
|   resolved?: InteractionApplicationCommandResolvedPayload | ||||
| } | ||||
| 
 | ||||
| export enum InteractionType { | ||||
|   /** Ping sent by the API (HTTP-only) */ | ||||
|   PING = 1, | ||||
|   /** Slash Command Interaction */ | ||||
|   APPLICATION_COMMAND = 2 | ||||
| } | ||||
| 
 | ||||
| export interface InteractionMemberPayload extends MemberPayload { | ||||
|   /** Permissions of the Member who initiated Interaction (Guild-only) */ | ||||
|   permissions: string | ||||
| } | ||||
| 
 | ||||
| export interface InteractionPayload { | ||||
|   /** Type of the Interaction */ | ||||
|   type: InteractionType | ||||
|   /** Token of the Interaction to respond */ | ||||
|   token: string | ||||
|   /** Member object of user who invoked */ | ||||
|   member?: InteractionMemberPayload | ||||
|   /** User who initiated Interaction (only in DMs) */ | ||||
|   user?: UserPayload | ||||
|   /** ID of the Interaction */ | ||||
|   id: string | ||||
|   /** | ||||
|    * Data sent with the interaction. Undefined only when Interaction is not Slash Command.* | ||||
|    */ | ||||
|   data?: InteractionApplicationCommandData | ||||
|   /** ID of the Guild in which Interaction was invoked */ | ||||
|   guild_id?: string | ||||
|   /** ID of the Channel in which Interaction was invoked */ | ||||
|   channel_id?: string | ||||
|   application_id: string | ||||
| } | ||||
| 
 | ||||
| export interface SlashCommandChoice { | ||||
|   /** (Display) name of the Choice */ | ||||
|   name: string | ||||
|  | @ -131,35 +93,3 @@ export interface SlashCommandPayload extends SlashCommandPartial { | |||
|   /** Application ID */ | ||||
|   application_id: string | ||||
| } | ||||
| 
 | ||||
| export enum InteractionResponseType { | ||||
|   /** Just ack a ping, Http-only. */ | ||||
|   PONG = 1, | ||||
|   /** Send a channel message as response. */ | ||||
|   CHANNEL_MESSAGE_WITH_SOURCE = 4, | ||||
|   /** Let the user know bot is processing ("thinking") and you can edit the response later */ | ||||
|   DEFERRED_CHANNEL_MESSAGE = 5 | ||||
| } | ||||
| 
 | ||||
| export interface InteractionResponsePayload { | ||||
|   /** Type of the response */ | ||||
|   type: InteractionResponseType | ||||
|   /** Data to be sent with response. Optional for types: Pong, Acknowledge, Ack with Source */ | ||||
|   data?: InteractionResponseDataPayload | ||||
| } | ||||
| 
 | ||||
| export interface InteractionResponseDataPayload { | ||||
|   tts?: boolean | ||||
|   /** Text content of the Response (Message) */ | ||||
|   content: string | ||||
|   /** Upto 10 Embed Objects to send with Response */ | ||||
|   embeds?: EmbedPayload[] | ||||
|   /** Allowed Mentions object */ | ||||
|   allowed_mentions?: AllowedMentionsPayload | ||||
|   flags?: number | ||||
| } | ||||
| 
 | ||||
| export enum InteractionResponseFlags { | ||||
|   /** A Message which is only visible to Interaction User. */ | ||||
|   EPHEMERAL = 1 << 6 | ||||
| } | ||||
|  | @ -12,7 +12,7 @@ export function simplifyAPIError(errors: any): SimplifiedError { | |||
|         const arrayIndex = !isNaN(Number(obj[0])) | ||||
|         if (arrayIndex) obj[0] = `[${obj[0]}]` | ||||
|         if (acum !== '' && !arrayIndex) acum += '.' | ||||
|         fmt(obj[1], (acum += obj[0])) | ||||
|         fmt(obj[1], acum + obj[0]) | ||||
|       }) | ||||
|     } | ||||
|   } | ||||
|  |  | |||
							
								
								
									
										9
									
								
								src/utils/interactions.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/utils/interactions.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | |||
| import { InteractionType } from '../../mod.ts' | ||||
| import { Interaction } from '../structures/interactions.ts' | ||||
| import { SlashCommandInteraction } from '../structures/slash.ts' | ||||
| 
 | ||||
| export function isSlashCommandInteraction( | ||||
|   d: Interaction | ||||
| ): d is SlashCommandInteraction { | ||||
|   return d.type === InteractionType.APPLICATION_COMMAND | ||||
| } | ||||
|  | @ -8,12 +8,12 @@ import { | |||
|   CommandContext, | ||||
|   Extension, | ||||
|   Collection, | ||||
|   GuildTextChannel | ||||
| } from '../../mod.ts' | ||||
|   GuildTextChannel, | ||||
|   slash, | ||||
|   SlashCommandInteraction | ||||
| } from '../mod.ts' | ||||
| import { LL_IP, LL_PASS, LL_PORT, TOKEN } from './config.ts' | ||||
| import { Manager, Player } from 'https://deno.land/x/lavadeno/mod.ts' | ||||
| import { Interaction } from '../structures/slash.ts' | ||||
| import { slash } from '../client/mod.ts' | ||||
| // import { SlashCommandOptionType } from '../types/slash.ts'
 | ||||
| 
 | ||||
| export const nodes = [ | ||||
|  | @ -58,12 +58,12 @@ class MyClient extends CommandClient { | |||
|   } | ||||
| 
 | ||||
|   @subslash('cmd', 'sub-cmd-no-grp') | ||||
|   subCmdNoGroup(d: Interaction): void { | ||||
|   subCmdNoGroup(d: SlashCommandInteraction): void { | ||||
|     d.respond({ content: 'sub-cmd-no-group worked' }) | ||||
|   } | ||||
| 
 | ||||
|   @groupslash('cmd', 'sub-cmd-group', 'sub-cmd') | ||||
|   subCmdGroup(d: Interaction): void { | ||||
|   subCmdGroup(d: SlashCommandInteraction): void { | ||||
|     d.respond({ content: 'sub-cmd-group worked' }) | ||||
|   } | ||||
| 
 | ||||
|  | @ -79,7 +79,7 @@ class MyClient extends CommandClient { | |||
|   } | ||||
| 
 | ||||
|   @slash() | ||||
|   run(d: Interaction): void { | ||||
|   run(d: SlashCommandInteraction): void { | ||||
|     console.log(d.name) | ||||
|   } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue