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,4 +6,4 @@ export const DISCORD_CDN_URL: string = 'https://cdn.discordapp.com' | ||||||
| 
 | 
 | ||||||
| export const DISCORD_API_VERSION: number = 8 | export const DISCORD_API_VERSION: number = 8 | ||||||
| 
 | 
 | ||||||
| export const DISCORD_VOICE_VERSION: number = 4 | export const DISCORD_VOICE_VERSION: number = 4 | ||||||
|  |  | ||||||
|  | @ -1,13 +1,13 @@ | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| import { ChannelPayload } from '../../types/channel.ts' | import { ChannelPayload } from '../../types/channel.ts' | ||||||
| 
 | 
 | ||||||
| export const channelDelete: GatewayEventHandler = async ( | export const channelDelete: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|   d: ChannelPayload |   d: ChannelPayload | ||||||
| ) => { | ) => { | ||||||
|   const channel = await gateway.client.channels.get(d.id) |   const channel = await gateway.client.channels.get(d.id) | ||||||
|   if (channel !== undefined) { |   if (channel !== undefined) { | ||||||
|     await gateway.client.channels.delete(d.id) |     await gateway.client.channels.delete(d.id) | ||||||
|     gateway.client.emit('channelDelete', channel) |     gateway.client.emit('channelDelete', channel) | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -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( | ||||||
|  |  | ||||||
|  | @ -1,17 +1,19 @@ | ||||||
| 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 { User } from '../../structures/user.ts' | import { User } from '../../structures/user.ts' | ||||||
| import { GuildBanAddPayload } from '../../types/gateway.ts' | import { GuildBanAddPayload } from '../../types/gateway.ts' | ||||||
| 
 | 
 | ||||||
| export const guildBanAdd: GatewayEventHandler = async ( | export const guildBanAdd: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|   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)) ?? | ||||||
|   if (guild !== undefined) { |     new User(gateway.client, d.user) | ||||||
|     // We don't have to delete member, already done with guildMemberRemove event
 | 
 | ||||||
|     gateway.client.emit('guildBanAdd', guild, user) |   if (guild !== undefined) { | ||||||
|   } |     // We don't have to delete member, already done with guildMemberRemove event
 | ||||||
| } |     gateway.client.emit('guildBanAdd', guild, user) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -1,17 +1,18 @@ | ||||||
| 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 { User } from '../../structures/user.ts' | import { User } from '../../structures/user.ts' | ||||||
| import { GuildBanRemovePayload } from '../../types/gateway.ts' | import { GuildBanRemovePayload } from '../../types/gateway.ts' | ||||||
| 
 | 
 | ||||||
| export const guildBanRemove: GatewayEventHandler = async ( | export const guildBanRemove: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|   d: GuildBanRemovePayload |   d: GuildBanRemovePayload | ||||||
| ) => { | ) => { | ||||||
|   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) { | 
 | ||||||
|     gateway.client.emit('guildBanRemove', guild, user) |   if (guild !== undefined) { | ||||||
|   } |     gateway.client.emit('guildBanRemove', guild, user) | ||||||
| } |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -1,64 +1,32 @@ | ||||||
| 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) { |   await gateway.client.guilds.set(d.id, d) | ||||||
|     // It was just lazy load, so we don't fire the event as its gonna fire for every guild bot is in
 |   const guild = ((await gateway.client.guilds.get(d.id)) as unknown) as Guild | ||||||
|     await gateway.client.guilds.set(d.id, d) |  | ||||||
| 
 | 
 | ||||||
|     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) |   if (d.channels !== undefined) { | ||||||
|       guild.members = members |     for (const ch of d.channels as GuildChannelPayload[]) { | ||||||
|  |       ch.guild_id = d.id | ||||||
|  |       await gateway.client.channels.set(ch.id, ch) | ||||||
|     } |     } | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|     if (d.channels !== undefined) { |   await guild.roles.fromPayload(d.roles) | ||||||
|       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) { |   if (d.voice_states !== undefined) | ||||||
|       const roles = new RolesManager(gateway.client, guild) |     await guild.voiceStates.fromPayload(d.voice_states) | ||||||
|       await roles.fromPayload(d.roles) |  | ||||||
|       guild.roles = roles |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     guild.refreshFromData(d) |   if (hasGuild === undefined) { | ||||||
|   } else { |     // It wasn't lazy load, so emit event
 | ||||||
|     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) |  | ||||||
|     guild = new Guild(gateway.client, d) |  | ||||||
|     gateway.client.emit('guildCreate', guild) |     gateway.client.emit('guildCreate', guild) | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,21 +1,21 @@ | ||||||
| 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 { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| 
 | 
 | ||||||
| export const guildDelte: GatewayEventHandler = async ( | export const guildDelte: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|   d: GuildPayload |   d: GuildPayload | ||||||
| ) => { | ) => { | ||||||
|   const guild: Guild | undefined = await gateway.client.guilds.get(d.id) |   const guild: Guild | undefined = await gateway.client.guilds.get(d.id) | ||||||
| 
 | 
 | ||||||
|   if (guild !== undefined) { |   if (guild !== undefined) { | ||||||
|     guild.refreshFromData(d) |     guild.refreshFromData(d) | ||||||
| 
 | 
 | ||||||
|     await guild.members.flush() |     await guild.members.flush() | ||||||
|     await guild.channels.flush() |     await guild.channels.flush() | ||||||
|     await guild.roles.flush() |     await guild.roles.flush() | ||||||
|     await gateway.client.guilds.delete(d.id) |     await gateway.client.guilds.delete(d.id) | ||||||
| 
 | 
 | ||||||
|     gateway.client.emit('guildDelete', guild) |     gateway.client.emit('guildDelete', 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, | ||||||
|  | @ -11,4 +11,4 @@ export const guildIntegrationsUpdate: GatewayEventHandler = async ( | ||||||
|   if (guild === undefined) return |   if (guild === undefined) return | ||||||
| 
 | 
 | ||||||
|   gateway.client.emit('guildIntegrationsUpdate', guild) |   gateway.client.emit('guildIntegrationsUpdate', guild) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -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,18 +1,18 @@ | ||||||
| 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, | ||||||
|   d: GuildRoleDeletePayload |   d: GuildRoleDeletePayload | ||||||
| ) => { | ) => { | ||||||
|   const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) |   const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) | ||||||
|   // Weird case, shouldn't happen
 |   // Weird case, shouldn't happen
 | ||||||
|   if (guild === undefined) return |   if (guild === undefined) return | ||||||
| 
 | 
 | ||||||
|   const role = await guild.roles.get(d.role_id) |   const role = await guild.roles.get(d.role_id) | ||||||
|   // Shouldn't happen either
 |   // Shouldn't happen either
 | ||||||
|   if(role === undefined) return |   if (role === undefined) return | ||||||
| 
 | 
 | ||||||
|   gateway.client.emit('guildRoleDelete', role) |   gateway.client.emit('guildRoleDelete', role) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,14 +1,14 @@ | ||||||
| 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' | ||||||
| 
 | 
 | ||||||
| export const guildUpdate: GatewayEventHandler = async ( | export const guildUpdate: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|   d: GuildPayload |   d: GuildPayload | ||||||
| ) => { | ) => { | ||||||
|   const after: Guild | undefined = await gateway.client.guilds.get(d.id) |   const after: Guild | undefined = await gateway.client.guilds.get(d.id) | ||||||
|   if (after === undefined) return |   if (after === undefined) return | ||||||
|   const before = after.refreshFromData(d) |   const before = after.refreshFromData(d) | ||||||
|   await gateway.client.guilds.set(d.id, d) |   await gateway.client.guilds.set(d.id, d) | ||||||
|   gateway.client.emit('guildUpdate', before, after) |   gateway.client.emit('guildUpdate', before, after) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -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,19 +1,20 @@ | ||||||
| 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 ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|   d: MessageDeletePayload |   d: MessageDeletePayload | ||||||
| ) => { | ) => { | ||||||
|   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
 |     // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
 | ||||||
|     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) | ||||||
|   await channel.messages.delete(d.id) |     return gateway.client.emit('messageDeleteUncached', d) | ||||||
|   gateway.client.emit('messageDelete', message) |   await channel.messages.delete(d.id) | ||||||
| } |   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,19 +1,22 @@ | ||||||
| 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) | ||||||
|   }) |   }) | ||||||
|    | 
 | ||||||
|   gateway.client.emit('ready') |   gateway.client.emit('ready') | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -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.reconnect() |   gateway: Gateway, | ||||||
| } |   d: any | ||||||
|  | ) => { | ||||||
|  |   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> { |   constructor(client: Client, guild: Guild) { | ||||||
|     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) { |  | ||||||
|     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) | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,69 +1,80 @@ | ||||||
| import { Client } from '../models/client.ts' | import { Client } from '../models/client.ts' | ||||||
| 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 { User } from '../structures/user.ts' | ||||||
| import { MessagePayload } from '../types/channel.ts' | import { MessagePayload } from '../types/channel.ts' | ||||||
| import { CHANNEL_MESSAGE } from '../types/endpoint.ts' | import { CHANNEL_MESSAGE } from '../types/endpoint.ts' | ||||||
| import { BaseManager } from './base.ts' | import { BaseManager } from './base.ts' | ||||||
| 
 | 
 | ||||||
| export class MessagesManager extends BaseManager<MessagePayload, Message> { | export class MessagesManager extends BaseManager<MessagePayload, Message> { | ||||||
|   channel: TextChannel |   channel: TextChannel | ||||||
| 
 | 
 | ||||||
|   constructor (client: Client, channel: TextChannel) { |   constructor(client: Client, channel: TextChannel) { | ||||||
|     super(client, 'messages', Message) |     super(client, 'messages', Message) | ||||||
|     this.channel = channel |     this.channel = channel | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async get (key: string): Promise<Message | undefined> { |   async get(key: string): Promise<Message | undefined> { | ||||||
|     const raw = await this._get(key) |     const raw = await this._get(key) | ||||||
|     if (raw === undefined) return |     if (raw === undefined) return | ||||||
| 
 | 
 | ||||||
|     let channel = await this.client.channels.get(raw.channel_id) |     if (raw.author === undefined) return | ||||||
|     if (channel === undefined) | 
 | ||||||
|       channel = await this.client.channels.fetch(raw.channel_id) |     let channel = await this.client.channels.get(raw.channel_id) | ||||||
| 
 |     if (channel === undefined) | ||||||
|     const author = new User(this.client, raw.author) |       channel = await this.client.channels.fetch(raw.channel_id) | ||||||
| 
 | 
 | ||||||
|     const res = new this.DataType(this.client, raw, channel, author) as any |     let author = ((await this.client.users.get( | ||||||
|     await res.mentions.fromPayload(raw) |       raw.author.id | ||||||
|     return res |     )) as unknown) as User | ||||||
|   } | 
 | ||||||
| 
 |     if (author === undefined) author = new User(this.client, raw.author) | ||||||
|   async set (key: string, value: MessagePayload): Promise<any> { | 
 | ||||||
|     return this.client.cache.set(this.cacheName, key, value, this.client.messageCacheLifetime) |     const res = new this.DataType(this.client, raw, channel, author) as any | ||||||
|   } |     await res.mentions.fromPayload(raw) | ||||||
| 
 |     return res | ||||||
|   async fetch (id: string): Promise<Message> { |   } | ||||||
|     return await new Promise((resolve, reject) => { | 
 | ||||||
|       this.client.rest |   async set(key: string, value: MessagePayload): Promise<any> { | ||||||
|         .get(CHANNEL_MESSAGE(this.channel.id, id)) |     return this.client.cache.set( | ||||||
|         .then(async data => { |       this.cacheName, | ||||||
|           await this.set(id, data as MessagePayload) |       key, | ||||||
| 
 |       value, | ||||||
|           let channel: any = await this.client.channels.get<TextChannel>( |       this.client.messageCacheLifetime | ||||||
|             this.channel.id |     ) | ||||||
|           ) |   } | ||||||
|           if (channel === undefined) | 
 | ||||||
|             channel = await this.client.channels.fetch(this.channel.id) |   async fetch(id: string): Promise<Message> { | ||||||
| 
 |     return await new Promise((resolve, reject) => { | ||||||
|           const author = new User(this.client, (data as MessagePayload).author) |       this.client.rest | ||||||
|           await this.client.users.set( |         .get(CHANNEL_MESSAGE(this.channel.id, id)) | ||||||
|             author.id, |         .then(async (data) => { | ||||||
|             (data as MessagePayload).author |           await this.set(id, data as MessagePayload) | ||||||
|           ) | 
 | ||||||
| 
 |           let channel: any = await this.client.channels.get<TextChannel>( | ||||||
|           const res = new Message( |             this.channel.id | ||||||
|             this.client, |           ) | ||||||
|             data as MessagePayload, |           if (channel === undefined) | ||||||
|             channel as TextChannel, |             channel = await this.client.channels.fetch(this.channel.id) | ||||||
|             author | 
 | ||||||
|           ) |           const author = new User(this.client, (data as MessagePayload).author) | ||||||
| 
 |           await this.client.users.set( | ||||||
|           await res.mentions.fromPayload(data) |             author.id, | ||||||
| 
 |             (data as MessagePayload).author | ||||||
|           resolve(res) |           ) | ||||||
|         }) | 
 | ||||||
|         .catch(e => reject(e)) |           const res = new Message( | ||||||
|     }) |             this.client, | ||||||
|   } |             data as MessagePayload, | ||||||
| } |             channel as TextChannel, | ||||||
|  |             author | ||||||
|  |           ) | ||||||
|  | 
 | ||||||
|  |           await res.mentions.fromPayload(data) | ||||||
|  | 
 | ||||||
|  |           resolve(res) | ||||||
|  |         }) | ||||||
|  |         .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,198 +1,332 @@ | ||||||
| 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, | ||||||
| type PrefixReturnType = string | string[] | Promise<string | string[]> |   CommandsManager, | ||||||
| 
 |   parseCommand, | ||||||
| export interface CommandClientOptions extends ClientOptions { | } from './command.ts' | ||||||
|   prefix: string | string[] | import { ExtensionsManager } from './extensions.ts' | ||||||
|   mentionPrefix?: boolean | 
 | ||||||
|   getGuildPrefix?: (guildID: string) => PrefixReturnType | type PrefixReturnType = string | string[] | Promise<string | string[]> | ||||||
|   getUserPrefix?: (userID: string) => PrefixReturnType | 
 | ||||||
|   isGuildBlacklisted?: (guildID: string) => boolean | Promise<boolean> | export interface CommandClientOptions extends ClientOptions { | ||||||
|   isUserBlacklisted?: (guildID: string) => boolean | Promise<boolean> |   prefix: string | string[] | ||||||
|   isChannelBlacklisted?: (guildID: string) => boolean | Promise<boolean> |   mentionPrefix?: boolean | ||||||
|   spacesAfterPrefix?: boolean |   getGuildPrefix?: (guildID: string) => PrefixReturnType | ||||||
|   betterArgs?: boolean |   getUserPrefix?: (userID: string) => PrefixReturnType | ||||||
|   owners?: string[] |   isGuildBlacklisted?: (guildID: string) => boolean | Promise<boolean> | ||||||
|   allowBots?: boolean |   isUserBlacklisted?: (guildID: string) => boolean | Promise<boolean> | ||||||
|   allowDMs?: boolean |   isChannelBlacklisted?: (guildID: string) => boolean | Promise<boolean> | ||||||
|   caseSensitive?: boolean |   spacesAfterPrefix?: boolean | ||||||
| } |   betterArgs?: boolean | ||||||
| 
 |   owners?: string[] | ||||||
| export class CommandClient extends Client implements CommandClientOptions { |   allowBots?: boolean | ||||||
|   prefix: string | string[] |   allowDMs?: boolean | ||||||
|   mentionPrefix: boolean |   caseSensitive?: boolean | ||||||
|   getGuildPrefix: (guildID: string) => PrefixReturnType | } | ||||||
|   getUserPrefix: (userID: string) => PrefixReturnType | 
 | ||||||
|   isGuildBlacklisted: (guildID: string) => boolean | Promise<boolean> | export class CommandClient extends Client implements CommandClientOptions { | ||||||
|   isUserBlacklisted: (guildID: string) => boolean | Promise<boolean> |   prefix: string | string[] | ||||||
|   isChannelBlacklisted: (guildID: string) => boolean | Promise<boolean> |   mentionPrefix: boolean | ||||||
|   spacesAfterPrefix: boolean |   getGuildPrefix: (guildID: string) => PrefixReturnType | ||||||
|   betterArgs: boolean |   getUserPrefix: (userID: string) => PrefixReturnType | ||||||
|   owners: string[] |   isGuildBlacklisted: (guildID: string) => boolean | Promise<boolean> | ||||||
|   allowBots: boolean |   isUserBlacklisted: (guildID: string) => boolean | Promise<boolean> | ||||||
|   allowDMs: boolean |   isChannelBlacklisted: (guildID: string) => boolean | Promise<boolean> | ||||||
|   caseSensitive: boolean |   spacesAfterPrefix: boolean | ||||||
|   extensions: ExtensionsManager = new ExtensionsManager(this) |   betterArgs: boolean | ||||||
|   commands: CommandsManager = new CommandsManager(this) |   owners: string[] | ||||||
| 
 |   allowBots: boolean | ||||||
|   constructor(options: CommandClientOptions) { |   allowDMs: boolean | ||||||
|     super(options) |   caseSensitive: boolean | ||||||
|     this.prefix = options.prefix |   extensions: ExtensionsManager = new ExtensionsManager(this) | ||||||
|     this.mentionPrefix = |   commands: CommandsManager = new CommandsManager(this) | ||||||
|       options.mentionPrefix === undefined ? false : options.mentionPrefix |   categories: CategoriesManager = new CategoriesManager(this) | ||||||
|     this.getGuildPrefix = | 
 | ||||||
|       options.getGuildPrefix === undefined |   constructor(options: CommandClientOptions) { | ||||||
|         ? (id: string) => this.prefix |     super(options) | ||||||
|         : options.getGuildPrefix |     this.prefix = options.prefix | ||||||
|     this.getUserPrefix = |     this.mentionPrefix = | ||||||
|       options.getUserPrefix === undefined |       options.mentionPrefix === undefined ? false : options.mentionPrefix | ||||||
|         ? (id: string) => this.prefix |     this.getGuildPrefix = | ||||||
|         : options.getUserPrefix |       options.getGuildPrefix === undefined | ||||||
|     this.isUserBlacklisted = |         ? (id: string) => this.prefix | ||||||
|       options.isUserBlacklisted === undefined |         : options.getGuildPrefix | ||||||
|         ? (id: string) => false |     this.getUserPrefix = | ||||||
|         : options.isUserBlacklisted |       options.getUserPrefix === undefined | ||||||
|     this.isGuildBlacklisted = |         ? (id: string) => this.prefix | ||||||
|       options.isGuildBlacklisted === undefined |         : options.getUserPrefix | ||||||
|         ? (id: string) => false |     this.isUserBlacklisted = | ||||||
|         : options.isGuildBlacklisted |       options.isUserBlacklisted === undefined | ||||||
|     this.isChannelBlacklisted = |         ? (id: string) => false | ||||||
|       options.isChannelBlacklisted === undefined |         : options.isUserBlacklisted | ||||||
|         ? (id: string) => false |     this.isGuildBlacklisted = | ||||||
|         : options.isChannelBlacklisted |       options.isGuildBlacklisted === undefined | ||||||
|     this.spacesAfterPrefix = |         ? (id: string) => false | ||||||
|       options.spacesAfterPrefix === undefined |         : options.isGuildBlacklisted | ||||||
|         ? false |     this.isChannelBlacklisted = | ||||||
|         : options.spacesAfterPrefix |       options.isChannelBlacklisted === undefined | ||||||
|     this.betterArgs = |         ? (id: string) => false | ||||||
|       options.betterArgs === undefined ? false : options.betterArgs |         : options.isChannelBlacklisted | ||||||
|     this.owners = options.owners === undefined ? [] : options.owners |     this.spacesAfterPrefix = | ||||||
|     this.allowBots = options.allowBots === undefined ? false : options.allowBots |       options.spacesAfterPrefix === undefined | ||||||
|     this.allowDMs = options.allowDMs === undefined ? true : options.allowDMs |         ? false | ||||||
|     this.caseSensitive = |         : options.spacesAfterPrefix | ||||||
|       options.caseSensitive === undefined ? false : options.caseSensitive |     this.betterArgs = | ||||||
| 
 |       options.betterArgs === undefined ? false : options.betterArgs | ||||||
|     this.on( |     this.owners = options.owners === undefined ? [] : options.owners | ||||||
|       'messageCreate', |     this.allowBots = options.allowBots === undefined ? false : options.allowBots | ||||||
|       async (msg: Message) => await this.processMessage(msg) |     this.allowDMs = options.allowDMs === undefined ? true : options.allowDMs | ||||||
|     ) |     this.caseSensitive = | ||||||
|   } |       options.caseSensitive === undefined ? false : options.caseSensitive | ||||||
| 
 | 
 | ||||||
|   async processMessage(msg: Message): Promise<any> { |     this.on( | ||||||
|     if (!this.allowBots && msg.author.bot === true) return |       'messageCreate', | ||||||
| 
 |       async (msg: Message) => await this.processMessage(msg) | ||||||
|     const isUserBlacklisted = await awaitSync(this.isUserBlacklisted(msg.author.id)) |     ) | ||||||
|     if (isUserBlacklisted === true) return |   } | ||||||
| 
 | 
 | ||||||
|     const isChannelBlacklisted = await awaitSync(this.isChannelBlacklisted(msg.channel.id)) |   async processMessage(msg: Message): Promise<any> { | ||||||
|     if (isChannelBlacklisted === true) return |     if (!this.allowBots && msg.author.bot === true) return | ||||||
| 
 | 
 | ||||||
|     if (msg.guild !== undefined) { |     const isUserBlacklisted = await awaitSync( | ||||||
|       const isGuildBlacklisted = await awaitSync(this.isGuildBlacklisted(msg.guild.id)) |       this.isUserBlacklisted(msg.author.id) | ||||||
|       if (isGuildBlacklisted === true) return |     ) | ||||||
|     } |     if (isUserBlacklisted === true) return | ||||||
| 
 | 
 | ||||||
|     let prefix: string | string[] = this.prefix |     const isChannelBlacklisted = await awaitSync( | ||||||
| 
 |       this.isChannelBlacklisted(msg.channel.id) | ||||||
|     if (msg.guild !== undefined) { |     ) | ||||||
|       prefix = await awaitSync(this.getGuildPrefix(msg.guild.id)) |     if (isChannelBlacklisted === true) return | ||||||
|     } else { | 
 | ||||||
|       prefix = await awaitSync(this.getUserPrefix(msg.author.id)) |     if (msg.guild !== undefined) { | ||||||
|     } |       const isGuildBlacklisted = await awaitSync( | ||||||
| 
 |         this.isGuildBlacklisted(msg.guild.id) | ||||||
|     let mentionPrefix = false |       ) | ||||||
| 
 |       if (isGuildBlacklisted === true) return | ||||||
|     if (typeof prefix === 'string') { |     } | ||||||
|       if (msg.content.startsWith(prefix) === false) { | 
 | ||||||
|         if (this.mentionPrefix) mentionPrefix = true |     let prefix: string | string[] = this.prefix | ||||||
|         else return | 
 | ||||||
|       } |     if (msg.guild !== undefined) { | ||||||
|     } else { |       prefix = await awaitSync(this.getGuildPrefix(msg.guild.id)) | ||||||
|       const usedPrefix = prefix.find(v => msg.content.startsWith(v)) |     } else { | ||||||
|       if (usedPrefix === undefined) { |       prefix = await awaitSync(this.getUserPrefix(msg.author.id)) | ||||||
|         if (this.mentionPrefix) mentionPrefix = true |     } | ||||||
|         else return | 
 | ||||||
|       } |     let mentionPrefix = false | ||||||
|       else prefix = usedPrefix | 
 | ||||||
|     } |     if (typeof prefix === 'string') { | ||||||
| 
 |       if (msg.content.startsWith(prefix) === false) { | ||||||
|     if (mentionPrefix) { |         if (this.mentionPrefix) mentionPrefix = true | ||||||
|       if (msg.content.startsWith(this.user?.mention as string) === true) prefix = this.user?.mention as string |         else return | ||||||
|       else if (msg.content.startsWith(this.user?.nickMention as string) === true) prefix = this.user?.nickMention as string |       } | ||||||
|       else return |     } else { | ||||||
|     } |       const usedPrefix = prefix.find((v) => msg.content.startsWith(v)) | ||||||
| 
 |       if (usedPrefix === undefined) { | ||||||
|     if (typeof prefix !== 'string') return |         if (this.mentionPrefix) mentionPrefix = true | ||||||
| 
 |         else return | ||||||
|     const parsed = parseCommand(this, msg, prefix) |       } else prefix = usedPrefix | ||||||
|     const command = this.commands.find(parsed.name) |     } | ||||||
| 
 | 
 | ||||||
|     if (command === undefined) return |     if (mentionPrefix) { | ||||||
| 
 |       if (msg.content.startsWith(this.user?.mention as string) === true) | ||||||
|     if (command.whitelistedGuilds !== undefined && msg.guild !== undefined && command.whitelistedGuilds.includes(msg.guild.id) === false) return; |         prefix = this.user?.mention as string | ||||||
|     if (command.whitelistedChannels !== undefined && command.whitelistedChannels.includes(msg.channel.id) === false) return; |       else if ( | ||||||
|     if (command.whitelistedUsers !== undefined && command.whitelistedUsers.includes(msg.author.id) === false) return; |         msg.content.startsWith(this.user?.nickMention as string) === true | ||||||
| 
 |       ) | ||||||
|     const ctx: CommandContext = { |         prefix = this.user?.nickMention as string | ||||||
|       client: this, |       else return | ||||||
|       name: parsed.name, |     } | ||||||
|       prefix, | 
 | ||||||
|       args: parsed.args, |     if (typeof prefix !== 'string') return | ||||||
|       argString: parsed.argString, | 
 | ||||||
|       message: msg, |     const parsed = parseCommand(this, msg, prefix) | ||||||
|       author: msg.author, |     const command = this.commands.find(parsed.name) | ||||||
|       command, | 
 | ||||||
|       channel: msg.channel, |     if (command === undefined) return | ||||||
|       guild: msg.guild |     const category = | ||||||
|     } |       command.category !== undefined | ||||||
| 
 |         ? this.categories.get(command.category) | ||||||
|     if (command.ownerOnly === true && !this.owners.includes(msg.author.id)) return this.emit('commandOwnerOnly', ctx, command) |         : undefined | ||||||
|     if (command.guildOnly === true && msg.guild === undefined) return this.emit('commandGuildOnly', ctx, command) | 
 | ||||||
|     if (command.dmOnly === true && msg.guild !== undefined) return this.emit('commandDmOnly', ctx, command) |     // Guild whitelist exists, and if does and Command used in a Guild, is this Guild allowed?
 | ||||||
|      |     // This is a bit confusing here, if these settings on a Command exist, and also do on Category, Command overrides them
 | ||||||
|     if (command.botPermissions !== undefined && msg.guild !== undefined) { |     if ( | ||||||
|       // TODO: Check Overwrites too
 |       command.whitelistedGuilds === undefined && | ||||||
|       const me = await msg.guild.me() |       category?.whitelistedGuilds !== undefined && | ||||||
|       const missing: string[] = [] |       msg.guild !== undefined && | ||||||
|        |       category.whitelistedGuilds.includes(msg.guild.id) === false | ||||||
|       for (const perm of command.botPermissions) { |     ) | ||||||
|         if (me.permissions.has(perm) === false) missing.push(perm) |       return | ||||||
|       } |     if ( | ||||||
| 
 |       command.whitelistedGuilds !== undefined && | ||||||
|       if (missing.length !== 0) return this.emit('commandBotMissingPermissions', ctx, command, missing) |       msg.guild !== undefined && | ||||||
|     } |       command.whitelistedGuilds.includes(msg.guild.id) === false | ||||||
| 
 |     ) | ||||||
|     if (command.permissions !== undefined && msg.guild !== undefined) { |       return | ||||||
|       const missing: string[] = [] | 
 | ||||||
|       let perms: string[] = [] |     // Checks for Channel Whitelist
 | ||||||
|       if (typeof command.permissions === 'string') perms = [command.permissions] |     if ( | ||||||
|       else perms = command.permissions |       command.whitelistedChannels === undefined && | ||||||
|       for (const perm of perms) { |       category?.whitelistedChannels !== undefined && | ||||||
|         const has = msg.member?.permissions.has(perm) |       category.whitelistedChannels.includes(msg.channel.id) === false | ||||||
|         if (has !== true) missing.push(perm) |     ) | ||||||
|       }  |       return | ||||||
|       if (missing.length !== 0) return this.emit('commandMissingPermissions', command, missing, ctx) |     if ( | ||||||
|     } |       command.whitelistedChannels !== undefined && | ||||||
| 
 |       command.whitelistedChannels.includes(msg.channel.id) === false | ||||||
|     if (command.args !== undefined) { |     ) | ||||||
|       if (typeof command.args === 'boolean' && parsed.args.length === 0) return this.emit('commandMissingArgs', ctx, command) |       return | ||||||
|       else if (typeof command.args === 'number' && parsed.args.length < command.args) this.emit('commandMissingArgs', ctx, command)  | 
 | ||||||
|     } |     // Checks for Users Whitelist
 | ||||||
| 
 |     if ( | ||||||
|     try { |       command.whitelistedUsers === undefined && | ||||||
|       this.emit('commandUsed', ctx, command) |       category?.whitelistedUsers !== undefined && | ||||||
| 
 |       category.whitelistedUsers.includes(msg.author.id) === false | ||||||
|       const beforeExecute = await awaitSync(command.beforeExecute(ctx)) |     ) | ||||||
|       if (beforeExecute === false) return |       return | ||||||
| 
 |     if ( | ||||||
|       const result = await awaitSync(command.execute(ctx)) |       command.whitelistedUsers !== undefined && | ||||||
|       command.afterExecute(ctx, result) |       command.whitelistedUsers.includes(msg.author.id) === false | ||||||
|     } catch (e) { |     ) | ||||||
|       this.emit('commandError', command, ctx, e) |       return | ||||||
|     } | 
 | ||||||
|   } |     const ctx: CommandContext = { | ||||||
| } |       client: this, | ||||||
|  |       name: parsed.name, | ||||||
|  |       prefix, | ||||||
|  |       args: parsed.args, | ||||||
|  |       argString: parsed.argString, | ||||||
|  |       message: msg, | ||||||
|  |       author: msg.author, | ||||||
|  |       command, | ||||||
|  |       channel: msg.channel, | ||||||
|  |       guild: msg.guild, | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // In these checks too, Command overrides Category if present
 | ||||||
|  |     // Check if Command is only for Owners
 | ||||||
|  |     if ( | ||||||
|  |       (command.ownerOnly !== undefined || category === undefined | ||||||
|  |         ? command.ownerOnly | ||||||
|  |         : category.ownerOnly) === true && | ||||||
|  |       !this.owners.includes(msg.author.id) | ||||||
|  |     ) | ||||||
|  |       return this.emit('commandOwnerOnly', ctx, command) | ||||||
|  | 
 | ||||||
|  |     // 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
 | ||||||
|  |       const me = await msg.guild.me() | ||||||
|  |       const missing: string[] = [] | ||||||
|  | 
 | ||||||
|  |       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 (missing.length !== 0) | ||||||
|  |           return this.emit( | ||||||
|  |             'commandBotMissingPermissions', | ||||||
|  |             ctx, | ||||||
|  |             command, | ||||||
|  |             missing | ||||||
|  |           ) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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[] = [] | ||||||
|  | 
 | ||||||
|  |         for (const perm of permissions) { | ||||||
|  |           const has = msg.member?.permissions.has(perm) | ||||||
|  |           if (has !== true) missing.push(perm) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (missing.length !== 0) | ||||||
|  |           return this.emit( | ||||||
|  |             'commandUserMissingPermissions', | ||||||
|  |             command, | ||||||
|  |             missing, | ||||||
|  |             ctx | ||||||
|  |           ) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (command.args !== undefined) { | ||||||
|  |       if (typeof command.args === 'boolean' && parsed.args.length === 0) | ||||||
|  |         return this.emit('commandMissingArgs', ctx, command) | ||||||
|  |       else if ( | ||||||
|  |         typeof command.args === 'number' && | ||||||
|  |         parsed.args.length < command.args | ||||||
|  |       ) | ||||||
|  |         this.emit('commandMissingArgs', ctx, command) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     try { | ||||||
|  |       this.emit('commandUsed', ctx, command) | ||||||
|  | 
 | ||||||
|  |       const beforeExecute = await awaitSync(command.beforeExecute(ctx)) | ||||||
|  |       if (beforeExecute === false) return | ||||||
|  | 
 | ||||||
|  |       const result = await awaitSync(command.execute(ctx)) | ||||||
|  |       command.afterExecute(ctx, result) | ||||||
|  |     } catch (e) { | ||||||
|  |       this.emit('commandError', command, ctx, e) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -1,55 +1,63 @@ | ||||||
| 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 | ||||||
|   message: Message |   message: Message | ||||||
|   users: Collection<string, User> = new Collection() |   users: Collection<string, User> = new Collection() | ||||||
|   roles: Collection<string, Role> = new Collection() |   roles: Collection<string, Role> = new Collection() | ||||||
|   channels: Collection<string, GuildTextChannel> = new Collection() |   channels: Collection<string, GuildTextChannel> = new Collection() | ||||||
|   everyone: boolean = false |   everyone: boolean = false | ||||||
| 
 | 
 | ||||||
|   static EVERYONE_MENTION = /@(everyone|here)/g |   static EVERYONE_MENTION = /@(everyone|here)/g | ||||||
|   static USER_MENTION = /<@!?(\d{17,19})>/g |   static USER_MENTION = /<@!?(\d{17,19})>/g | ||||||
|   static ROLE_MENTION = /<@&(\d{17,19})>/g |   static ROLE_MENTION = /<@&(\d{17,19})>/g | ||||||
|   static CHANNEL_MENTION = /<#(\d{17,19})>/g |   static CHANNEL_MENTION = /<#(\d{17,19})>/g | ||||||
| 
 | 
 | ||||||
|   constructor(client: Client, message: Message) { |   constructor(client: Client, message: Message) { | ||||||
|     this.client = client |     this.client = client | ||||||
|     this.message = message |     this.message = message | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async fromPayload(payload: MessagePayload): Promise<MessageMentions> { |   async fromPayload(payload: MessagePayload): Promise<MessageMentions> { | ||||||
|     payload.mentions.forEach(rawUser => { |     if (this.message === undefined) return this | ||||||
|       this.users.set(rawUser.id, new User(this.client, rawUser)) |     if (payload.mentions !== undefined) | ||||||
|     }) |       payload.mentions.forEach((rawUser) => { | ||||||
|      |         this.users.set(rawUser.id, new User(this.client, rawUser)) | ||||||
|     if (this.message.guild !== undefined) { |       }) | ||||||
|       for (const id of payload.mention_roles) { | 
 | ||||||
|         const role = await this.message.guild.roles.get(id) |     if (this.message.guild !== undefined) { | ||||||
|         if(role !== undefined) this.roles.set(role.id, role) |       for (const id of payload.mention_roles) { | ||||||
|       } |         const role = await this.message.guild.roles.get(id) | ||||||
|     } |         if (role !== undefined) this.roles.set(role.id, role) | ||||||
|     if (payload.mention_channels !== undefined) { |       } | ||||||
|       for (const mentionChannel of payload.mention_channels) { |     } | ||||||
|         const channel = await this.client.channels.get<GuildTextChannel>(mentionChannel.id) |     if (payload.mention_channels !== undefined) { | ||||||
|         if (channel !== undefined) this.channels.set(channel.id, channel) |       for (const mentionChannel of payload.mention_channels) { | ||||||
|       } |         const channel = await this.client.channels.get<GuildTextChannel>( | ||||||
|     } |           mentionChannel.id | ||||||
|     const matchChannels = this.message.content.match(MessageMentions.CHANNEL_MENTION) |         ) | ||||||
|     if (matchChannels !== null) { |         if (channel !== undefined) this.channels.set(channel.id, channel) | ||||||
|       for (const id of matchChannels) { |       } | ||||||
|         const parsedID = id.substr(2, id.length - 3) |     } | ||||||
|         const channel = await this.client.channels.get<GuildTextChannel>(parsedID) |     const matchChannels = this.message.content.match( | ||||||
|         if (channel !== undefined) this.channels.set(channel.id, channel) |       MessageMentions.CHANNEL_MENTION | ||||||
|       } |     ) | ||||||
|     } |     if (matchChannels !== null) { | ||||||
|     this.everyone = payload.mention_everyone |       for (const id of matchChannels) { | ||||||
|     return this |         const parsedID = id.substr(2, id.length - 3) | ||||||
|   } |         const channel = await this.client.channels.get<GuildTextChannel>( | ||||||
| } |           parsedID | ||||||
|  |         ) | ||||||
|  |         if (channel !== undefined) this.channels.set(channel.id, channel) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     this.everyone = payload.mention_everyone | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -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) => { | ||||||
|  | @ -114,4 +132,4 @@ for (const file of files) { | ||||||
| 
 | 
 | ||||||
| console.log(`Loaded ${client.commands.count} commands!`) | console.log(`Loaded ${client.commands.count} commands!`) | ||||||
| 
 | 
 | ||||||
| client.connect(TOKEN, Intents.create(['GUILD_MEMBERS', 'GUILD_PRESENCES'])) | client.connect(TOKEN, Intents.create(['GUILD_MEMBERS', 'GUILD_PRESENCES'])) | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue