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 { | import { | ||||||
|   SlashCommandsManager, |   SlashCommandsManager, | ||||||
|   SlashClient, |   SlashClient, | ||||||
|   SlashCommandHandlerCallback, |   SlashCommandHandlerCallback, | ||||||
|   SlashCommandHandler |   SlashCommandHandler | ||||||
| } from './src/interactions/mod.ts' | } from './src/interactions/mod.ts' | ||||||
| import { InteractionResponseType, InteractionType } from './src/types/slash.ts' | import { | ||||||
|  |   InteractionResponseType, | ||||||
|  |   InteractionType | ||||||
|  | } from './src/types/interactions.ts' | ||||||
| 
 | 
 | ||||||
| export interface DeploySlashInitOptions { | export interface DeploySlashInitOptions { | ||||||
|   env?: boolean |   env?: boolean | ||||||
|   publicKey?: string |   publicKey?: string | ||||||
|   token?: string |   token?: string | ||||||
|  |   path?: string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** Current Slash Client being used to handle commands */ | /** Current Slash Client being used to handle commands */ | ||||||
|  | @ -37,8 +42,12 @@ let commands: SlashCommandsManager | ||||||
|  * |  * | ||||||
|  * @param options Initialization options |  * @param options Initialization options | ||||||
|  */ |  */ | ||||||
| export function init(options: { env: boolean }): void | export function init(options: { env: boolean; path?: string }): void | ||||||
| export function init(options: { publicKey: string; token?: string }): void | export function init(options: { | ||||||
|  |   publicKey: string | ||||||
|  |   token?: string | ||||||
|  |   path?: string | ||||||
|  | }): void | ||||||
| export function init(options: DeploySlashInitOptions): void { | export function init(options: DeploySlashInitOptions): void { | ||||||
|   if (client !== undefined) throw new Error('Already initialized') |   if (client !== undefined) throw new Error('Already initialized') | ||||||
|   if (options.env === true) { |   if (options.env === true) { | ||||||
|  | @ -60,6 +69,9 @@ export function init(options: DeploySlashInitOptions): void { | ||||||
|     respondWith: CallableFunction |     respondWith: CallableFunction | ||||||
|     request: Request |     request: Request | ||||||
|   }): Promise<void> => { |   }): Promise<void> => { | ||||||
|  |     if (options.path !== undefined) { | ||||||
|  |       if (new URL(evt.request.url).pathname !== options.path) return | ||||||
|  |     } | ||||||
|     try { |     try { | ||||||
|       // we have to wrap because there are some weird scope errors
 |       // we have to wrap because there are some weird scope errors
 | ||||||
|       const d = await client.verifyFetchEvent({ |       const d = await client.verifyFetchEvent({ | ||||||
|  | @ -124,8 +136,18 @@ export function handle( | ||||||
|   client.handle(cmd, handler) |   client.handle(cmd, handler) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | export function interactions(cb: (i: Interaction) => any): void { | ||||||
|  |   client.on('interaction', cb) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export { commands, client } | 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/structures/slash.ts' | ||||||
| export * from './src/interactions/mod.ts' | export * from './src/interactions/mod.ts' | ||||||
| export * from './src/types/channel.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 { GuildManager } from './src/managers/guilds.ts' | ||||||
| export * from './src/structures/base.ts' | export * from './src/structures/base.ts' | ||||||
| export * from './src/structures/slash.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 { GuildEmojisManager } from './src/managers/guildEmojis.ts' | ||||||
| export { MembersManager } from './src/managers/members.ts' | export { MembersManager } from './src/managers/members.ts' | ||||||
| export { MessageReactionsManager } from './src/managers/messageReactions.ts' | export { MessageReactionsManager } from './src/managers/messageReactions.ts' | ||||||
|  | @ -191,4 +193,5 @@ export { | ||||||
|   isVoiceChannel, |   isVoiceChannel, | ||||||
|   default as getChannelByType |   default as getChannelByType | ||||||
| } from './src/utils/channel.ts' | } from './src/utils/channel.ts' | ||||||
|  | export * from './src/utils/interactions.ts' | ||||||
| export * from "./src/utils/command.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 { Guild } from '../../structures/guild.ts' | ||||||
| import { Member } from '../../structures/member.ts' | import { Member } from '../../structures/member.ts' | ||||||
| import { | import { | ||||||
|   Interaction, |  | ||||||
|   InteractionApplicationCommandResolved, |   InteractionApplicationCommandResolved, | ||||||
|   InteractionChannel |   SlashCommandInteraction | ||||||
| } from '../../structures/slash.ts' | } from '../../structures/slash.ts' | ||||||
|  | import { | ||||||
|  |   Interaction, | ||||||
|  |   InteractionChannel | ||||||
|  | } from '../../structures/interactions.ts' | ||||||
| import { GuildTextBasedChannel } from '../../structures/guildTextChannel.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 { UserPayload } from '../../types/user.ts' | ||||||
| import { Permissions } from '../../utils/permissions.ts' | import { Permissions } from '../../utils/permissions.ts' | ||||||
| import type { Gateway, GatewayEventHandler } from '../mod.ts' | import type { Gateway, GatewayEventHandler } from '../mod.ts' | ||||||
| import { User } from '../../structures/user.ts' | import { User } from '../../structures/user.ts' | ||||||
| import { Role } from '../../structures/role.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 ( | export const interactionCreate: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|  | @ -26,13 +40,22 @@ export const interactionCreate: GatewayEventHandler = async ( | ||||||
|   const guild = |   const guild = | ||||||
|     d.guild_id === undefined |     d.guild_id === undefined | ||||||
|       ? 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) |   if (d.member !== undefined) | ||||||
|     await guild?.members.set(d.member.user.id, d.member) |     await guild?.members.set(d.member.user.id, d.member) | ||||||
|   const member = |   const member = | ||||||
|     d.member !== undefined |     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 |       : undefined | ||||||
|   if (d.user !== undefined) await gateway.client.users.set(d.user.id, d.user) |   if (d.user !== undefined) await gateway.client.users.set(d.user.id, d.user) | ||||||
|   const dmUser = |   const dmUser = | ||||||
|  | @ -41,9 +64,9 @@ export const interactionCreate: GatewayEventHandler = async ( | ||||||
|   const user = member !== undefined ? member.user : dmUser |   const user = member !== undefined ? member.user : dmUser | ||||||
|   if (user === undefined) return |   if (user === undefined) return | ||||||
| 
 | 
 | ||||||
|   const channel = |   const channel = await gateway.client.channels.get<GuildTextBasedChannel>( | ||||||
|     (await gateway.client.channels.get<GuildTextBasedChannel>(d.channel_id)) ?? |     d.channel_id | ||||||
|     (await gateway.client.channels.fetch<GuildTextBasedChannel>(d.channel_id)) |   ) | ||||||
| 
 | 
 | ||||||
|   const resolved: InteractionApplicationCommandResolved = { |   const resolved: InteractionApplicationCommandResolved = { | ||||||
|     users: {}, |     users: {}, | ||||||
|  | @ -52,9 +75,11 @@ export const interactionCreate: GatewayEventHandler = async ( | ||||||
|     roles: {} |     roles: {} | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   if (d.data?.resolved !== undefined) { |   if ((d.data as InteractionApplicationCommandData)?.resolved !== undefined) { | ||||||
|     for (const [id, data] of Object.entries(d.data.resolved.users ?? {})) { |     for (const [id, data] of Object.entries( | ||||||
|       await gateway.client.users.set(id, data) |       (d.data as any)?.resolved.users ?? {} | ||||||
|  |     )) { | ||||||
|  |       await gateway.client.users.set(id, data as UserPayload) | ||||||
|       resolved.users[id] = ((await gateway.client.users.get( |       resolved.users[id] = ((await gateway.client.users.get( | ||||||
|         id |         id | ||||||
|       )) as unknown) as User |       )) as unknown) as User | ||||||
|  | @ -62,49 +87,87 @@ export const interactionCreate: GatewayEventHandler = async ( | ||||||
|         resolved.users[id].member = resolved.members[id] |         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() |       const roles = await guild?.roles.array() | ||||||
|       let permissions = new Permissions(Permissions.DEFAULT) |       let permissions = new Permissions(Permissions.DEFAULT) | ||||||
|       if (roles !== undefined) { |       if (roles !== undefined) { | ||||||
|         const mRoles = roles.filter( |         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)) |         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( |       resolved.members[id] = new Member( | ||||||
|         gateway.client, |         gateway.client, | ||||||
|         data, |         data as any, | ||||||
|         resolved.users[id], |         resolved.users[id], | ||||||
|         guild as Guild, |         guild as Guild, | ||||||
|         permissions |         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) { |       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 |         resolved.roles[id] = ((await guild.roles.get(id)) as unknown) as Role | ||||||
|       } else { |       } else { | ||||||
|         resolved.roles[id] = new Role( |         resolved.roles[id] = new Role( | ||||||
|           gateway.client, |           gateway.client, | ||||||
|           data, |           data as any, | ||||||
|           (guild as unknown) as Guild |           (guild as unknown) as Guild | ||||||
|         ) |         ) | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     for (const [id, data] of Object.entries(d.data.resolved.channels ?? {})) { |     for (const [id, data] of Object.entries( | ||||||
|       resolved.channels[id] = new InteractionChannel(gateway.client, data) |       (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, |       member, | ||||||
|       guild, |       guild, | ||||||
|       channel, |       channel, | ||||||
|       user, |       user, | ||||||
|       resolved |       resolved | ||||||
|     }) |     }) | ||||||
|  |   } else { | ||||||
|  |     interaction = new Interaction(gateway.client, d, { | ||||||
|  |       member, | ||||||
|  |       guild, | ||||||
|  |       channel, | ||||||
|  |       user, | ||||||
|  |       message | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   gateway.client.emit('interactionCreate', interaction) |   gateway.client.emit('interactionCreate', interaction) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -59,7 +59,8 @@ import type { | ||||||
|   EveryTextChannelTypes |   EveryTextChannelTypes | ||||||
| } from '../../utils/channel.ts' | } from '../../utils/channel.ts' | ||||||
| import { interactionCreate } from './interactionCreate.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 { CommandContext } from '../../commands/command.ts' | ||||||
| import type { RequestMethods } from '../../rest/types.ts' | import type { RequestMethods } from '../../rest/types.ts' | ||||||
| import type { PartialInvitePayload } from '../../types/invite.ts' | import type { PartialInvitePayload } from '../../types/invite.ts' | ||||||
|  | @ -358,11 +359,12 @@ export type ClientEvents = { | ||||||
|    * @param channel Channel of which Webhooks were updated |    * @param channel Channel of which Webhooks were updated | ||||||
|    */ |    */ | ||||||
|   webhooksUpdate: [guild: Guild, channel: GuildTextBasedChannel] |   webhooksUpdate: [guild: Guild, channel: GuildTextBasedChannel] | ||||||
|  | 
 | ||||||
|   /** |   /** | ||||||
|    * An Interaction was created |    * An Interaction was created | ||||||
|    * @param interaction Created interaction object |    * @param interaction Created interaction object | ||||||
|    */ |    */ | ||||||
|   interactionCreate: [interaction: Interaction] |   interactionCreate: [interaction: Interaction | SlashCommandInteraction] | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * When debug message was made |    * When debug message was made | ||||||
|  |  | ||||||
|  | @ -1,13 +1,14 @@ | ||||||
| import { | import { | ||||||
|   Interaction, |   SlashCommandInteraction, | ||||||
|   InteractionApplicationCommandResolved |   InteractionApplicationCommandResolved | ||||||
| } from '../structures/slash.ts' | } from '../structures/slash.ts' | ||||||
|  | import { Interaction } from '../structures/interactions.ts' | ||||||
| import { | import { | ||||||
|   InteractionPayload, |   InteractionPayload, | ||||||
|   InteractionResponsePayload, |   InteractionResponsePayload, | ||||||
|   InteractionType, |   InteractionType | ||||||
|   SlashCommandOptionType | } from '../types/interactions.ts' | ||||||
| } from '../types/slash.ts' | import { SlashCommandOptionType } from '../types/slashCommands.ts' | ||||||
| import type { Client } from '../client/mod.ts' | import type { Client } from '../client/mod.ts' | ||||||
| import { RESTManager } from '../rest/mod.ts' | import { RESTManager } from '../rest/mod.ts' | ||||||
| import { SlashModule } from './slashModule.ts' | import { SlashModule } from './slashModule.ts' | ||||||
|  | @ -17,7 +18,9 @@ import { HarmonyEventEmitter } from '../utils/events.ts' | ||||||
| import { encodeText, decodeText } from '../utils/encoding.ts' | import { encodeText, decodeText } from '../utils/encoding.ts' | ||||||
| import { SlashCommandsManager } from './slashCommand.ts' | import { SlashCommandsManager } from './slashCommand.ts' | ||||||
| 
 | 
 | ||||||
| export type SlashCommandHandlerCallback = (interaction: Interaction) => unknown | export type SlashCommandHandlerCallback = ( | ||||||
|  |   interaction: SlashCommandInteraction | ||||||
|  | ) => unknown | ||||||
| export interface SlashCommandHandler { | export interface SlashCommandHandler { | ||||||
|   name: string |   name: string | ||||||
|   guild?: 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. */ |   /** 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) => { |     return this.getHandlers().find((e) => { | ||||||
|       const hasGroupOrParent = e.group !== undefined || e.parent !== undefined |       const hasGroupOrParent = e.group !== undefined || e.parent !== undefined | ||||||
|       const groupMatched = |       const groupMatched = | ||||||
|  | @ -196,28 +201,28 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** Process an incoming Interaction */ |   /** Process an incoming Interaction */ | ||||||
|   private async _process(interaction: Interaction): Promise<void> { |   private async _process( | ||||||
|  |     interaction: Interaction | SlashCommandInteraction | ||||||
|  |   ): Promise<void> { | ||||||
|     if (!this.enabled) return |     if (!this.enabled) return | ||||||
| 
 | 
 | ||||||
|     if ( |     if (interaction.type !== InteractionType.APPLICATION_COMMAND) return | ||||||
|       interaction.type !== InteractionType.APPLICATION_COMMAND || |  | ||||||
|       interaction.data === undefined |  | ||||||
|     ) |  | ||||||
|       return |  | ||||||
| 
 | 
 | ||||||
|     const cmd = |     const cmd = | ||||||
|       this._getCommand(interaction) ?? |       this._getCommand(interaction as SlashCommandInteraction) ?? | ||||||
|       this.getHandlers().find((e) => e.name === '*') |       this.getHandlers().find((e) => e.name === '*') | ||||||
|     if (cmd?.group !== undefined) |     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) |     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 |     if (cmd === undefined) return | ||||||
| 
 | 
 | ||||||
|     await this.emit('interaction', interaction) |     await this.emit('interaction', interaction) | ||||||
|     try { |     try { | ||||||
|       await cmd.handler(interaction) |       await cmd.handler(interaction as SlashCommandInteraction) | ||||||
|     } catch (e) { |     } catch (e) { | ||||||
|       await this.emit('interactionError', e) |       await this.emit('interactionError', e) | ||||||
|     } |     } | ||||||
|  | @ -266,13 +271,15 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> { | ||||||
|       const payload: InteractionPayload = JSON.parse(decodeText(rawbody)) |       const payload: InteractionPayload = JSON.parse(decodeText(rawbody)) | ||||||
| 
 | 
 | ||||||
|       // TODO: Maybe fix all this hackery going on here?
 |       // 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
 |           // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
 | ||||||
|           user: new User(this as any, (payload.member?.user ?? payload.user)!), |           user: new User(this as any, (payload.member?.user ?? payload.user)!), | ||||||
|           member: payload.member as any, |           member: payload.member as any, | ||||||
|           guild: payload.guild_id as any, |           guild: payload.guild_id as any, | ||||||
|           channel: payload.channel_id as any, |           channel: payload.channel_id as any, | ||||||
|         resolved: ((payload.data |           resolved: (((payload.data as any) | ||||||
|             ?.resolved as unknown) as InteractionApplicationCommandResolved) ?? { |             ?.resolved as unknown) as InteractionApplicationCommandResolved) ?? { | ||||||
|             users: {}, |             users: {}, | ||||||
|             members: {}, |             members: {}, | ||||||
|  | @ -280,6 +287,15 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> { | ||||||
|             channels: {} |             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) => |       res._httpRespond = async (d: InteractionResponsePayload | FormData) => | ||||||
|         await req.respond({ |         await req.respond({ | ||||||
|           status: 200, |           status: 200, | ||||||
|  |  | ||||||
|  | @ -6,7 +6,7 @@ import { | ||||||
|   SlashCommandOptionType, |   SlashCommandOptionType, | ||||||
|   SlashCommandPartial, |   SlashCommandPartial, | ||||||
|   SlashCommandPayload |   SlashCommandPayload | ||||||
| } from '../types/slash.ts' | } from '../types/slashCommands.ts' | ||||||
| import { Collection } from '../utils/collection.ts' | import { Collection } from '../utils/collection.ts' | ||||||
| import type { SlashClient, SlashCommandHandlerCallback } from './slashClient.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 { CHANNEL } from '../types/endpoint.ts' | ||||||
| import getChannelByType from '../utils/channel.ts' | import getChannelByType from '../utils/channel.ts' | ||||||
| import { BaseManager } from './base.ts' | import { BaseManager } from './base.ts' | ||||||
| // Deno is bugged
 |  | ||||||
| import {} from './_util.ts' |  | ||||||
| 
 | 
 | ||||||
| export type AllMessageOptions = MessageOptions | Embed | export type AllMessageOptions = MessageOptions | Embed | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -30,11 +30,11 @@ import type { | ||||||
|   InviteWithMetadataPayload |   InviteWithMetadataPayload | ||||||
| } from '../types/invite.ts' | } from '../types/invite.ts' | ||||||
| import type { RoleModifyPayload, RolePayload } from '../types/role.ts' | import type { RoleModifyPayload, RolePayload } from '../types/role.ts' | ||||||
|  | import type { InteractionResponsePayload } from '../types/interactions.ts' | ||||||
| import type { | import type { | ||||||
|   InteractionResponsePayload, |  | ||||||
|   SlashCommandPartial, |   SlashCommandPartial, | ||||||
|   SlashCommandPayload |   SlashCommandPayload | ||||||
| } from '../types/slash.ts' | } from '../types/slashCommands.ts' | ||||||
| import type { TemplatePayload } from '../types/template.ts' | import type { TemplatePayload } from '../types/template.ts' | ||||||
| import type { UserPayload } from '../types/user.ts' | import type { UserPayload } from '../types/user.ts' | ||||||
| import type { VoiceRegion } from '../types/voice.ts' | import type { VoiceRegion } from '../types/voice.ts' | ||||||
|  |  | ||||||
|  | @ -13,7 +13,7 @@ export class DiscordAPIError extends Error { | ||||||
|     this.message = |     this.message = | ||||||
|       typeof error === 'string' |       typeof error === 'string' | ||||||
|         ? `${error} ` |         ? `${error} ` | ||||||
|         : `\n${error.method.toUpperCase()} ${error.url.slice(7)} returned ${ |         : `\n${error.method.toUpperCase()} ${error.url} returned ${ | ||||||
|             error.status |             error.status | ||||||
|           }\n(${error.code ?? 'unknown'}) ${error.message}${ |           }\n(${error.code ?? 'unknown'}) ${error.message}${ | ||||||
|             fmt.length === 0 |             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 { MessageReactionsManager } from '../managers/messageReactions.ts' | ||||||
| import { MessageSticker } from './messageSticker.ts' | import { MessageSticker } from './messageSticker.ts' | ||||||
| import type { Emoji } from './emoji.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' | import { encodeText } from '../utils/encoding.ts' | ||||||
| 
 | 
 | ||||||
| type AllMessageOptions = MessageOptions | Embed | type AllMessageOptions = MessageOptions | Embed | ||||||
|  |  | ||||||
|  | @ -1,80 +1,22 @@ | ||||||
| import type { Client } from '../client/mod.ts' | import type { Client } from '../client/mod.ts' | ||||||
| import type { | import { InteractionPayload } from '../types/interactions.ts' | ||||||
|   AllowedMentionsPayload, |  | ||||||
|   ChannelTypes, |  | ||||||
|   EmbedPayload, |  | ||||||
|   MessageOptions |  | ||||||
| } from '../types/channel.ts' |  | ||||||
| import { INTERACTION_CALLBACK, WEBHOOK_MESSAGE } from '../types/endpoint.ts' |  | ||||||
| import { | import { | ||||||
|   InteractionApplicationCommandData, |   InteractionApplicationCommandData, | ||||||
|   InteractionApplicationCommandOption, |   InteractionApplicationCommandOption, | ||||||
|   InteractionChannelPayload, |  | ||||||
|   InteractionPayload, |  | ||||||
|   InteractionResponseFlags, |  | ||||||
|   InteractionResponsePayload, |  | ||||||
|   InteractionResponseType, |  | ||||||
|   InteractionType, |  | ||||||
|   SlashCommandOptionType |   SlashCommandOptionType | ||||||
| } from '../types/slash.ts' | } from '../types/slashCommands.ts' | ||||||
| import type { Dict } from '../utils/dict.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 { Guild } from './guild.ts' | ||||||
| import type { GuildTextChannel } from './guildTextChannel.ts' | import type { GuildTextChannel } from './guildTextChannel.ts' | ||||||
| import type { Member } from './member.ts' | import type { Member } from './member.ts' | ||||||
| import { Message } from './message.ts' |  | ||||||
| import type { Role } from './role.ts' | import type { Role } from './role.ts' | ||||||
| import type { TextChannel } from './textChannel.ts' | import type { TextChannel } from './textChannel.ts' | ||||||
| import { User } from './user.ts' | import { User } from './user.ts' | ||||||
| 
 | import { | ||||||
| interface WebhookMessageOptions extends MessageOptions { |   InteractionUser, | ||||||
|   embeds?: Array<Embed | EmbedPayload> |   InteractionChannel, | ||||||
|   name?: string |   Interaction | ||||||
|   avatar?: string | } from './interactions.ts' | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 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 interface InteractionApplicationCommandResolved { | export interface InteractionApplicationCommandResolved { | ||||||
|   users: Dict<InteractionUser> |   users: Dict<InteractionUser> | ||||||
|  | @ -83,36 +25,11 @@ export interface InteractionApplicationCommandResolved { | ||||||
|   roles: Dict<Role> |   roles: Dict<Role> | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export class InteractionUser extends User { | export class SlashCommandInteraction extends Interaction { | ||||||
|   member?: Member |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export class Interaction extends SnowflakeBase { |  | ||||||
|   /** Type of Interaction */ |  | ||||||
|   type: InteractionType |  | ||||||
|   /** Interaction Token */ |  | ||||||
|   token: string |  | ||||||
|   /** Interaction ID */ |  | ||||||
|   id: string |  | ||||||
|   /** Data sent with Interaction. Only applies to Application Command */ |   /** Data sent with Interaction. Only applies to Application Command */ | ||||||
|   data?: InteractionApplicationCommandData |   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 |  | ||||||
|   /** Resolved data for Snowflakes in Slash Command Arguments */ |   /** Resolved data for Snowflakes in Slash Command Arguments */ | ||||||
|   resolved: InteractionApplicationCommandResolved |   resolved: InteractionApplicationCommandResolved | ||||||
|   /** Whether response was deferred or not */ |  | ||||||
|   deferred: boolean = false |  | ||||||
|   _httpRespond?: (d: InteractionResponsePayload) => unknown |  | ||||||
|   _httpResponded?: boolean |  | ||||||
|   applicationID: string |  | ||||||
| 
 | 
 | ||||||
|   constructor( |   constructor( | ||||||
|     client: Client, |     client: Client, | ||||||
|  | @ -125,26 +42,19 @@ export class Interaction extends SnowflakeBase { | ||||||
|       resolved: InteractionApplicationCommandResolved |       resolved: InteractionApplicationCommandResolved | ||||||
|     } |     } | ||||||
|   ) { |   ) { | ||||||
|     super(client) |     super(client, data, others) | ||||||
|     this.type = data.type |     // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
 | ||||||
|     this.token = data.token |     this.data = data.data as InteractionApplicationCommandData | ||||||
|     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.resolved = others.resolved |     this.resolved = others.resolved | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** Name of the Command Used (may change with future additions to Interactions!) */ |   /** Name of the Command Used (may change with future additions to Interactions!) */ | ||||||
|   get name(): string | undefined { |   get name(): string { | ||||||
|     return this.data?.name |     return this.data.name | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   get options(): InteractionApplicationCommandOption[] { |   get options(): InteractionApplicationCommandOption[] { | ||||||
|     return this.data?.options ?? [] |     return this.data.options ?? [] | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** Get an option by name */ |   /** Get an option by name */ | ||||||
|  | @ -162,222 +72,4 @@ export class Interaction extends SnowflakeBase { | ||||||
|       return this.resolved.channels[op.value] as any |       return this.resolved.channels[op.value] as any | ||||||
|     else return op.value |     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 { Permissions } from '../utils/permissions.ts' | ||||||
| import type { EmojiPayload } from './emoji.ts' | import type { EmojiPayload } from './emoji.ts' | ||||||
| import type { MemberPayload } from './guild.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' | import type { UserPayload } from './user.ts' | ||||||
| 
 | 
 | ||||||
| export interface ChannelPayload { | export interface ChannelPayload { | ||||||
|  |  | ||||||
|  | @ -11,7 +11,7 @@ import type { | ||||||
|   ClientStatus |   ClientStatus | ||||||
| } from './presence.ts' | } from './presence.ts' | ||||||
| import type { RolePayload } from './role.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' | 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 { Dict } from '../utils/dict.ts' | ||||||
| import type { | import type { ChannelTypes } from './channel.ts' | ||||||
|   AllowedMentionsPayload, |  | ||||||
|   ChannelTypes, |  | ||||||
|   EmbedPayload |  | ||||||
| } from './channel.ts' |  | ||||||
| import type { MemberPayload } from './guild.ts' | import type { MemberPayload } from './guild.ts' | ||||||
| import type { RolePayload } from './role.ts' | import type { RolePayload } from './role.ts' | ||||||
| import type { UserPayload } from './user.ts' | import type { UserPayload } from './user.ts' | ||||||
|  | @ -44,40 +40,6 @@ export interface InteractionApplicationCommandData { | ||||||
|   resolved?: InteractionApplicationCommandResolvedPayload |   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 { | export interface SlashCommandChoice { | ||||||
|   /** (Display) name of the Choice */ |   /** (Display) name of the Choice */ | ||||||
|   name: string |   name: string | ||||||
|  | @ -131,35 +93,3 @@ export interface SlashCommandPayload extends SlashCommandPartial { | ||||||
|   /** Application ID */ |   /** Application ID */ | ||||||
|   application_id: string |   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])) |         const arrayIndex = !isNaN(Number(obj[0])) | ||||||
|         if (arrayIndex) obj[0] = `[${obj[0]}]` |         if (arrayIndex) obj[0] = `[${obj[0]}]` | ||||||
|         if (acum !== '' && !arrayIndex) acum += '.' |         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, |   CommandContext, | ||||||
|   Extension, |   Extension, | ||||||
|   Collection, |   Collection, | ||||||
|   GuildTextChannel |   GuildTextChannel, | ||||||
| } from '../../mod.ts' |   slash, | ||||||
|  |   SlashCommandInteraction | ||||||
|  | } from '../mod.ts' | ||||||
| import { LL_IP, LL_PASS, LL_PORT, TOKEN } from './config.ts' | import { LL_IP, LL_PASS, LL_PORT, TOKEN } from './config.ts' | ||||||
| import { Manager, Player } from 'https://deno.land/x/lavadeno/mod.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'
 | // import { SlashCommandOptionType } from '../types/slash.ts'
 | ||||||
| 
 | 
 | ||||||
| export const nodes = [ | export const nodes = [ | ||||||
|  | @ -58,12 +58,12 @@ class MyClient extends CommandClient { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @subslash('cmd', 'sub-cmd-no-grp') |   @subslash('cmd', 'sub-cmd-no-grp') | ||||||
|   subCmdNoGroup(d: Interaction): void { |   subCmdNoGroup(d: SlashCommandInteraction): void { | ||||||
|     d.respond({ content: 'sub-cmd-no-group worked' }) |     d.respond({ content: 'sub-cmd-no-group worked' }) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @groupslash('cmd', 'sub-cmd-group', 'sub-cmd') |   @groupslash('cmd', 'sub-cmd-group', 'sub-cmd') | ||||||
|   subCmdGroup(d: Interaction): void { |   subCmdGroup(d: SlashCommandInteraction): void { | ||||||
|     d.respond({ content: 'sub-cmd-group worked' }) |     d.respond({ content: 'sub-cmd-group worked' }) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -79,7 +79,7 @@ class MyClient extends CommandClient { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @slash() |   @slash() | ||||||
|   run(d: Interaction): void { |   run(d: SlashCommandInteraction): void { | ||||||
|     console.log(d.name) |     console.log(d.name) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue