feat(commands): add CommandCategory and fix messageUpdate
This commit is contained in:
		
							parent
							
								
									b748086ae7
								
							
						
					
					
						commit
						a7336c19e3
					
				
					 28 changed files with 1097 additions and 655 deletions
				
			
		|  | @ -6,10 +6,12 @@ export const channelPinsUpdate: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|   d: ChannelPinsUpdatePayload |   d: ChannelPinsUpdatePayload | ||||||
| ) => { | ) => { | ||||||
|   const after: TextChannel | undefined = await gateway.client.channels.get<TextChannel>(d.channel_id) |   const after: | ||||||
|  |     | TextChannel | ||||||
|  |     | undefined = await gateway.client.channels.get<TextChannel>(d.channel_id) | ||||||
|   if (after !== undefined) { |   if (after !== undefined) { | ||||||
|     const before = after.refreshFromData({ |     const before = after.refreshFromData({ | ||||||
|       last_pin_timestamp: d.last_pin_timestamp |       last_pin_timestamp: d.last_pin_timestamp, | ||||||
|     }) |     }) | ||||||
|     const raw = await gateway.client.channels._get(d.channel_id) |     const raw = await gateway.client.channels._get(d.channel_id) | ||||||
|     await gateway.client.channels.set( |     await gateway.client.channels.set( | ||||||
|  |  | ||||||
|  | @ -8,7 +8,9 @@ export const guildBanAdd: GatewayEventHandler = async ( | ||||||
|   d: GuildBanAddPayload |   d: GuildBanAddPayload | ||||||
| ) => { | ) => { | ||||||
|   const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) |   const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) | ||||||
|   const user: User = await gateway.client.users.get(d.user.id) ?? new User(gateway.client, d.user) |   const user: User = | ||||||
|  |     (await gateway.client.users.get(d.user.id)) ?? | ||||||
|  |     new User(gateway.client, d.user) | ||||||
| 
 | 
 | ||||||
|   if (guild !== undefined) { |   if (guild !== undefined) { | ||||||
|     // We don't have to delete member, already done with guildMemberRemove event
 |     // We don't have to delete member, already done with guildMemberRemove event
 | ||||||
|  |  | ||||||
|  | @ -9,7 +9,8 @@ export const guildBanRemove: GatewayEventHandler = async ( | ||||||
| ) => { | ) => { | ||||||
|   const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) |   const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) | ||||||
|   const user: User = |   const user: User = | ||||||
|     await gateway.client.users.get(d.user.id) ?? new User(gateway.client, d.user) |     (await gateway.client.users.get(d.user.id)) ?? | ||||||
|  |     new User(gateway.client, d.user) | ||||||
| 
 | 
 | ||||||
|   if (guild !== undefined) { |   if (guild !== undefined) { | ||||||
|     gateway.client.emit('guildBanRemove', guild, user) |     gateway.client.emit('guildBanRemove', guild, user) | ||||||
|  |  | ||||||
|  | @ -1,24 +1,17 @@ | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| import { Guild } from '../../structures/guild.ts' | import { Guild } from '../../structures/guild.ts' | ||||||
| import { GuildPayload } from '../../types/guild.ts' | import { GuildPayload } from '../../types/guild.ts' | ||||||
| import { MembersManager } from '../../managers/members.ts' |  | ||||||
| import { GuildChannelPayload } from '../../types/channel.ts' | import { GuildChannelPayload } from '../../types/channel.ts' | ||||||
| import { RolesManager } from '../../managers/roles.ts' |  | ||||||
| 
 | 
 | ||||||
| export const guildCreate: GatewayEventHandler = async ( | export const guildCreate: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|   d: GuildPayload |   d: GuildPayload | ||||||
| ) => { | ) => { | ||||||
|   let guild: Guild | undefined = await gateway.client.guilds.get(d.id) |   const hasGuild: Guild | undefined = await gateway.client.guilds.get(d.id) | ||||||
|   if (guild !== undefined) { |  | ||||||
|     // It was just lazy load, so we don't fire the event as its gonna fire for every guild bot is in
 |  | ||||||
|   await gateway.client.guilds.set(d.id, d) |   await gateway.client.guilds.set(d.id, d) | ||||||
|  |   const guild = ((await gateway.client.guilds.get(d.id)) as unknown) as Guild | ||||||
| 
 | 
 | ||||||
|     if (d.members !== undefined) { |   if (d.members !== undefined) await guild.members.fromPayload(d.members) | ||||||
|       const members = new MembersManager(gateway.client, guild) |  | ||||||
|       await members.fromPayload(d.members) |  | ||||||
|       guild.members = members |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|   if (d.channels !== undefined) { |   if (d.channels !== undefined) { | ||||||
|     for (const ch of d.channels as GuildChannelPayload[]) { |     for (const ch of d.channels as GuildChannelPayload[]) { | ||||||
|  | @ -27,38 +20,13 @@ export const guildCreate: GatewayEventHandler = async ( | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|     if (d.roles !== undefined) { |  | ||||||
|       const roles = new RolesManager(gateway.client, guild) |  | ||||||
|       await roles.fromPayload(d.roles) |  | ||||||
|       guild.roles = roles |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     guild.refreshFromData(d) |  | ||||||
|   } else { |  | ||||||
|     await gateway.client.guilds.set(d.id, d) |  | ||||||
|     guild = new Guild(gateway.client, d) |  | ||||||
| 
 |  | ||||||
|     if (d.members !== undefined) { |  | ||||||
|       const members = new MembersManager(gateway.client, guild) |  | ||||||
|       await members.fromPayload(d.members) |  | ||||||
|       guild.members = members |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (d.channels !== undefined) { |  | ||||||
|       for (const ch of d.channels as GuildChannelPayload[]) { |  | ||||||
|         ch.guild_id = d.id |  | ||||||
|         await gateway.client.channels.set(ch.id, ch) |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (d.roles !== undefined) { |  | ||||||
|       const roles = new RolesManager(gateway.client, guild) |  | ||||||
|       await roles.fromPayload(d.roles) |  | ||||||
|       guild.roles = roles |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|   await guild.roles.fromPayload(d.roles) |   await guild.roles.fromPayload(d.roles) | ||||||
|     guild = new Guild(gateway.client, d) | 
 | ||||||
|  |   if (d.voice_states !== undefined) | ||||||
|  |     await guild.voiceStates.fromPayload(d.voice_states) | ||||||
|  | 
 | ||||||
|  |   if (hasGuild === undefined) { | ||||||
|  |     // It wasn't lazy load, so emit event
 | ||||||
|     gateway.client.emit('guildCreate', guild) |     gateway.client.emit('guildCreate', guild) | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| import { Emoji } from "../../structures/emoji.ts" | import { Emoji } from '../../structures/emoji.ts' | ||||||
| import { Guild } from '../../structures/guild.ts' | import { Guild } from '../../structures/guild.ts' | ||||||
| import { EmojiPayload } from "../../types/emoji.ts" | import { EmojiPayload } from '../../types/emoji.ts' | ||||||
| import { GuildEmojiUpdatePayload } from '../../types/gateway.ts' | import { GuildEmojiUpdatePayload } from '../../types/gateway.ts' | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| 
 | 
 | ||||||
|  | @ -13,27 +13,27 @@ export const guildEmojiUpdate: GatewayEventHandler = async ( | ||||||
|     const emojis = await guild.emojis.collection() |     const emojis = await guild.emojis.collection() | ||||||
|     const deleted: Emoji[] = [] |     const deleted: Emoji[] = [] | ||||||
|     const added: Emoji[] = [] |     const added: Emoji[] = [] | ||||||
|     const updated: Array<{ before: Emoji, after: Emoji }> = [] |     const updated: Array<{ before: Emoji; after: Emoji }> = [] | ||||||
|     const _updated: EmojiPayload[] = [] |     const _updated: EmojiPayload[] = [] | ||||||
| 
 | 
 | ||||||
|     for (const raw of d.emojis) { |     for (const raw of d.emojis) { | ||||||
|       const has = emojis.get(raw.id) |       const has = emojis.get(raw.id) | ||||||
|       if (has === undefined) { |       if (has === undefined) { | ||||||
|         await guild.emojis.set(raw.id, raw) |         await guild.emojis.set(raw.id, raw) | ||||||
|         const emoji = await guild.emojis.get(raw.id) as Emoji |         const emoji = (await guild.emojis.get(raw.id)) as Emoji | ||||||
|         added.push(emoji) |         added.push(emoji) | ||||||
|       } else _updated.push(raw) |       } else _updated.push(raw) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     for (const emoji of emojis.values()) { |     for (const emoji of emojis.values()) { | ||||||
|       const find = _updated.find(e => emoji.id === e.id) |       const find = _updated.find((e) => emoji.id === e.id) | ||||||
|       if (find === undefined) { |       if (find === undefined) { | ||||||
|         await guild.emojis.delete(emoji.id) |         await guild.emojis.delete(emoji.id) | ||||||
|         deleted.push(emoji) |         deleted.push(emoji) | ||||||
|       } else { |       } else { | ||||||
|         const before = await guild.emojis.get(find.id) as Emoji |         const before = (await guild.emojis.get(find.id)) as Emoji | ||||||
|         await guild.emojis.set(find.id, find) |         await guild.emojis.set(find.id, find) | ||||||
|         const after = await guild.emojis.get(find.id) as Emoji |         const after = (await guild.emojis.get(find.id)) as Emoji | ||||||
|         updated.push({ before, after }) |         updated.push({ before, after }) | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| import { Guild } from '../../structures/guild.ts' | import { Guild } from '../../structures/guild.ts' | ||||||
| import { GuildIntegrationsUpdatePayload } from "../../types/gateway.ts" | import { GuildIntegrationsUpdatePayload } from '../../types/gateway.ts' | ||||||
| 
 | 
 | ||||||
| export const guildIntegrationsUpdate: GatewayEventHandler = async ( | export const guildIntegrationsUpdate: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| import { Guild } from '../../structures/guild.ts' | import { Guild } from '../../structures/guild.ts' | ||||||
| import { GuildMemberAddPayload } from "../../types/gateway.ts" | import { GuildMemberAddPayload } from '../../types/gateway.ts' | ||||||
| import { Member } from "../../structures/member.ts" | import { Member } from '../../structures/member.ts' | ||||||
| 
 | 
 | ||||||
| export const guildMemberAdd: GatewayEventHandler = async ( | export const guildMemberAdd: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|  | @ -12,6 +12,6 @@ export const guildMemberAdd: GatewayEventHandler = async ( | ||||||
|   if (guild === undefined) return |   if (guild === undefined) return | ||||||
| 
 | 
 | ||||||
|   await guild.members.set(d.user.id, d) |   await guild.members.set(d.user.id, d) | ||||||
|   const member = await guild.members.get(d.user.id) as Member |   const member = (await guild.members.get(d.user.id)) as Member | ||||||
|   gateway.client.emit('guildMemberAdd', member) |   gateway.client.emit('guildMemberAdd', member) | ||||||
| } | } | ||||||
|  | @ -20,7 +20,7 @@ export const guildMemberUpdate: GatewayEventHandler = async ( | ||||||
|     nick: d.nick, |     nick: d.nick, | ||||||
|     premium_since: d.premium_since, |     premium_since: d.premium_since, | ||||||
|     deaf: member?.deaf ?? false, |     deaf: member?.deaf ?? false, | ||||||
|     mute: member?.mute ?? false |     mute: member?.mute ?? false, | ||||||
|   } |   } | ||||||
|   await guild.members.set(d.user.id, newMemberPayload) |   await guild.members.set(d.user.id, newMemberPayload) | ||||||
|   const newMember = await guild.members.get(d.user.id) |   const newMember = await guild.members.get(d.user.id) | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| import { Guild } from '../../structures/guild.ts' | import { Guild } from '../../structures/guild.ts' | ||||||
| import { GuildRoleDeletePayload } from "../../types/gateway.ts" | import { GuildRoleDeletePayload } from '../../types/gateway.ts' | ||||||
| 
 | 
 | ||||||
| export const guildRoleDelete: GatewayEventHandler = async ( | export const guildRoleDelete: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|  |  | ||||||
|  | @ -13,32 +13,32 @@ import { guildBanRemove } from './guildBanRemove.ts' | ||||||
| import { messageCreate } from './messageCreate.ts' | import { messageCreate } from './messageCreate.ts' | ||||||
| import { resume } from './resume.ts' | import { resume } from './resume.ts' | ||||||
| import { reconnect } from './reconnect.ts' | import { reconnect } from './reconnect.ts' | ||||||
| import { messageDelete } from "./messageDelete.ts" | import { messageDelete } from './messageDelete.ts' | ||||||
| import { messageUpdate } from "./messageUpdate.ts" | import { messageUpdate } from './messageUpdate.ts' | ||||||
| import { guildEmojiUpdate } from "./guildEmojiUpdate.ts" | import { guildEmojiUpdate } from './guildEmojiUpdate.ts' | ||||||
| import { guildMemberAdd } from "./guildMemberAdd.ts" | import { guildMemberAdd } from './guildMemberAdd.ts' | ||||||
| import { guildMemberRemove } from "./guildMemberRemove.ts" | import { guildMemberRemove } from './guildMemberRemove.ts' | ||||||
| import { guildMemberUpdate } from "./guildMemberUpdate.ts" | import { guildMemberUpdate } from './guildMemberUpdate.ts' | ||||||
| import { guildRoleCreate } from "./guildRoleCreate.ts" | import { guildRoleCreate } from './guildRoleCreate.ts' | ||||||
| import { guildRoleDelete } from "./guildRoleDelete.ts" | import { guildRoleDelete } from './guildRoleDelete.ts' | ||||||
| import { guildRoleUpdate } from "./guildRoleUpdate.ts" | import { guildRoleUpdate } from './guildRoleUpdate.ts' | ||||||
| import { guildIntegrationsUpdate } from "./guildIntegrationsUpdate.ts" | import { guildIntegrationsUpdate } from './guildIntegrationsUpdate.ts' | ||||||
| import { webhooksUpdate } from "./webhooksUpdate.ts" | import { webhooksUpdate } from './webhooksUpdate.ts' | ||||||
| import { messageDeleteBulk } from "./messageDeleteBulk.ts" | import { messageDeleteBulk } from './messageDeleteBulk.ts' | ||||||
| import { userUpdate } from "./userUpdate.ts" | import { userUpdate } from './userUpdate.ts' | ||||||
| import { typingStart } from "./typingStart.ts" | import { typingStart } from './typingStart.ts' | ||||||
| import { Channel } from "../../structures/channel.ts" | import { Channel } from '../../structures/channel.ts' | ||||||
| import { GuildTextChannel, TextChannel } from "../../structures/textChannel.ts" | import { GuildTextChannel, TextChannel } from '../../structures/textChannel.ts' | ||||||
| import { Guild } from "../../structures/guild.ts" | import { Guild } from '../../structures/guild.ts' | ||||||
| import { User } from "../../structures/user.ts" | import { User } from '../../structures/user.ts' | ||||||
| import { Emoji } from "../../structures/emoji.ts" | import { Emoji } from '../../structures/emoji.ts' | ||||||
| import { Member } from "../../structures/member.ts" | import { Member } from '../../structures/member.ts' | ||||||
| import { Role } from "../../structures/role.ts" | import { Role } from '../../structures/role.ts' | ||||||
| import { Message } from "../../structures/message.ts" | import { Message } from '../../structures/message.ts' | ||||||
| import { Collection } from "../../utils/collection.ts" | import { Collection } from '../../utils/collection.ts' | ||||||
| import { voiceServerUpdate } from "./voiceServerUpdate.ts" | import { voiceServerUpdate } from './voiceServerUpdate.ts' | ||||||
| import { voiceStateUpdate } from "./voiceStateUpdate.ts" | import { voiceStateUpdate } from './voiceStateUpdate.ts' | ||||||
| import { VoiceState } from "../../structures/voiceState.ts" | import { VoiceState } from '../../structures/voiceState.ts' | ||||||
| 
 | 
 | ||||||
| export const gatewayHandlers: { | export const gatewayHandlers: { | ||||||
|   [eventCode in GatewayEvents]: GatewayEventHandler | undefined |   [eventCode in GatewayEvents]: GatewayEventHandler | undefined | ||||||
|  | @ -79,7 +79,7 @@ export const gatewayHandlers: { | ||||||
|   USER_UPDATE: userUpdate, |   USER_UPDATE: userUpdate, | ||||||
|   VOICE_STATE_UPDATE: voiceStateUpdate, |   VOICE_STATE_UPDATE: voiceStateUpdate, | ||||||
|   VOICE_SERVER_UPDATE: voiceServerUpdate, |   VOICE_SERVER_UPDATE: voiceServerUpdate, | ||||||
|   WEBHOOKS_UPDATE: webhooksUpdate |   WEBHOOKS_UPDATE: webhooksUpdate, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface EventTypes { | export interface EventTypes { | ||||||
|  | @ -93,37 +93,46 @@ export interface VoiceServerUpdateData { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface ClientEvents extends EventTypes { | export interface ClientEvents extends EventTypes { | ||||||
|   'ready': () => void |   ready: () => void | ||||||
|   'reconnect': () => void |   reconnect: () => void | ||||||
|   'resumed': () => void |   resumed: () => void | ||||||
|   'channelCreate': (channel: Channel) => void |   channelCreate: (channel: Channel) => void | ||||||
|   'channelDelete': (channel: Channel) => void |   channelDelete: (channel: Channel) => void | ||||||
|   'channelPinsUpdate': (before: TextChannel, after: TextChannel) => void |   channelPinsUpdate: (before: TextChannel, after: TextChannel) => void | ||||||
|   'channelUpdate': (before: Channel, after: Channel) => void |   channelUpdate: (before: Channel, after: Channel) => void | ||||||
|   'guildBanAdd': (guild: Guild, user: User) => void |   guildBanAdd: (guild: Guild, user: User) => void | ||||||
|   'guildBanRemove': (guild: Guild, user: User) => void |   guildBanRemove: (guild: Guild, user: User) => void | ||||||
|   'guildCreate': (guild: Guild) => void |   guildCreate: (guild: Guild) => void | ||||||
|   'guildDelete': (guild: Guild) => void |   guildDelete: (guild: Guild) => void | ||||||
|   'guildEmojiAdd': (guild: Guild, emoji: Emoji) => void |   guildEmojiAdd: (guild: Guild, emoji: Emoji) => void | ||||||
|   'guildEmojiDelete': (guild: Guild, emoji: Emoji) => void |   guildEmojiDelete: (guild: Guild, emoji: Emoji) => void | ||||||
|   'guildEmojiUpdate': (guild: Guild, before: Emoji, after: Emoji) => void |   guildEmojiUpdate: (guild: Guild, before: Emoji, after: Emoji) => void | ||||||
|   'guildIntegrationsUpdate': (guild: Guild) => void |   guildIntegrationsUpdate: (guild: Guild) => void | ||||||
|   'guildMemberAdd': (member: Member) => void |   guildMemberAdd: (member: Member) => void | ||||||
|   'guildMemberRemove': (member: Member) => void |   guildMemberRemove: (member: Member) => void | ||||||
|   'guildMemberUpdate': (before: Member, after: Member) => void |   guildMemberUpdate: (before: Member, after: Member) => void | ||||||
|   'guildRoleCreate': (role: Role) => void |   guildRoleCreate: (role: Role) => void | ||||||
|   'guildRoleDelete': (role: Role) => void |   guildRoleDelete: (role: Role) => void | ||||||
|   'guildRoleUpdate': (before: Role, after: Role) => void |   guildRoleUpdate: (before: Role, after: Role) => void | ||||||
|   'guildUpdate': (before: Guild, after: Guild) => void |   guildUpdate: (before: Guild, after: Guild) => void | ||||||
|   'messageCreate': (message: Message) => void |   messageCreate: (message: Message) => void | ||||||
|   'messageDelete': (message: Message) => void |   messageDelete: (message: Message) => void | ||||||
|   'messageDeleteBulk': (channel: GuildTextChannel, messages: Collection<string, Message>, uncached: Set<string>) => void |   messageDeleteBulk: ( | ||||||
|   'messageUpdate': (before: Message, after: Message) => void |     channel: GuildTextChannel, | ||||||
|   'typingStart': (user: User, channel: TextChannel, at: Date, guildData?: TypingStartGuildData) => void |     messages: Collection<string, Message>, | ||||||
|   'userUpdate': (before: User, after: User) => void |     uncached: Set<string> | ||||||
|   'voiceServerUpdate': (data: VoiceServerUpdateData) => void |   ) => void | ||||||
|   'voiceStateAdd': (state: VoiceState) => void |   messageUpdate: (before: Message, after: Message) => void | ||||||
|   'voiceStateRemove': (state: VoiceState) => void |   typingStart: ( | ||||||
|   'voiceStateUpdate': (state: VoiceState, after: VoiceState) => void |     user: User, | ||||||
|   'webhooksUpdate': (guild: Guild, channel: GuildTextChannel) => void |     channel: TextChannel, | ||||||
|  |     at: Date, | ||||||
|  |     guildData?: TypingStartGuildData | ||||||
|  |   ) => void | ||||||
|  |   userUpdate: (before: User, after: User) => void | ||||||
|  |   voiceServerUpdate: (data: VoiceServerUpdateData) => void | ||||||
|  |   voiceStateAdd: (state: VoiceState) => void | ||||||
|  |   voiceStateRemove: (state: VoiceState) => void | ||||||
|  |   voiceStateUpdate: (state: VoiceState, after: VoiceState) => void | ||||||
|  |   webhooksUpdate: (guild: Guild, channel: GuildTextChannel) => void | ||||||
| } | } | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| import { TextChannel } from '../../structures/textChannel.ts' | import { TextChannel } from '../../structures/textChannel.ts' | ||||||
| import { MessageDeletePayload } from "../../types/gateway.ts" | import { MessageDeletePayload } from '../../types/gateway.ts' | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| 
 | 
 | ||||||
| export const messageDelete: GatewayEventHandler = async ( | export const messageDelete: GatewayEventHandler = async ( | ||||||
|  | @ -13,7 +13,8 @@ export const messageDelete: GatewayEventHandler = async ( | ||||||
|     channel = (await gateway.client.channels.fetch(d.channel_id)) as TextChannel |     channel = (await gateway.client.channels.fetch(d.channel_id)) as TextChannel | ||||||
| 
 | 
 | ||||||
|   const message = await channel.messages.get(d.id) |   const message = await channel.messages.get(d.id) | ||||||
|   if (message === undefined) return gateway.client.emit('messageDeleteUncached', d) |   if (message === undefined) | ||||||
|  |     return gateway.client.emit('messageDeleteUncached', d) | ||||||
|   await channel.messages.delete(d.id) |   await channel.messages.delete(d.id) | ||||||
|   gateway.client.emit('messageDelete', message) |   gateway.client.emit('messageDelete', message) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,18 +1,22 @@ | ||||||
| import { Message } from "../../structures/message.ts" | import { Message } from '../../structures/message.ts' | ||||||
| import { GuildTextChannel } from '../../structures/textChannel.ts' | import { GuildTextChannel } from '../../structures/textChannel.ts' | ||||||
| import { MessageDeleteBulkPayload } from "../../types/gateway.ts" | import { MessageDeleteBulkPayload } from '../../types/gateway.ts' | ||||||
| import { Collection } from "../../utils/collection.ts" | import { Collection } from '../../utils/collection.ts' | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| 
 | 
 | ||||||
| export const messageDeleteBulk: GatewayEventHandler = async ( | export const messageDeleteBulk: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|   d: MessageDeleteBulkPayload |   d: MessageDeleteBulkPayload | ||||||
| ) => { | ) => { | ||||||
|   let channel = await gateway.client.channels.get<GuildTextChannel>(d.channel_id) |   let channel = await gateway.client.channels.get<GuildTextChannel>( | ||||||
|  |     d.channel_id | ||||||
|  |   ) | ||||||
|   // Fetch the channel if not cached
 |   // Fetch the channel if not cached
 | ||||||
|   if (channel === undefined) |   if (channel === undefined) | ||||||
|     // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
 |     // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
 | ||||||
|     channel = (await gateway.client.channels.fetch(d.channel_id)) as GuildTextChannel |     channel = (await gateway.client.channels.fetch( | ||||||
|  |       d.channel_id | ||||||
|  |     )) as GuildTextChannel | ||||||
| 
 | 
 | ||||||
|   const messages = new Collection<string, Message>() |   const messages = new Collection<string, Message>() | ||||||
|   const uncached = new Set<string>() |   const uncached = new Set<string>() | ||||||
|  |  | ||||||
|  | @ -1,6 +1,5 @@ | ||||||
| import { Message } from '../../structures/message.ts' | import { Message } from '../../structures/message.ts' | ||||||
| import { TextChannel } from '../../structures/textChannel.ts' | import { TextChannel } from '../../structures/textChannel.ts' | ||||||
| import { User } from '../../structures/user.ts' |  | ||||||
| import { MessagePayload } from '../../types/channel.ts' | import { MessagePayload } from '../../types/channel.ts' | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| 
 | 
 | ||||||
|  | @ -11,19 +10,19 @@ export const messageUpdate: GatewayEventHandler = async ( | ||||||
|   let channel = await gateway.client.channels.get<TextChannel>(d.channel_id) |   let channel = await gateway.client.channels.get<TextChannel>(d.channel_id) | ||||||
|   // Fetch the channel if not cached
 |   // Fetch the channel if not cached
 | ||||||
|   if (channel === undefined) |   if (channel === undefined) | ||||||
|     // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
 |     channel = await gateway.client.channels.fetch(d.channel_id) | ||||||
|     channel = (await gateway.client.channels.fetch(d.channel_id)) as TextChannel | 
 | ||||||
|  |   if (channel === undefined) return | ||||||
| 
 | 
 | ||||||
|   const message = await channel.messages.get(d.id) |   const message = await channel.messages.get(d.id) | ||||||
|   const author = |   if (message === undefined) return | ||||||
|     message?.author !== undefined |   const raw = await channel.messages._get(d.id) | ||||||
|       ? message.author |   if (raw === undefined) return | ||||||
|       : new User(gateway.client, d.author) | 
 | ||||||
|   const newMsg = new Message(gateway.client, d, channel, author) |   const newRaw = raw | ||||||
|   if (message === undefined) { |   Object.assign(newRaw, d) | ||||||
|     await channel.messages.set(d.id, d) |   await channel.messages.set(d.id, newRaw) | ||||||
|     return gateway.client.emit('messageUpdateUncached', newMsg) | 
 | ||||||
|   } |   const newMsg = ((await channel.messages.get(d.id)) as unknown) as Message | ||||||
|   await channel.messages.set(d.id, d) |  | ||||||
|   gateway.client.emit('messageUpdate', message, newMsg) |   gateway.client.emit('messageUpdate', message, newMsg) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,15 +1,18 @@ | ||||||
| import { User } from '../../structures/user.ts' | import { User } from '../../structures/user.ts' | ||||||
| import { Ready } from "../../types/gateway.ts" | import { Ready } from '../../types/gateway.ts' | ||||||
| import { GuildPayload } from '../../types/guild.ts' | import { GuildPayload } from '../../types/guild.ts' | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| 
 | 
 | ||||||
| export const ready: GatewayEventHandler = async (gateway: Gateway, d: Ready) => { | export const ready: GatewayEventHandler = async ( | ||||||
|  |   gateway: Gateway, | ||||||
|  |   d: Ready | ||||||
|  | ) => { | ||||||
|   await gateway.client.guilds.flush() |   await gateway.client.guilds.flush() | ||||||
| 
 | 
 | ||||||
|   gateway.client.user = new User(gateway.client, d.user) |   gateway.client.user = new User(gateway.client, d.user) | ||||||
|   gateway.sessionID = d.session_id |   gateway.sessionID = d.session_id | ||||||
|   gateway.debug(`Received READY. Session: ${gateway.sessionID}`) |   gateway.debug(`Received READY. Session: ${gateway.sessionID}`) | ||||||
|   await gateway.cache.set("session_id", gateway.sessionID) |   await gateway.cache.set('session_id', gateway.sessionID) | ||||||
| 
 | 
 | ||||||
|   d.guilds.forEach((guild: GuildPayload) => { |   d.guilds.forEach((guild: GuildPayload) => { | ||||||
|     gateway.client.guilds.set(guild.id, guild) |     gateway.client.guilds.set(guild.id, guild) | ||||||
|  |  | ||||||
|  | @ -1,5 +1,8 @@ | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| 
 | 
 | ||||||
| export const reconnect: GatewayEventHandler = async (gateway: Gateway, d: any) => { | export const reconnect: GatewayEventHandler = async ( | ||||||
|  |   gateway: Gateway, | ||||||
|  |   d: any | ||||||
|  | ) => { | ||||||
|   gateway.reconnect() |   gateway.reconnect() | ||||||
| } | } | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| import { Guild } from "../../structures/guild.ts" | import { Guild } from '../../structures/guild.ts' | ||||||
| import { VoiceServerUpdatePayload } from "../../types/gateway.ts" | import { VoiceServerUpdatePayload } from '../../types/gateway.ts' | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| 
 | 
 | ||||||
| export const voiceServerUpdate: GatewayEventHandler = async ( | export const voiceServerUpdate: GatewayEventHandler = async ( | ||||||
|  | @ -9,6 +9,6 @@ export const voiceServerUpdate: GatewayEventHandler = async ( | ||||||
|   gateway.client.emit('voiceServerUpdate', { |   gateway.client.emit('voiceServerUpdate', { | ||||||
|     token: d.token, |     token: d.token, | ||||||
|     endpoint: d.endpoint, |     endpoint: d.endpoint, | ||||||
|     guild: (await gateway.client.guilds.get(d.guild_id) as unknown) as Guild |     guild: ((await gateway.client.guilds.get(d.guild_id)) as unknown) as Guild, | ||||||
|   }) |   }) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| import { Guild } from "../../structures/guild.ts" | import { Guild } from '../../structures/guild.ts' | ||||||
| import { VoiceState } from "../../structures/voiceState.ts" | import { VoiceState } from '../../structures/voiceState.ts' | ||||||
| import { VoiceStatePayload } from "../../types/voice.ts" | import { MemberPayload } from '../../types/guild.ts' | ||||||
|  | import { VoiceStatePayload } from '../../types/voice.ts' | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| 
 | 
 | ||||||
| export const voiceStateUpdate: GatewayEventHandler = async ( | export const voiceStateUpdate: GatewayEventHandler = async ( | ||||||
|  | @ -9,22 +10,41 @@ export const voiceStateUpdate: GatewayEventHandler = async ( | ||||||
| ) => { | ) => { | ||||||
|   // TODO(DjDeveloperr): Support self-bot here; they can be in DMs (Call)
 |   // TODO(DjDeveloperr): Support self-bot here; they can be in DMs (Call)
 | ||||||
|   if (d.guild_id === undefined) return |   if (d.guild_id === undefined) return | ||||||
|   const guild = (await gateway.client.guilds.get(d.guild_id) as unknown) as Guild |   const guild = ((await gateway.client.guilds.get( | ||||||
|  |     d.guild_id | ||||||
|  |   )) as unknown) as Guild | ||||||
| 
 | 
 | ||||||
|   const voiceState = await guild.voiceStates.get(d.user_id) |   const voiceState = await guild.voiceStates.get(d.user_id) | ||||||
| 
 | 
 | ||||||
|   if (d.channel_id === null) { |   if (d.channel_id === null) { | ||||||
|  |     if (voiceState === undefined) { | ||||||
|  |       await guild.members.set(d.user_id, (d.member as unknown) as MemberPayload) | ||||||
|  |       const member = ((await guild.members.get( | ||||||
|  |         d.user_id | ||||||
|  |       )) as unknown) as MemberPayload | ||||||
|  |       return gateway.client.emit('voiceStateRemoveUncached', { guild, member }) | ||||||
|  |     } | ||||||
|     // No longer in the channel, so delete
 |     // No longer in the channel, so delete
 | ||||||
|     await guild.voiceStates.delete(d.user_id) |     await guild.voiceStates.delete(d.user_id) | ||||||
|     gateway.client.emit('voiceStateRemove', (voiceState as unknown) as VoiceState) |     gateway.client.emit( | ||||||
|  |       'voiceStateRemove', | ||||||
|  |       (voiceState as unknown) as VoiceState | ||||||
|  |     ) | ||||||
|     return |     return | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   await guild.voiceStates.set(d.user_id, d) |   await guild.voiceStates.set(d.user_id, d) | ||||||
|   const newVoiceState = await guild.voiceStates.get(d.user_id) |   const newVoiceState = await guild.voiceStates.get(d.user_id) | ||||||
|   if (voiceState === undefined) { |   if (voiceState === undefined) { | ||||||
|     gateway.client.emit('voiceStateAdd', (newVoiceState as unknown) as VoiceState) |     gateway.client.emit( | ||||||
|  |       'voiceStateAdd', | ||||||
|  |       (newVoiceState as unknown) as VoiceState | ||||||
|  |     ) | ||||||
|   } else { |   } else { | ||||||
|     gateway.client.emit('voiceStateUpdate', voiceState, (newVoiceState as unknown) as VoiceState) |     gateway.client.emit( | ||||||
|  |       'voiceStateUpdate', | ||||||
|  |       voiceState, | ||||||
|  |       (newVoiceState as unknown) as VoiceState | ||||||
|  |     ) | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| import { Guild } from '../../structures/guild.ts' | import { Guild } from '../../structures/guild.ts' | ||||||
| import { WebhooksUpdatePayload } from "../../types/gateway.ts" | import { WebhooksUpdatePayload } from '../../types/gateway.ts' | ||||||
| import { GuildTextChannel } from "../../structures/textChannel.ts" | import { GuildTextChannel } from '../../structures/textChannel.ts' | ||||||
| 
 | 
 | ||||||
| export const webhooksUpdate: GatewayEventHandler = async ( | export const webhooksUpdate: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|  | @ -10,7 +10,10 @@ export const webhooksUpdate: GatewayEventHandler = async ( | ||||||
|   const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) |   const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) | ||||||
|   if (guild === undefined) return |   if (guild === undefined) return | ||||||
| 
 | 
 | ||||||
|   const channel: GuildTextChannel | undefined = await guild.channels.get(d.channel_id) as GuildTextChannel |   const channel: GuildTextChannel | undefined = (await guild.channels.get( | ||||||
|   if (channel === undefined) gateway.client.emit('webhooksUpdateUncached', guild, d.channel_id) |     d.channel_id | ||||||
|  |   )) as GuildTextChannel | ||||||
|  |   if (channel === undefined) | ||||||
|  |     gateway.client.emit('webhooksUpdateUncached', guild, d.channel_id) | ||||||
|   else gateway.client.emit('webhooksUpdate', guild, channel) |   else gateway.client.emit('webhooksUpdate', guild, channel) | ||||||
| } | } | ||||||
|  | @ -1,30 +1,48 @@ | ||||||
| import { Client } from '../models/client.ts' | import { Client } from '../models/client.ts' | ||||||
| import { Guild } from "../structures/guild.ts" | import { Guild } from '../structures/guild.ts' | ||||||
| import { VoiceChannel } from "../structures/guildVoiceChannel.ts" | import { VoiceChannel } from '../structures/guildVoiceChannel.ts' | ||||||
| import { User } from "../structures/user.ts" | import { User } from '../structures/user.ts' | ||||||
| import { VoiceState } from "../structures/voiceState.ts" | import { VoiceState } from '../structures/voiceState.ts' | ||||||
| import { VoiceStatePayload } from "../types/voice.ts" | import { VoiceStatePayload } from '../types/voice.ts' | ||||||
| import { BaseManager } from './base.ts' | import { BaseManager } from './base.ts' | ||||||
| 
 | 
 | ||||||
| export class GuildVoiceStatesManager extends BaseManager<VoiceStatePayload, VoiceState> { | export class GuildVoiceStatesManager extends BaseManager< | ||||||
|  |   VoiceStatePayload, | ||||||
|  |   VoiceState | ||||||
|  | > { | ||||||
|   guild: Guild |   guild: Guild | ||||||
| 
 | 
 | ||||||
|   async get (key: string): Promise<VoiceState | undefined> { |  | ||||||
|     const raw = await this._get(key) |  | ||||||
|     if (raw === undefined) return |  | ||||||
| 
 |  | ||||||
|     const guild = raw.guild_id === undefined ? undefined : await this.client.guilds.get(raw.guild_id) |  | ||||||
| 
 |  | ||||||
|     return new VoiceState(this.client, raw, { |  | ||||||
|       user: (await this.client.users.get(raw.user_id) as unknown) as User, |  | ||||||
|       channel: raw.channel_id == null ? null : (await this.client.channels.get<VoiceChannel>(raw.channel_id) as unknown) as VoiceChannel, |  | ||||||
|       guild, |  | ||||||
|       member: guild === undefined ? undefined : await guild.members.get(raw.user_id)  |  | ||||||
|     }) |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   constructor(client: Client, guild: Guild) { |   constructor(client: Client, guild: Guild) { | ||||||
|     super(client, `vs:${guild.id}`, VoiceState) |     super(client, `vs:${guild.id}`, VoiceState) | ||||||
|     this.guild = guild |     this.guild = guild | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   async get(key: string): Promise<VoiceState | undefined> { | ||||||
|  |     const raw = await this._get(key) | ||||||
|  |     if (raw === undefined) return | ||||||
|  | 
 | ||||||
|  |     const guild = | ||||||
|  |       raw.guild_id === undefined | ||||||
|  |         ? undefined | ||||||
|  |         : await this.client.guilds.get(raw.guild_id) | ||||||
|  | 
 | ||||||
|  |     return new VoiceState(this.client, raw, { | ||||||
|  |       user: ((await this.client.users.get(raw.user_id)) as unknown) as User, | ||||||
|  |       channel: | ||||||
|  |         raw.channel_id == null | ||||||
|  |           ? null | ||||||
|  |           : (((await this.client.channels.get<VoiceChannel>( | ||||||
|  |               raw.channel_id | ||||||
|  |             )) as unknown) as VoiceChannel), | ||||||
|  |       guild, | ||||||
|  |       member: | ||||||
|  |         guild === undefined ? undefined : await guild.members.get(raw.user_id), | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async fromPayload(d: VoiceStatePayload[]): Promise<void> { | ||||||
|  |     for (const data of d) { | ||||||
|  |       await this.set(data.user_id, data) | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -18,11 +18,17 @@ export class MessagesManager extends BaseManager<MessagePayload, Message> { | ||||||
|     const raw = await this._get(key) |     const raw = await this._get(key) | ||||||
|     if (raw === undefined) return |     if (raw === undefined) return | ||||||
| 
 | 
 | ||||||
|  |     if (raw.author === undefined) return | ||||||
|  | 
 | ||||||
|     let channel = await this.client.channels.get(raw.channel_id) |     let channel = await this.client.channels.get(raw.channel_id) | ||||||
|     if (channel === undefined) |     if (channel === undefined) | ||||||
|       channel = await this.client.channels.fetch(raw.channel_id) |       channel = await this.client.channels.fetch(raw.channel_id) | ||||||
| 
 | 
 | ||||||
|     const author = new User(this.client, raw.author) |     let author = ((await this.client.users.get( | ||||||
|  |       raw.author.id | ||||||
|  |     )) as unknown) as User | ||||||
|  | 
 | ||||||
|  |     if (author === undefined) author = new User(this.client, raw.author) | ||||||
| 
 | 
 | ||||||
|     const res = new this.DataType(this.client, raw, channel, author) as any |     const res = new this.DataType(this.client, raw, channel, author) as any | ||||||
|     await res.mentions.fromPayload(raw) |     await res.mentions.fromPayload(raw) | ||||||
|  | @ -30,14 +36,19 @@ export class MessagesManager extends BaseManager<MessagePayload, Message> { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async set(key: string, value: MessagePayload): Promise<any> { |   async set(key: string, value: MessagePayload): Promise<any> { | ||||||
|     return this.client.cache.set(this.cacheName, key, value, this.client.messageCacheLifetime) |     return this.client.cache.set( | ||||||
|  |       this.cacheName, | ||||||
|  |       key, | ||||||
|  |       value, | ||||||
|  |       this.client.messageCacheLifetime | ||||||
|  |     ) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async fetch(id: string): Promise<Message> { |   async fetch(id: string): Promise<Message> { | ||||||
|     return await new Promise((resolve, reject) => { |     return await new Promise((resolve, reject) => { | ||||||
|       this.client.rest |       this.client.rest | ||||||
|         .get(CHANNEL_MESSAGE(this.channel.id, id)) |         .get(CHANNEL_MESSAGE(this.channel.id, id)) | ||||||
|         .then(async data => { |         .then(async (data) => { | ||||||
|           await this.set(id, data as MessagePayload) |           await this.set(id, data as MessagePayload) | ||||||
| 
 | 
 | ||||||
|           let channel: any = await this.client.channels.get<TextChannel>( |           let channel: any = await this.client.channels.get<TextChannel>( | ||||||
|  | @ -63,7 +74,7 @@ export class MessagesManager extends BaseManager<MessagePayload, Message> { | ||||||
| 
 | 
 | ||||||
|           resolve(res) |           resolve(res) | ||||||
|         }) |         }) | ||||||
|         .catch(e => reject(e)) |         .catch((e) => reject(e)) | ||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -4,7 +4,7 @@ import { TextChannel } from '../structures/textChannel.ts' | ||||||
| import { User } from '../structures/user.ts' | import { User } from '../structures/user.ts' | ||||||
| import { Collection } from '../utils/collection.ts' | import { Collection } from '../utils/collection.ts' | ||||||
| import { CommandClient } from './commandClient.ts' | import { CommandClient } from './commandClient.ts' | ||||||
| import { Extension } from "./extensions.ts" | import { Extension } from './extensions.ts' | ||||||
| 
 | 
 | ||||||
| export interface CommandContext { | export interface CommandContext { | ||||||
|   /** The Client object */ |   /** The Client object */ | ||||||
|  | @ -34,6 +34,8 @@ export class Command { | ||||||
|   name: string = '' |   name: string = '' | ||||||
|   /** Description of the Command */ |   /** Description of the Command */ | ||||||
|   description?: string |   description?: string | ||||||
|  |   /** Category of the Command */ | ||||||
|  |   category?: string | ||||||
|   /** Array of Aliases of Command, or only string */ |   /** Array of Aliases of Command, or only string */ | ||||||
|   aliases?: string | string[] |   aliases?: string | string[] | ||||||
|   /** Extension (Parent) of the Command */ |   /** Extension (Parent) of the Command */ | ||||||
|  | @ -42,10 +44,12 @@ export class Command { | ||||||
|   usage?: string | string[] |   usage?: string | string[] | ||||||
|   /** Usage Example of Command, only Arguments (without Prefix and Name) */ |   /** Usage Example of Command, only Arguments (without Prefix and Name) */ | ||||||
|   examples?: string | string[] |   examples?: string | string[] | ||||||
|   /** Does the Command take Arguments? Maybe number of required arguments? */ |   /** Does the Command take Arguments? Maybe number of required arguments? Or list of arguments? */ | ||||||
|   args?: number | boolean |   args?: number | boolean | string[] | ||||||
|   /** Permission(s) required for using Command */ |   /** Permissions(s) required by both User and Bot in order to use Command */ | ||||||
|   permissions?: string | string[] |   permissions?: string | string[] | ||||||
|  |   /** Permission(s) required for using Command */ | ||||||
|  |   userPermissions?: string | string[] | ||||||
|   /** Permission(s) bot will need in order to execute Command */ |   /** Permission(s) bot will need in order to execute Command */ | ||||||
|   botPermissions?: string | string[] |   botPermissions?: string | string[] | ||||||
|   /** Role(s) user will require in order to use Command. List or one of ID or name */ |   /** Role(s) user will require in order to use Command. List or one of ID or name */ | ||||||
|  | @ -64,14 +68,189 @@ export class Command { | ||||||
|   ownerOnly?: boolean |   ownerOnly?: boolean | ||||||
| 
 | 
 | ||||||
|   /** Method executed before executing actual command. Returns bool value - whether to continue or not (optional) */ |   /** Method executed before executing actual command. Returns bool value - whether to continue or not (optional) */ | ||||||
|   beforeExecute(ctx: CommandContext): boolean | Promise<boolean> { return true } |   beforeExecute(ctx: CommandContext): boolean | Promise<boolean> { | ||||||
|  |     return true | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   /** Actual command code, which is executed when all checks have passed. */ |   /** Actual command code, which is executed when all checks have passed. */ | ||||||
|   execute(ctx: CommandContext): any {} |   execute(ctx: CommandContext): any {} | ||||||
|   /** Method executed after executing command, passes on CommandContext and the value returned by execute too. (optional) */ |   /** Method executed after executing command, passes on CommandContext and the value returned by execute too. (optional) */ | ||||||
|   afterExecute(ctx: CommandContext, executeResult: any): any {} |   afterExecute(ctx: CommandContext, executeResult: any): any {} | ||||||
| 
 | 
 | ||||||
|   toString(): string { |   toString(): string { | ||||||
|     return `Command: ${this.name}${this.extension !== undefined ? ` [${this.extension.name}]` : ''}` |     return `Command: ${this.name}${ | ||||||
|  |       this.extension !== undefined | ||||||
|  |         ? ` [${this.extension.name}]` | ||||||
|  |         : this.category !== undefined | ||||||
|  |         ? ` [${this.category}]` | ||||||
|  |         : '' | ||||||
|  |     }` | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export class CommandCategory { | ||||||
|  |   /** Name of the Category. */ | ||||||
|  |   name: string = '' | ||||||
|  |   /** Permissions(s) required by both User and Bot in order to use Category Commands */ | ||||||
|  |   permissions?: string | string[] | ||||||
|  |   /** Permission(s) required for using Category Commands */ | ||||||
|  |   userPermissions?: string | string[] | ||||||
|  |   /** Permission(s) bot will need in order to execute Category Commands */ | ||||||
|  |   botPermissions?: string | string[] | ||||||
|  |   /** Role(s) user will require in order to use Category Commands. List or one of ID or name */ | ||||||
|  |   roles?: string | string[] | ||||||
|  |   /** Whitelisted Guilds. Only these Guild(s) can execute Category Commands. (List or one of IDs) */ | ||||||
|  |   whitelistedGuilds?: string | string[] | ||||||
|  |   /** Whitelisted Channels. Category Commands can be executed only in these channels. (List or one of IDs) */ | ||||||
|  |   whitelistedChannels?: string | string[] | ||||||
|  |   /** Whitelisted Users. Category Commands can be executed only by these Users (List or one of IDs) */ | ||||||
|  |   whitelistedUsers?: string | string[] | ||||||
|  |   /** Whether the Category Commands can only be used in Guild (if allowed in DMs) */ | ||||||
|  |   guildOnly?: boolean | ||||||
|  |   /** Whether the Category Commands can only be used in Bot's DMs (if allowed) */ | ||||||
|  |   dmOnly?: boolean | ||||||
|  |   /** Whether the Category Commands can only be used by Bot Owners */ | ||||||
|  |   ownerOnly?: boolean | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export class CommandBuilder extends Command { | ||||||
|  |   setName(name: string): CommandBuilder { | ||||||
|  |     this.name = name | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setDescription(description?: string): CommandBuilder { | ||||||
|  |     this.description = description | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setCategory(category?: string): CommandBuilder { | ||||||
|  |     this.category = category | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setAlias(alias: string | string[]): CommandBuilder { | ||||||
|  |     this.aliases = alias | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   addAlias(alias: string | string[]): CommandBuilder { | ||||||
|  |     if (this.aliases === undefined) this.aliases = [] | ||||||
|  |     if (typeof this.aliases === 'string') this.aliases = [this.aliases] | ||||||
|  | 
 | ||||||
|  |     this.aliases = [ | ||||||
|  |       ...new Set( | ||||||
|  |         ...this.aliases, | ||||||
|  |         ...(typeof alias === 'string' ? [alias] : alias) | ||||||
|  |       ), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setExtension(extension?: Extension): CommandBuilder { | ||||||
|  |     this.extension = extension | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setUsage(usage: string | string[]): CommandBuilder { | ||||||
|  |     this.usage = usage | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   addUsage(usage: string | string[]): CommandBuilder { | ||||||
|  |     if (this.usage === undefined) this.usage = [] | ||||||
|  |     if (typeof this.usage === 'string') this.usage = [this.usage] | ||||||
|  | 
 | ||||||
|  |     this.aliases = [ | ||||||
|  |       ...new Set( | ||||||
|  |         ...this.usage, | ||||||
|  |         ...(typeof usage === 'string' ? [usage] : usage) | ||||||
|  |       ), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setExample(examples: string | string[]): CommandBuilder { | ||||||
|  |     this.examples = examples | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   addExample(examples: string | string[]): CommandBuilder { | ||||||
|  |     if (this.examples === undefined) this.examples = [] | ||||||
|  |     if (typeof this.examples === 'string') this.examples = [this.examples] | ||||||
|  | 
 | ||||||
|  |     this.examples = [ | ||||||
|  |       ...new Set( | ||||||
|  |         ...this.examples, | ||||||
|  |         ...(typeof examples === 'string' ? [examples] : examples) | ||||||
|  |       ), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setPermissions(perms?: string | string[]): CommandBuilder { | ||||||
|  |     this.permissions = perms | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setUserPermissions(perms?: string | string[]): CommandBuilder { | ||||||
|  |     this.userPermissions = perms | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setBotPermissions(perms?: string | string[]): CommandBuilder { | ||||||
|  |     this.botPermissions = perms | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setRoles(roles: string | string[]): CommandBuilder { | ||||||
|  |     this.roles = roles | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setWhitelistedGuilds(list: string | string[]): CommandBuilder { | ||||||
|  |     this.whitelistedGuilds = list | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setWhitelistedUsers(list: string | string[]): CommandBuilder { | ||||||
|  |     this.whitelistedUsers = list | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setWhitelistedChannels(list: string | string[]): CommandBuilder { | ||||||
|  |     this.whitelistedChannels = list | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setGuildOnly(value: boolean = true): CommandBuilder { | ||||||
|  |     this.guildOnly = value | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setOwnerOnly(value: boolean = true): CommandBuilder { | ||||||
|  |     this.ownerOnly = value | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   onBeforeExecute(fn: (ctx: CommandContext) => boolean | any): CommandBuilder { | ||||||
|  |     this.beforeExecute = fn | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   onExecute(fn: (ctx: CommandContext) => any): CommandBuilder { | ||||||
|  |     this.execute = fn | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   onAfterExecute( | ||||||
|  |     fn: (ctx: CommandContext, executeResult?: any) => any | ||||||
|  |   ): CommandBuilder { | ||||||
|  |     this.afterExecute = fn | ||||||
|  |     return this | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -85,7 +264,9 @@ export class CommandsManager { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** Number of loaded Commands */ |   /** Number of loaded Commands */ | ||||||
|   get count(): number { return this.list.size } |   get count(): number { | ||||||
|  |     return this.list.size | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|   /** Find a Command by name/alias */ |   /** Find a Command by name/alias */ | ||||||
|   find(search: string): Command | undefined { |   find(search: string): Command | undefined { | ||||||
|  | @ -99,7 +280,7 @@ export class CommandsManager { | ||||||
|         if (typeof cmd.aliases === 'string') aliases = [cmd.aliases] |         if (typeof cmd.aliases === 'string') aliases = [cmd.aliases] | ||||||
|         else aliases = cmd.aliases |         else aliases = cmd.aliases | ||||||
|         if (this.client.caseSensitive === false) |         if (this.client.caseSensitive === false) | ||||||
|           aliases = aliases.map(e => e.toLowerCase()) |           aliases = aliases.map((e) => e.toLowerCase()) | ||||||
|         return aliases.includes(search) |         return aliases.includes(search) | ||||||
|       } else return false |       } else return false | ||||||
|     }) |     }) | ||||||
|  | @ -123,8 +304,9 @@ export class CommandsManager { | ||||||
|         const aliases: string[] = |         const aliases: string[] = | ||||||
|           typeof search.aliases === 'string' ? [search.aliases] : search.aliases |           typeof search.aliases === 'string' ? [search.aliases] : search.aliases | ||||||
|         exists = |         exists = | ||||||
|           aliases.map(alias => this.find(alias) !== undefined).find(e => e) ?? |           aliases | ||||||
|           false |             .map((alias) => this.find(alias) !== undefined) | ||||||
|  |             .find((e) => e) ?? false | ||||||
|       } |       } | ||||||
|       return exists |       return exists | ||||||
|     } |     } | ||||||
|  | @ -134,7 +316,10 @@ export class CommandsManager { | ||||||
|   add(cmd: Command | typeof Command): boolean { |   add(cmd: Command | typeof Command): boolean { | ||||||
|     // eslint-disable-next-line new-cap
 |     // eslint-disable-next-line new-cap
 | ||||||
|     if (!(cmd instanceof Command)) cmd = new cmd() |     if (!(cmd instanceof Command)) cmd = new cmd() | ||||||
|     if (this.exists(cmd)) throw new Error(`Failed to add Command '${cmd.toString()}' with name/alias already exists.`) |     if (this.exists(cmd)) | ||||||
|  |       throw new Error( | ||||||
|  |         `Failed to add Command '${cmd.toString()}' with name/alias already exists.` | ||||||
|  |       ) | ||||||
|     this.list.set(cmd.name, cmd) |     this.list.set(cmd.name, cmd) | ||||||
|     return true |     return true | ||||||
|   } |   } | ||||||
|  | @ -148,7 +333,7 @@ export class CommandsManager { | ||||||
| 
 | 
 | ||||||
|   /** Check whether a Command is disabled or not */ |   /** Check whether a Command is disabled or not */ | ||||||
|   isDisabled(name: string | Command): boolean { |   isDisabled(name: string | Command): boolean { | ||||||
|     const cmd = typeof name === "string" ? this.find(name) : name |     const cmd = typeof name === 'string' ? this.find(name) : name | ||||||
|     if (cmd === undefined) return false |     if (cmd === undefined) return false | ||||||
|     const exists = this.exists(name) |     const exists = this.exists(name) | ||||||
|     if (!exists) return false |     if (!exists) return false | ||||||
|  | @ -157,12 +342,65 @@ export class CommandsManager { | ||||||
| 
 | 
 | ||||||
|   /** Disable a Command */ |   /** Disable a Command */ | ||||||
|   disable(name: string | Command): boolean { |   disable(name: string | Command): boolean { | ||||||
|     const cmd = typeof name === "string" ? this.find(name) : name |     const cmd = typeof name === 'string' ? this.find(name) : name | ||||||
|     if (cmd === undefined) return false |     if (cmd === undefined) return false | ||||||
|     if (this.isDisabled(cmd)) return false |     if (this.isDisabled(cmd)) return false | ||||||
|     this.disabled.add(cmd.name) |     this.disabled.add(cmd.name) | ||||||
|     return true |     return true | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   /** Get all commands of a Category */ | ||||||
|  |   category(category: string): Collection<string, Command> { | ||||||
|  |     return this.list.filter( | ||||||
|  |       (cmd) => cmd.category !== undefined && cmd.category === category | ||||||
|  |     ) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export class CategoriesManager { | ||||||
|  |   client: CommandClient | ||||||
|  |   list: Collection<string, CommandCategory> = new Collection() | ||||||
|  | 
 | ||||||
|  |   constructor(client: CommandClient) { | ||||||
|  |     this.client = client | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Get a Collection of Categories */ | ||||||
|  |   all(): Collection<string, CommandCategory> { | ||||||
|  |     return this.list | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Get a list of names of Categories added */ | ||||||
|  |   names(): string[] { | ||||||
|  |     return [...this.list.keys()] | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Check if a Category exists or not */ | ||||||
|  |   has(category: string | CommandCategory): boolean { | ||||||
|  |     return this.list.has( | ||||||
|  |       typeof category === 'string' ? category : category.name | ||||||
|  |     ) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Get a Category by name */ | ||||||
|  |   get(name: string): CommandCategory | undefined { | ||||||
|  |     return this.list.get(name) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Add a Category to the Manager */ | ||||||
|  |   add(category: CommandCategory): CategoriesManager { | ||||||
|  |     if (this.has(category)) | ||||||
|  |       throw new Error(`Category ${category.name} already exists`) | ||||||
|  |     this.list.set(category.name, category) | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Remove a Category from the Manager */ | ||||||
|  |   remove(category: string | CommandCategory): boolean { | ||||||
|  |     if (!this.has(category)) return false | ||||||
|  |     this.list.delete(typeof category === 'string' ? category : category.name) | ||||||
|  |     return true | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface ParsedCommand { | export interface ParsedCommand { | ||||||
|  | @ -185,6 +423,6 @@ export const parseCommand = ( | ||||||
|   return { |   return { | ||||||
|     name, |     name, | ||||||
|     args, |     args, | ||||||
|     argString |     argString, | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,8 +1,13 @@ | ||||||
| import { Message } from "../../mod.ts" | import { Message } from '../../mod.ts' | ||||||
| import { awaitSync } from "../utils/mixedPromise.ts" | import { awaitSync } from '../utils/mixedPromise.ts' | ||||||
| import { Client, ClientOptions } from './client.ts' | import { Client, ClientOptions } from './client.ts' | ||||||
| import { CommandContext, CommandsManager, parseCommand } from './command.ts' | import { | ||||||
| import { ExtensionsManager } from "./extensions.ts" |   CategoriesManager, | ||||||
|  |   CommandContext, | ||||||
|  |   CommandsManager, | ||||||
|  |   parseCommand, | ||||||
|  | } from './command.ts' | ||||||
|  | import { ExtensionsManager } from './extensions.ts' | ||||||
| 
 | 
 | ||||||
| type PrefixReturnType = string | string[] | Promise<string | string[]> | type PrefixReturnType = string | string[] | Promise<string | string[]> | ||||||
| 
 | 
 | ||||||
|  | @ -38,6 +43,7 @@ export class CommandClient extends Client implements CommandClientOptions { | ||||||
|   caseSensitive: boolean |   caseSensitive: boolean | ||||||
|   extensions: ExtensionsManager = new ExtensionsManager(this) |   extensions: ExtensionsManager = new ExtensionsManager(this) | ||||||
|   commands: CommandsManager = new CommandsManager(this) |   commands: CommandsManager = new CommandsManager(this) | ||||||
|  |   categories: CategoriesManager = new CategoriesManager(this) | ||||||
| 
 | 
 | ||||||
|   constructor(options: CommandClientOptions) { |   constructor(options: CommandClientOptions) { | ||||||
|     super(options) |     super(options) | ||||||
|  | @ -85,14 +91,20 @@ export class CommandClient extends Client implements CommandClientOptions { | ||||||
|   async processMessage(msg: Message): Promise<any> { |   async processMessage(msg: Message): Promise<any> { | ||||||
|     if (!this.allowBots && msg.author.bot === true) return |     if (!this.allowBots && msg.author.bot === true) return | ||||||
| 
 | 
 | ||||||
|     const isUserBlacklisted = await awaitSync(this.isUserBlacklisted(msg.author.id)) |     const isUserBlacklisted = await awaitSync( | ||||||
|  |       this.isUserBlacklisted(msg.author.id) | ||||||
|  |     ) | ||||||
|     if (isUserBlacklisted === true) return |     if (isUserBlacklisted === true) return | ||||||
| 
 | 
 | ||||||
|     const isChannelBlacklisted = await awaitSync(this.isChannelBlacklisted(msg.channel.id)) |     const isChannelBlacklisted = await awaitSync( | ||||||
|  |       this.isChannelBlacklisted(msg.channel.id) | ||||||
|  |     ) | ||||||
|     if (isChannelBlacklisted === true) return |     if (isChannelBlacklisted === true) return | ||||||
| 
 | 
 | ||||||
|     if (msg.guild !== undefined) { |     if (msg.guild !== undefined) { | ||||||
|       const isGuildBlacklisted = await awaitSync(this.isGuildBlacklisted(msg.guild.id)) |       const isGuildBlacklisted = await awaitSync( | ||||||
|  |         this.isGuildBlacklisted(msg.guild.id) | ||||||
|  |       ) | ||||||
|       if (isGuildBlacklisted === true) return |       if (isGuildBlacklisted === true) return | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -112,17 +124,20 @@ export class CommandClient extends Client implements CommandClientOptions { | ||||||
|         else return |         else return | ||||||
|       } |       } | ||||||
|     } else { |     } else { | ||||||
|       const usedPrefix = prefix.find(v => msg.content.startsWith(v)) |       const usedPrefix = prefix.find((v) => msg.content.startsWith(v)) | ||||||
|       if (usedPrefix === undefined) { |       if (usedPrefix === undefined) { | ||||||
|         if (this.mentionPrefix) mentionPrefix = true |         if (this.mentionPrefix) mentionPrefix = true | ||||||
|         else return |         else return | ||||||
|       } |       } else prefix = usedPrefix | ||||||
|       else prefix = usedPrefix |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (mentionPrefix) { |     if (mentionPrefix) { | ||||||
|       if (msg.content.startsWith(this.user?.mention as string) === true) prefix = this.user?.mention as string |       if (msg.content.startsWith(this.user?.mention as string) === true) | ||||||
|       else if (msg.content.startsWith(this.user?.nickMention as string) === true) prefix = this.user?.nickMention as string |         prefix = this.user?.mention as string | ||||||
|  |       else if ( | ||||||
|  |         msg.content.startsWith(this.user?.nickMention as string) === true | ||||||
|  |       ) | ||||||
|  |         prefix = this.user?.nickMention as string | ||||||
|       else return |       else return | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -132,10 +147,52 @@ export class CommandClient extends Client implements CommandClientOptions { | ||||||
|     const command = this.commands.find(parsed.name) |     const command = this.commands.find(parsed.name) | ||||||
| 
 | 
 | ||||||
|     if (command === undefined) return |     if (command === undefined) return | ||||||
|  |     const category = | ||||||
|  |       command.category !== undefined | ||||||
|  |         ? this.categories.get(command.category) | ||||||
|  |         : undefined | ||||||
| 
 | 
 | ||||||
|     if (command.whitelistedGuilds !== undefined && msg.guild !== undefined && command.whitelistedGuilds.includes(msg.guild.id) === false) return; |     // Guild whitelist exists, and if does and Command used in a Guild, is this Guild allowed?
 | ||||||
|     if (command.whitelistedChannels !== undefined && command.whitelistedChannels.includes(msg.channel.id) === false) return; |     // This is a bit confusing here, if these settings on a Command exist, and also do on Category, Command overrides them
 | ||||||
|     if (command.whitelistedUsers !== undefined && command.whitelistedUsers.includes(msg.author.id) === false) return; |     if ( | ||||||
|  |       command.whitelistedGuilds === undefined && | ||||||
|  |       category?.whitelistedGuilds !== undefined && | ||||||
|  |       msg.guild !== undefined && | ||||||
|  |       category.whitelistedGuilds.includes(msg.guild.id) === false | ||||||
|  |     ) | ||||||
|  |       return | ||||||
|  |     if ( | ||||||
|  |       command.whitelistedGuilds !== undefined && | ||||||
|  |       msg.guild !== undefined && | ||||||
|  |       command.whitelistedGuilds.includes(msg.guild.id) === false | ||||||
|  |     ) | ||||||
|  |       return | ||||||
|  | 
 | ||||||
|  |     // Checks for Channel Whitelist
 | ||||||
|  |     if ( | ||||||
|  |       command.whitelistedChannels === undefined && | ||||||
|  |       category?.whitelistedChannels !== undefined && | ||||||
|  |       category.whitelistedChannels.includes(msg.channel.id) === false | ||||||
|  |     ) | ||||||
|  |       return | ||||||
|  |     if ( | ||||||
|  |       command.whitelistedChannels !== undefined && | ||||||
|  |       command.whitelistedChannels.includes(msg.channel.id) === false | ||||||
|  |     ) | ||||||
|  |       return | ||||||
|  | 
 | ||||||
|  |     // Checks for Users Whitelist
 | ||||||
|  |     if ( | ||||||
|  |       command.whitelistedUsers === undefined && | ||||||
|  |       category?.whitelistedUsers !== undefined && | ||||||
|  |       category.whitelistedUsers.includes(msg.author.id) === false | ||||||
|  |     ) | ||||||
|  |       return | ||||||
|  |     if ( | ||||||
|  |       command.whitelistedUsers !== undefined && | ||||||
|  |       command.whitelistedUsers.includes(msg.author.id) === false | ||||||
|  |     ) | ||||||
|  |       return | ||||||
| 
 | 
 | ||||||
|     const ctx: CommandContext = { |     const ctx: CommandContext = { | ||||||
|       client: this, |       client: this, | ||||||
|  | @ -147,40 +204,117 @@ export class CommandClient extends Client implements CommandClientOptions { | ||||||
|       author: msg.author, |       author: msg.author, | ||||||
|       command, |       command, | ||||||
|       channel: msg.channel, |       channel: msg.channel, | ||||||
|       guild: msg.guild |       guild: msg.guild, | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (command.ownerOnly === true && !this.owners.includes(msg.author.id)) return this.emit('commandOwnerOnly', ctx, command) |     // In these checks too, Command overrides Category if present
 | ||||||
|     if (command.guildOnly === true && msg.guild === undefined) return this.emit('commandGuildOnly', ctx, command) |     // Check if Command is only for Owners
 | ||||||
|     if (command.dmOnly === true && msg.guild !== undefined) return this.emit('commandDmOnly', ctx, command) |     if ( | ||||||
|  |       (command.ownerOnly !== undefined || category === undefined | ||||||
|  |         ? command.ownerOnly | ||||||
|  |         : category.ownerOnly) === true && | ||||||
|  |       !this.owners.includes(msg.author.id) | ||||||
|  |     ) | ||||||
|  |       return this.emit('commandOwnerOnly', ctx, command) | ||||||
| 
 | 
 | ||||||
|     if (command.botPermissions !== undefined && msg.guild !== undefined) { |     // Check if Command is only for Guild
 | ||||||
|  |     if ( | ||||||
|  |       (command.guildOnly !== undefined || category === undefined | ||||||
|  |         ? command.guildOnly | ||||||
|  |         : category.guildOnly) === true && | ||||||
|  |       msg.guild === undefined | ||||||
|  |     ) | ||||||
|  |       return this.emit('commandGuildOnly', ctx, command) | ||||||
|  | 
 | ||||||
|  |     // Check if Command is only for DMs
 | ||||||
|  |     if ( | ||||||
|  |       (command.dmOnly !== undefined || category === undefined | ||||||
|  |         ? command.dmOnly | ||||||
|  |         : category.dmOnly) === true && | ||||||
|  |       msg.guild !== undefined | ||||||
|  |     ) | ||||||
|  |       return this.emit('commandDmOnly', ctx, command) | ||||||
|  | 
 | ||||||
|  |     const allPermissions = | ||||||
|  |       command.permissions !== undefined | ||||||
|  |         ? command.permissions | ||||||
|  |         : category?.permissions | ||||||
|  | 
 | ||||||
|  |     if ( | ||||||
|  |       (command.botPermissions !== undefined || | ||||||
|  |         category?.permissions !== undefined) && | ||||||
|  |       msg.guild !== undefined | ||||||
|  |     ) { | ||||||
|       // TODO: Check Overwrites too
 |       // TODO: Check Overwrites too
 | ||||||
|       const me = await msg.guild.me() |       const me = await msg.guild.me() | ||||||
|       const missing: string[] = [] |       const missing: string[] = [] | ||||||
| 
 | 
 | ||||||
|       for (const perm of command.botPermissions) { |       let permissions = | ||||||
|  |         command.botPermissions === undefined | ||||||
|  |           ? category?.permissions | ||||||
|  |           : command.botPermissions | ||||||
|  | 
 | ||||||
|  |       if (permissions !== undefined) { | ||||||
|  |         if (typeof permissions === 'string') permissions = [permissions] | ||||||
|  | 
 | ||||||
|  |         if (allPermissions !== undefined) | ||||||
|  |           permissions = [...new Set(...permissions, ...allPermissions)] | ||||||
|  | 
 | ||||||
|  |         for (const perm of permissions) { | ||||||
|           if (me.permissions.has(perm) === false) missing.push(perm) |           if (me.permissions.has(perm) === false) missing.push(perm) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|       if (missing.length !== 0) return this.emit('commandBotMissingPermissions', ctx, command, missing) |         if (missing.length !== 0) | ||||||
|  |           return this.emit( | ||||||
|  |             'commandBotMissingPermissions', | ||||||
|  |             ctx, | ||||||
|  |             command, | ||||||
|  |             missing | ||||||
|  |           ) | ||||||
|  |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (command.permissions !== undefined && msg.guild !== undefined) { |     if ( | ||||||
|  |       (command.userPermissions !== undefined || | ||||||
|  |         category?.userPermissions !== undefined) && | ||||||
|  |       msg.guild !== undefined | ||||||
|  |     ) { | ||||||
|  |       let permissions = | ||||||
|  |         command.userPermissions !== undefined | ||||||
|  |           ? command.userPermissions | ||||||
|  |           : category?.userPermissions | ||||||
|  | 
 | ||||||
|  |       if (permissions !== undefined) { | ||||||
|  |         if (typeof permissions === 'string') permissions = [permissions] | ||||||
|  | 
 | ||||||
|  |         if (allPermissions !== undefined) | ||||||
|  |           permissions = [...new Set(...permissions, ...allPermissions)] | ||||||
|  | 
 | ||||||
|         const missing: string[] = [] |         const missing: string[] = [] | ||||||
|       let perms: string[] = [] | 
 | ||||||
|       if (typeof command.permissions === 'string') perms = [command.permissions] |         for (const perm of permissions) { | ||||||
|       else perms = command.permissions |  | ||||||
|       for (const perm of perms) { |  | ||||||
|           const has = msg.member?.permissions.has(perm) |           const has = msg.member?.permissions.has(perm) | ||||||
|           if (has !== true) missing.push(perm) |           if (has !== true) missing.push(perm) | ||||||
|         } |         } | ||||||
|       if (missing.length !== 0) return this.emit('commandMissingPermissions', command, missing, ctx) | 
 | ||||||
|  |         if (missing.length !== 0) | ||||||
|  |           return this.emit( | ||||||
|  |             'commandUserMissingPermissions', | ||||||
|  |             command, | ||||||
|  |             missing, | ||||||
|  |             ctx | ||||||
|  |           ) | ||||||
|  |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (command.args !== undefined) { |     if (command.args !== undefined) { | ||||||
|       if (typeof command.args === 'boolean' && parsed.args.length === 0) return this.emit('commandMissingArgs', ctx, command) |       if (typeof command.args === 'boolean' && parsed.args.length === 0) | ||||||
|       else if (typeof command.args === 'number' && parsed.args.length < command.args) this.emit('commandMissingArgs', ctx, command)  |         return this.emit('commandMissingArgs', ctx, command) | ||||||
|  |       else if ( | ||||||
|  |         typeof command.args === 'number' && | ||||||
|  |         parsed.args.length < command.args | ||||||
|  |       ) | ||||||
|  |         this.emit('commandMissingArgs', ctx, command) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     try { |     try { | ||||||
|  |  | ||||||
|  | @ -1,10 +1,10 @@ | ||||||
| import { Client } from "../models/client.ts"; | import { Client } from '../models/client.ts' | ||||||
| import { MessagePayload } from "../types/channel.ts"; | import { MessagePayload } from '../types/channel.ts' | ||||||
| import { Collection } from "../utils/collection.ts"; | import { Collection } from '../utils/collection.ts' | ||||||
| import { GuildTextChannel } from "./textChannel.ts"; | import { GuildTextChannel } from './textChannel.ts' | ||||||
| import { Message } from "./message.ts"; | import { Message } from './message.ts' | ||||||
| import { Role } from "./role.ts"; | import { Role } from './role.ts' | ||||||
| import { User } from "./user.ts"; | import { User } from './user.ts' | ||||||
| 
 | 
 | ||||||
| export class MessageMentions { | export class MessageMentions { | ||||||
|   client: Client |   client: Client | ||||||
|  | @ -25,7 +25,9 @@ export class MessageMentions { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async fromPayload(payload: MessagePayload): Promise<MessageMentions> { |   async fromPayload(payload: MessagePayload): Promise<MessageMentions> { | ||||||
|     payload.mentions.forEach(rawUser => { |     if (this.message === undefined) return this | ||||||
|  |     if (payload.mentions !== undefined) | ||||||
|  |       payload.mentions.forEach((rawUser) => { | ||||||
|         this.users.set(rawUser.id, new User(this.client, rawUser)) |         this.users.set(rawUser.id, new User(this.client, rawUser)) | ||||||
|       }) |       }) | ||||||
| 
 | 
 | ||||||
|  | @ -37,15 +39,21 @@ export class MessageMentions { | ||||||
|     } |     } | ||||||
|     if (payload.mention_channels !== undefined) { |     if (payload.mention_channels !== undefined) { | ||||||
|       for (const mentionChannel of payload.mention_channels) { |       for (const mentionChannel of payload.mention_channels) { | ||||||
|         const channel = await this.client.channels.get<GuildTextChannel>(mentionChannel.id) |         const channel = await this.client.channels.get<GuildTextChannel>( | ||||||
|  |           mentionChannel.id | ||||||
|  |         ) | ||||||
|         if (channel !== undefined) this.channels.set(channel.id, channel) |         if (channel !== undefined) this.channels.set(channel.id, channel) | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     const matchChannels = this.message.content.match(MessageMentions.CHANNEL_MENTION) |     const matchChannels = this.message.content.match( | ||||||
|  |       MessageMentions.CHANNEL_MENTION | ||||||
|  |     ) | ||||||
|     if (matchChannels !== null) { |     if (matchChannels !== null) { | ||||||
|       for (const id of matchChannels) { |       for (const id of matchChannels) { | ||||||
|         const parsedID = id.substr(2, id.length - 3) |         const parsedID = id.substr(2, id.length - 3) | ||||||
|         const channel = await this.client.channels.get<GuildTextChannel>(parsedID) |         const channel = await this.client.channels.get<GuildTextChannel>( | ||||||
|  |           parsedID | ||||||
|  |         ) | ||||||
|         if (channel !== undefined) this.channels.set(channel.id, channel) |         if (channel !== undefined) this.channels.set(channel.id, channel) | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -1,10 +1,17 @@ | ||||||
| import { Command, CommandClient, Intents, GuildChannel, CommandContext, Extension } from '../../mod.ts' | import { | ||||||
|  |   Command, | ||||||
|  |   CommandClient, | ||||||
|  |   Intents, | ||||||
|  |   GuildChannel, | ||||||
|  |   CommandContext, | ||||||
|  |   Extension, | ||||||
|  | } from '../../mod.ts' | ||||||
| import { TOKEN } from './config.ts' | import { TOKEN } from './config.ts' | ||||||
| 
 | 
 | ||||||
| const client = new CommandClient({ | const client = new CommandClient({ | ||||||
|   prefix: ["pls", "!"], |   prefix: ['pls', '!'], | ||||||
|   spacesAfterPrefix: true, |   spacesAfterPrefix: true, | ||||||
|   mentionPrefix: true |   mentionPrefix: true, | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| client.on('debug', console.log) | client.on('debug', console.log) | ||||||
|  | @ -55,10 +62,9 @@ client.on('webhooksUpdate', (guild, channel) => { | ||||||
|   console.log(`Webhooks Updated in #${channel.name} from ${guild.name}`) |   console.log(`Webhooks Updated in #${channel.name} from ${guild.name}`) | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| client.on("commandError", console.error) | client.on('commandError', console.error) | ||||||
| 
 | 
 | ||||||
| class ChannelLog extends Extension { | class ChannelLog extends Extension { | ||||||
| 
 |  | ||||||
|   onChannelCreate(ext: Extension, channel: GuildChannel): void { |   onChannelCreate(ext: Extension, channel: GuildChannel): void { | ||||||
|     console.log(`Channel Created: ${channel.name}`) |     console.log(`Channel Created: ${channel.name}`) | ||||||
|   } |   } | ||||||
|  | @ -81,15 +87,27 @@ class ChannelLog extends Extension { | ||||||
| client.extensions.load(ChannelLog) | client.extensions.load(ChannelLog) | ||||||
| 
 | 
 | ||||||
| client.on('messageDeleteBulk', (channel, messages, uncached) => { | client.on('messageDeleteBulk', (channel, messages, uncached) => { | ||||||
|   console.log(`=== Message Delete Bulk ===\nMessages: ${messages.map(m => m.id).join(', ')}\nUncached: ${[...uncached.values()].join(', ')}`) |   console.log( | ||||||
|  |     `=== Message Delete Bulk ===\nMessages: ${messages | ||||||
|  |       .map((m) => m.id) | ||||||
|  |       .join(', ')}\nUncached: ${[...uncached.values()].join(', ')}` | ||||||
|  |   ) | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| client.on('channelUpdate', (before, after) => { | client.on('channelUpdate', (before, after) => { | ||||||
|   console.log(`Channel Update: ${(before as GuildChannel).name}, ${(after as GuildChannel).name}`) |   console.log( | ||||||
|  |     `Channel Update: ${(before as GuildChannel).name}, ${ | ||||||
|  |       (after as GuildChannel).name | ||||||
|  |     }` | ||||||
|  |   ) | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| client.on('typingStart', (user, channel, at, guildData) => { | client.on('typingStart', (user, channel, at, guildData) => { | ||||||
|   console.log(`${user.tag} started typing in ${channel.id} at ${at}${guildData !== undefined ? `\nGuild: ${guildData.guild.name}` : ''}`) |   console.log( | ||||||
|  |     `${user.tag} started typing in ${channel.id} at ${at}${ | ||||||
|  |       guildData !== undefined ? `\nGuild: ${guildData.guild.name}` : '' | ||||||
|  |     }` | ||||||
|  |   ) | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| client.on('voiceStateAdd', (state) => { | client.on('voiceStateAdd', (state) => { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue