Merge pull request #43 from DjDeveloperr/main
feat(reactions): added new sructures, managers and events
This commit is contained in:
		
						commit
						c277f67b75
					
				
					 39 changed files with 1475 additions and 772 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_VOICE_VERSION: number = 4 | ||||
| export const DISCORD_VOICE_VERSION: number = 4 | ||||
|  |  | |||
|  | @ -1,13 +1,13 @@ | |||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| import { ChannelPayload } from '../../types/channel.ts' | ||||
| 
 | ||||
| export const channelDelete: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|   d: ChannelPayload | ||||
| ) => { | ||||
|   const channel = await gateway.client.channels.get(d.id) | ||||
|   if (channel !== undefined) { | ||||
|     await gateway.client.channels.delete(d.id) | ||||
|     gateway.client.emit('channelDelete', channel) | ||||
|   } | ||||
| } | ||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| import { ChannelPayload } from '../../types/channel.ts' | ||||
| 
 | ||||
| export const channelDelete: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|   d: ChannelPayload | ||||
| ) => { | ||||
|   const channel = await gateway.client.channels.get(d.id) | ||||
|   if (channel !== undefined) { | ||||
|     await gateway.client.channels.delete(d.id) | ||||
|     gateway.client.emit('channelDelete', channel) | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -6,10 +6,12 @@ export const channelPinsUpdate: GatewayEventHandler = async ( | |||
|   gateway: Gateway, | ||||
|   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) { | ||||
|     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) | ||||
|     await gateway.client.channels.set( | ||||
|  |  | |||
|  | @ -1,17 +1,19 @@ | |||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| import { Guild } from '../../structures/guild.ts' | ||||
| import { User } from '../../structures/user.ts' | ||||
| import { GuildBanAddPayload } from '../../types/gateway.ts' | ||||
| 
 | ||||
| export const guildBanAdd: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|   d: GuildBanAddPayload | ||||
| ) => { | ||||
|   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) | ||||
| 
 | ||||
|   if (guild !== undefined) { | ||||
|     // We don't have to delete member, already done with guildMemberRemove event
 | ||||
|     gateway.client.emit('guildBanAdd', guild, user) | ||||
|   } | ||||
| } | ||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| import { Guild } from '../../structures/guild.ts' | ||||
| import { User } from '../../structures/user.ts' | ||||
| import { GuildBanAddPayload } from '../../types/gateway.ts' | ||||
| 
 | ||||
| export const guildBanAdd: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|   d: GuildBanAddPayload | ||||
| ) => { | ||||
|   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) | ||||
| 
 | ||||
|   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 { Guild } from '../../structures/guild.ts' | ||||
| import { User } from '../../structures/user.ts' | ||||
| import { GuildBanRemovePayload } from '../../types/gateway.ts' | ||||
| 
 | ||||
| export const guildBanRemove: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|   d: GuildBanRemovePayload | ||||
| ) => { | ||||
|   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) | ||||
| 
 | ||||
|   if (guild !== undefined) { | ||||
|     gateway.client.emit('guildBanRemove', guild, user) | ||||
|   } | ||||
| } | ||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| import { Guild } from '../../structures/guild.ts' | ||||
| import { User } from '../../structures/user.ts' | ||||
| import { GuildBanRemovePayload } from '../../types/gateway.ts' | ||||
| 
 | ||||
| export const guildBanRemove: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|   d: GuildBanRemovePayload | ||||
| ) => { | ||||
|   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) | ||||
| 
 | ||||
|   if (guild !== undefined) { | ||||
|     gateway.client.emit('guildBanRemove', guild, user) | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -1,64 +1,32 @@ | |||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| import { Guild } from '../../structures/guild.ts' | ||||
| import { GuildPayload } from '../../types/guild.ts' | ||||
| import { MembersManager } from '../../managers/members.ts' | ||||
| import { GuildChannelPayload } from '../../types/channel.ts' | ||||
| import { RolesManager } from '../../managers/roles.ts' | ||||
| 
 | ||||
| export const guildCreate: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|   d: GuildPayload | ||||
| ) => { | ||||
|   let guild: Guild | undefined = await gateway.client.guilds.get(d.id) | ||||
|   if (guild !== undefined) { | ||||
|     // It was just lazy load, so we don't fire the event as its gonna fire for every guild bot is in
 | ||||
|     await gateway.client.guilds.set(d.id, d) | ||||
|   const hasGuild: Guild | undefined = await gateway.client.guilds.get(d.id) | ||||
|   await gateway.client.guilds.set(d.id, d) | ||||
|   const guild = ((await gateway.client.guilds.get(d.id)) as unknown) as Guild | ||||
| 
 | ||||
|     if (d.members !== undefined) { | ||||
|       const members = new MembersManager(gateway.client, guild) | ||||
|       await members.fromPayload(d.members) | ||||
|       guild.members = members | ||||
|   if (d.members !== undefined) await guild.members.fromPayload(d.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.channels !== undefined) { | ||||
|       for (const ch of d.channels as GuildChannelPayload[]) { | ||||
|         ch.guild_id = d.id | ||||
|         await gateway.client.channels.set(ch.id, ch) | ||||
|       } | ||||
|     } | ||||
|   await guild.roles.fromPayload(d.roles) | ||||
| 
 | ||||
|     if (d.roles !== undefined) { | ||||
|       const roles = new RolesManager(gateway.client, guild) | ||||
|       await roles.fromPayload(d.roles) | ||||
|       guild.roles = roles | ||||
|     } | ||||
|   if (d.voice_states !== undefined) | ||||
|     await guild.voiceStates.fromPayload(d.voice_states) | ||||
| 
 | ||||
|     guild.refreshFromData(d) | ||||
|   } else { | ||||
|     await gateway.client.guilds.set(d.id, d) | ||||
|     guild = new Guild(gateway.client, d) | ||||
| 
 | ||||
|     if (d.members !== undefined) { | ||||
|       const members = new MembersManager(gateway.client, guild) | ||||
|       await members.fromPayload(d.members) | ||||
|       guild.members = members | ||||
|     } | ||||
| 
 | ||||
|     if (d.channels !== undefined) { | ||||
|       for (const ch of d.channels as GuildChannelPayload[]) { | ||||
|         ch.guild_id = d.id | ||||
|         await gateway.client.channels.set(ch.id, ch) | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     if (d.roles !== undefined) { | ||||
|       const roles = new RolesManager(gateway.client, guild) | ||||
|       await roles.fromPayload(d.roles) | ||||
|       guild.roles = roles | ||||
|     } | ||||
| 
 | ||||
|     await guild.roles.fromPayload(d.roles) | ||||
|     guild = new Guild(gateway.client, d) | ||||
|   if (hasGuild === undefined) { | ||||
|     // It wasn't lazy load, so emit event
 | ||||
|     gateway.client.emit('guildCreate', guild) | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -1,21 +1,21 @@ | |||
| import { Guild } from '../../structures/guild.ts' | ||||
| import { GuildPayload } from '../../types/guild.ts' | ||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| 
 | ||||
| export const guildDelte: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|   d: GuildPayload | ||||
| ) => { | ||||
|   const guild: Guild | undefined = await gateway.client.guilds.get(d.id) | ||||
| 
 | ||||
|   if (guild !== undefined) { | ||||
|     guild.refreshFromData(d) | ||||
| 
 | ||||
|     await guild.members.flush() | ||||
|     await guild.channels.flush() | ||||
|     await guild.roles.flush() | ||||
|     await gateway.client.guilds.delete(d.id) | ||||
| 
 | ||||
|     gateway.client.emit('guildDelete', guild) | ||||
|   } | ||||
| } | ||||
| import { Guild } from '../../structures/guild.ts' | ||||
| import { GuildPayload } from '../../types/guild.ts' | ||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| 
 | ||||
| export const guildDelte: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|   d: GuildPayload | ||||
| ) => { | ||||
|   const guild: Guild | undefined = await gateway.client.guilds.get(d.id) | ||||
| 
 | ||||
|   if (guild !== undefined) { | ||||
|     guild.refreshFromData(d) | ||||
| 
 | ||||
|     await guild.members.flush() | ||||
|     await guild.channels.flush() | ||||
|     await guild.roles.flush() | ||||
|     await gateway.client.guilds.delete(d.id) | ||||
| 
 | ||||
|     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 { EmojiPayload } from "../../types/emoji.ts" | ||||
| import { EmojiPayload } from '../../types/emoji.ts' | ||||
| import { GuildEmojiUpdatePayload } from '../../types/gateway.ts' | ||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| 
 | ||||
|  | @ -13,27 +13,27 @@ export const guildEmojiUpdate: GatewayEventHandler = async ( | |||
|     const emojis = await guild.emojis.collection() | ||||
|     const deleted: Emoji[] = [] | ||||
|     const added: Emoji[] = [] | ||||
|     const updated: Array<{ before: Emoji, after: Emoji }> = [] | ||||
|     const updated: Array<{ before: Emoji; after: Emoji }> = [] | ||||
|     const _updated: EmojiPayload[] = [] | ||||
| 
 | ||||
|     for (const raw of d.emojis) { | ||||
|       const has = emojis.get(raw.id) | ||||
|       if (has === undefined) { | ||||
|         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) | ||||
|       } else _updated.push(raw) | ||||
|     } | ||||
| 
 | ||||
|     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) { | ||||
|         await guild.emojis.delete(emoji.id) | ||||
|         deleted.push(emoji) | ||||
|       } 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) | ||||
|         const after = await guild.emojis.get(find.id) as Emoji | ||||
|         const after = (await guild.emojis.get(find.id)) as Emoji | ||||
|         updated.push({ before, after }) | ||||
|       } | ||||
|     } | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| import { Guild } from '../../structures/guild.ts' | ||||
| import { GuildIntegrationsUpdatePayload } from "../../types/gateway.ts" | ||||
| import { GuildIntegrationsUpdatePayload } from '../../types/gateway.ts' | ||||
| 
 | ||||
| export const guildIntegrationsUpdate: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|  | @ -11,4 +11,4 @@ export const guildIntegrationsUpdate: GatewayEventHandler = async ( | |||
|   if (guild === undefined) return | ||||
| 
 | ||||
|   gateway.client.emit('guildIntegrationsUpdate', guild) | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| import { Guild } from '../../structures/guild.ts' | ||||
| import { GuildMemberAddPayload } from "../../types/gateway.ts" | ||||
| import { Member } from "../../structures/member.ts" | ||||
| import { GuildMemberAddPayload } from '../../types/gateway.ts' | ||||
| import { Member } from '../../structures/member.ts' | ||||
| 
 | ||||
| export const guildMemberAdd: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|  | @ -12,6 +12,6 @@ export const guildMemberAdd: GatewayEventHandler = async ( | |||
|   if (guild === undefined) return | ||||
| 
 | ||||
|   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) | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -20,7 +20,7 @@ export const guildMemberUpdate: GatewayEventHandler = async ( | |||
|     nick: d.nick, | ||||
|     premium_since: d.premium_since, | ||||
|     deaf: member?.deaf ?? false, | ||||
|     mute: member?.mute ?? false | ||||
|     mute: member?.mute ?? false, | ||||
|   } | ||||
|   await guild.members.set(d.user.id, newMemberPayload) | ||||
|   const newMember = await guild.members.get(d.user.id) | ||||
|  |  | |||
|  | @ -1,18 +1,18 @@ | |||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| import { Guild } from '../../structures/guild.ts' | ||||
| import { GuildRoleDeletePayload } from "../../types/gateway.ts" | ||||
| 
 | ||||
| export const guildRoleDelete: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|   d: GuildRoleDeletePayload | ||||
| ) => { | ||||
|   const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) | ||||
|   // Weird case, shouldn't happen
 | ||||
|   if (guild === undefined) return | ||||
| 
 | ||||
|   const role = await guild.roles.get(d.role_id) | ||||
|   // Shouldn't happen either
 | ||||
|   if(role === undefined) return | ||||
| 
 | ||||
|   gateway.client.emit('guildRoleDelete', role) | ||||
| } | ||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| import { Guild } from '../../structures/guild.ts' | ||||
| import { GuildRoleDeletePayload } from '../../types/gateway.ts' | ||||
| 
 | ||||
| export const guildRoleDelete: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|   d: GuildRoleDeletePayload | ||||
| ) => { | ||||
|   const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) | ||||
|   // Weird case, shouldn't happen
 | ||||
|   if (guild === undefined) return | ||||
| 
 | ||||
|   const role = await guild.roles.get(d.role_id) | ||||
|   // Shouldn't happen either
 | ||||
|   if (role === undefined) return | ||||
| 
 | ||||
|   gateway.client.emit('guildRoleDelete', role) | ||||
| } | ||||
|  |  | |||
|  | @ -1,14 +1,14 @@ | |||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| import { Guild } from '../../structures/guild.ts' | ||||
| import { GuildPayload } from '../../types/guild.ts' | ||||
| 
 | ||||
| export const guildUpdate: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|   d: GuildPayload | ||||
| ) => { | ||||
|   const after: Guild | undefined = await gateway.client.guilds.get(d.id) | ||||
|   if (after === undefined) return | ||||
|   const before = after.refreshFromData(d) | ||||
|   await gateway.client.guilds.set(d.id, d) | ||||
|   gateway.client.emit('guildUpdate', before, after) | ||||
| } | ||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| import { Guild } from '../../structures/guild.ts' | ||||
| import { GuildPayload } from '../../types/guild.ts' | ||||
| 
 | ||||
| export const guildUpdate: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|   d: GuildPayload | ||||
| ) => { | ||||
|   const after: Guild | undefined = await gateway.client.guilds.get(d.id) | ||||
|   if (after === undefined) return | ||||
|   const before = after.refreshFromData(d) | ||||
|   await gateway.client.guilds.set(d.id, d) | ||||
|   gateway.client.emit('guildUpdate', before, after) | ||||
| } | ||||
|  |  | |||
|  | @ -39,6 +39,12 @@ import { Collection } from '../../utils/collection.ts' | |||
| import { voiceServerUpdate } from './voiceServerUpdate.ts' | ||||
| import { voiceStateUpdate } from './voiceStateUpdate.ts' | ||||
| import { VoiceState } from '../../structures/voiceState.ts' | ||||
| import { messageReactionAdd } from './messageReactionAdd.ts' | ||||
| import { messageReactionRemove } from './messageReactionRemove.ts' | ||||
| import { messageReactionRemoveAll } from './messageReactionRemoveAll.ts' | ||||
| import { messageReactionRemoveEmoji } from './messageReactionRemoveEmoji.ts' | ||||
| import { guildMembersChunk } from './guildMembersChunk.ts' | ||||
| import { presenceUpdate } from './presenceUpdate.ts' | ||||
| import { inviteCreate } from './inviteCreate.ts' | ||||
| import { inviteDelete } from './inviteDelete.ts' | ||||
| 
 | ||||
|  | @ -62,7 +68,7 @@ export const gatewayHandlers: { | |||
|   GUILD_MEMBER_ADD: guildMemberAdd, | ||||
|   GUILD_MEMBER_REMOVE: guildMemberRemove, | ||||
|   GUILD_MEMBER_UPDATE: guildMemberUpdate, | ||||
|   GUILD_MEMBERS_CHUNK: undefined, | ||||
|   GUILD_MEMBERS_CHUNK: guildMembersChunk, | ||||
|   GUILD_ROLE_CREATE: guildRoleCreate, | ||||
|   GUILD_ROLE_UPDATE: guildRoleUpdate, | ||||
|   GUILD_ROLE_DELETE: guildRoleDelete, | ||||
|  | @ -72,16 +78,16 @@ export const gatewayHandlers: { | |||
|   MESSAGE_UPDATE: messageUpdate, | ||||
|   MESSAGE_DELETE: messageDelete, | ||||
|   MESSAGE_DELETE_BULK: messageDeleteBulk, | ||||
|   MESSAGE_REACTION_ADD: undefined, | ||||
|   MESSAGE_REACTION_REMOVE: undefined, | ||||
|   MESSAGE_REACTION_REMOVE_ALL: undefined, | ||||
|   MESSAGE_REACTION_REMOVE_EMOJI: undefined, | ||||
|   PRESENCE_UPDATE: undefined, | ||||
|   MESSAGE_REACTION_ADD: messageReactionAdd, | ||||
|   MESSAGE_REACTION_REMOVE: messageReactionRemove, | ||||
|   MESSAGE_REACTION_REMOVE_ALL: messageReactionRemoveAll, | ||||
|   MESSAGE_REACTION_REMOVE_EMOJI: messageReactionRemoveEmoji, | ||||
|   PRESENCE_UPDATE: presenceUpdate, | ||||
|   TYPING_START: typingStart, | ||||
|   USER_UPDATE: userUpdate, | ||||
|   VOICE_STATE_UPDATE: voiceStateUpdate, | ||||
|   VOICE_SERVER_UPDATE: voiceServerUpdate, | ||||
|   WEBHOOKS_UPDATE: webhooksUpdate | ||||
|   WEBHOOKS_UPDATE: webhooksUpdate, | ||||
| } | ||||
| 
 | ||||
| export interface EventTypes { | ||||
|  | @ -95,37 +101,46 @@ export interface VoiceServerUpdateData { | |||
| } | ||||
| 
 | ||||
| export interface ClientEvents extends EventTypes { | ||||
|   'ready': () => void | ||||
|   'reconnect': () => void | ||||
|   'resumed': () => void | ||||
|   'channelCreate': (channel: Channel) => void | ||||
|   'channelDelete': (channel: Channel) => void | ||||
|   'channelPinsUpdate': (before: TextChannel, after: TextChannel) => void | ||||
|   'channelUpdate': (before: Channel, after: Channel) => void | ||||
|   'guildBanAdd': (guild: Guild, user: User) => void | ||||
|   'guildBanRemove': (guild: Guild, user: User) => void | ||||
|   'guildCreate': (guild: Guild) => void | ||||
|   'guildDelete': (guild: Guild) => void | ||||
|   'guildEmojiAdd': (guild: Guild, emoji: Emoji) => void | ||||
|   'guildEmojiDelete': (guild: Guild, emoji: Emoji) => void | ||||
|   'guildEmojiUpdate': (guild: Guild, before: Emoji, after: Emoji) => void | ||||
|   'guildIntegrationsUpdate': (guild: Guild) => void | ||||
|   'guildMemberAdd': (member: Member) => void | ||||
|   'guildMemberRemove': (member: Member) => void | ||||
|   'guildMemberUpdate': (before: Member, after: Member) => void | ||||
|   'guildRoleCreate': (role: Role) => void | ||||
|   'guildRoleDelete': (role: Role) => void | ||||
|   'guildRoleUpdate': (before: Role, after: Role) => void | ||||
|   'guildUpdate': (before: Guild, after: Guild) => void | ||||
|   'messageCreate': (message: Message) => void | ||||
|   'messageDelete': (message: Message) => void | ||||
|   'messageDeleteBulk': (channel: GuildTextChannel, messages: Collection<string, Message>, uncached: Set<string>) => void | ||||
|   'messageUpdate': (before: Message, after: Message) => void | ||||
|   'typingStart': (user: User, 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 | ||||
|   ready: () => void | ||||
|   reconnect: () => void | ||||
|   resumed: () => void | ||||
|   channelCreate: (channel: Channel) => void | ||||
|   channelDelete: (channel: Channel) => void | ||||
|   channelPinsUpdate: (before: TextChannel, after: TextChannel) => void | ||||
|   channelUpdate: (before: Channel, after: Channel) => void | ||||
|   guildBanAdd: (guild: Guild, user: User) => void | ||||
|   guildBanRemove: (guild: Guild, user: User) => void | ||||
|   guildCreate: (guild: Guild) => void | ||||
|   guildDelete: (guild: Guild) => void | ||||
|   guildEmojiAdd: (guild: Guild, emoji: Emoji) => void | ||||
|   guildEmojiDelete: (guild: Guild, emoji: Emoji) => void | ||||
|   guildEmojiUpdate: (guild: Guild, before: Emoji, after: Emoji) => void | ||||
|   guildIntegrationsUpdate: (guild: Guild) => void | ||||
|   guildMemberAdd: (member: Member) => void | ||||
|   guildMemberRemove: (member: Member) => void | ||||
|   guildMemberUpdate: (before: Member, after: Member) => void | ||||
|   guildRoleCreate: (role: Role) => void | ||||
|   guildRoleDelete: (role: Role) => void | ||||
|   guildRoleUpdate: (before: Role, after: Role) => void | ||||
|   guildUpdate: (before: Guild, after: Guild) => void | ||||
|   messageCreate: (message: Message) => void | ||||
|   messageDelete: (message: Message) => void | ||||
|   messageDeleteBulk: ( | ||||
|     channel: GuildTextChannel, | ||||
|     messages: Collection<string, Message>, | ||||
|     uncached: Set<string> | ||||
|   ) => void | ||||
|   messageUpdate: (before: Message, after: Message) => void | ||||
|   typingStart: ( | ||||
|     user: User, | ||||
|     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 { MessageDeletePayload } from "../../types/gateway.ts" | ||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| 
 | ||||
| export const messageDelete: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|   d: MessageDeletePayload | ||||
| ) => { | ||||
|   let channel = await gateway.client.channels.get<TextChannel>(d.channel_id) | ||||
|   // Fetch the channel if not cached
 | ||||
|   if (channel === undefined) | ||||
|     // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
 | ||||
|     channel = (await gateway.client.channels.fetch(d.channel_id)) as TextChannel | ||||
| 
 | ||||
|   const message = await channel.messages.get(d.id) | ||||
|   if (message === undefined) return gateway.client.emit('messageDeleteUncached', d) | ||||
|   await channel.messages.delete(d.id) | ||||
|   gateway.client.emit('messageDelete', message) | ||||
| } | ||||
| import { TextChannel } from '../../structures/textChannel.ts' | ||||
| import { MessageDeletePayload } from '../../types/gateway.ts' | ||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| 
 | ||||
| export const messageDelete: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|   d: MessageDeletePayload | ||||
| ) => { | ||||
|   let channel = await gateway.client.channels.get<TextChannel>(d.channel_id) | ||||
|   // Fetch the channel if not cached
 | ||||
|   if (channel === undefined) | ||||
|     // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
 | ||||
|     channel = (await gateway.client.channels.fetch(d.channel_id)) as TextChannel | ||||
| 
 | ||||
|   const message = await channel.messages.get(d.id) | ||||
|   if (message === undefined) | ||||
|     return gateway.client.emit('messageDeleteUncached', d) | ||||
|   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 { MessageDeleteBulkPayload } from "../../types/gateway.ts" | ||||
| import { Collection } from "../../utils/collection.ts" | ||||
| import { MessageDeleteBulkPayload } from '../../types/gateway.ts' | ||||
| import { Collection } from '../../utils/collection.ts' | ||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| 
 | ||||
| export const messageDeleteBulk: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|   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
 | ||||
|   if (channel === undefined) | ||||
|     // 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 uncached = new Set<string>() | ||||
|  |  | |||
							
								
								
									
										51
									
								
								src/gateway/handlers/messageReactionAdd.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/gateway/handlers/messageReactionAdd.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,51 @@ | |||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| import { MessageReactionAddPayload } from '../../types/gateway.ts' | ||||
| import { TextChannel } from '../../structures/textChannel.ts' | ||||
| import { MessageReaction } from '../../structures/messageReaction.ts' | ||||
| import { UserPayload } from '../../types/user.ts' | ||||
| 
 | ||||
| export const messageReactionAdd: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|   d: MessageReactionAddPayload | ||||
| ) => { | ||||
|   let channel = await gateway.client.channels.get<TextChannel>(d.channel_id) | ||||
|   if (channel === undefined) | ||||
|     channel = await gateway.client.channels.fetch<TextChannel>(d.channel_id) | ||||
|   if (channel === undefined) return | ||||
| 
 | ||||
|   let message = await channel.messages.get(d.message_id) | ||||
|   if (message === undefined) { | ||||
|     if (gateway.client.fetchUncachedReactions === true) { | ||||
|       message = await channel.messages.fetch(d.message_id) | ||||
|       if (message === undefined) return | ||||
|     } else return | ||||
|   } | ||||
| 
 | ||||
|   let user = await gateway.client.users.get(d.user_id) | ||||
|   if (user === undefined) { | ||||
|     if (gateway.client.fetchUncachedReactions === true) { | ||||
|       user = await gateway.client.users.fetch(d.user_id) | ||||
|       if (user === undefined) return | ||||
|     } else return | ||||
|   } | ||||
| 
 | ||||
|   let reaction = await message.reactions.get(d.emoji.id) | ||||
|   if (reaction === undefined) { | ||||
|     await message.reactions.set(d.emoji.id, { | ||||
|       count: 1, | ||||
|       emoji: d.emoji, | ||||
|       me: d.user_id === gateway.client.user?.id, | ||||
|     }) | ||||
|     reaction = ((await message.reactions.get( | ||||
|       d.emoji.id | ||||
|     )) as unknown) as MessageReaction | ||||
|   } | ||||
| 
 | ||||
|   const rawUser = ((await gateway.client.users.get( | ||||
|     d.user_id | ||||
|   )) as unknown) as UserPayload | ||||
| 
 | ||||
|   reaction.users.set(rawUser.id, rawUser) | ||||
| 
 | ||||
|   gateway.client.emit('messageReactionAdd', reaction, user) | ||||
| } | ||||
							
								
								
									
										36
									
								
								src/gateway/handlers/messageReactionRemove.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/gateway/handlers/messageReactionRemove.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | |||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| import { MessageReactionRemovePayload } from '../../types/gateway.ts' | ||||
| import { TextChannel } from '../../structures/textChannel.ts' | ||||
| 
 | ||||
| export const messageReactionRemove: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|   d: MessageReactionRemovePayload | ||||
| ) => { | ||||
|   let channel = await gateway.client.channels.get<TextChannel>(d.channel_id) | ||||
|   if (channel === undefined) | ||||
|     channel = await gateway.client.channels.fetch<TextChannel>(d.channel_id) | ||||
|   if (channel === undefined) return | ||||
| 
 | ||||
|   let message = await channel.messages.get(d.message_id) | ||||
|   if (message === undefined) { | ||||
|     if (gateway.client.fetchUncachedReactions === true) { | ||||
|       message = await channel.messages.fetch(d.message_id) | ||||
|       if (message === undefined) return | ||||
|     } else return | ||||
|   } | ||||
| 
 | ||||
|   let user = await gateway.client.users.get(d.user_id) | ||||
|   if (user === undefined) { | ||||
|     if (gateway.client.fetchUncachedReactions === true) { | ||||
|       user = await gateway.client.users.fetch(d.user_id) | ||||
|       if (user === undefined) return | ||||
|     } else return | ||||
|   } | ||||
| 
 | ||||
|   const reaction = await message.reactions.get(d.emoji.id) | ||||
|   if (reaction === undefined) return | ||||
| 
 | ||||
|   reaction.users.delete(d.user_id) | ||||
| 
 | ||||
|   gateway.client.emit('messageReactionRemove', reaction, user) | ||||
| } | ||||
							
								
								
									
										25
									
								
								src/gateway/handlers/messageReactionRemoveAll.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/gateway/handlers/messageReactionRemoveAll.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,25 @@ | |||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| import { MessageReactionRemoveAllPayload } from '../../types/gateway.ts' | ||||
| import { TextChannel } from '../../structures/textChannel.ts' | ||||
| 
 | ||||
| export const messageReactionRemoveAll: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|   d: MessageReactionRemoveAllPayload | ||||
| ) => { | ||||
|   let channel = await gateway.client.channels.get<TextChannel>(d.channel_id) | ||||
|   if (channel === undefined) | ||||
|     channel = await gateway.client.channels.fetch<TextChannel>(d.channel_id) | ||||
|   if (channel === undefined) return | ||||
| 
 | ||||
|   let message = await channel.messages.get(d.message_id) | ||||
|   if (message === undefined) { | ||||
|     if (gateway.client.fetchUncachedReactions === true) { | ||||
|       message = await channel.messages.fetch(d.message_id) | ||||
|       if (message === undefined) return | ||||
|     } else return | ||||
|   } | ||||
| 
 | ||||
|   await message.reactions.flush() | ||||
| 
 | ||||
|   gateway.client.emit('messageReactionRemoveAll', message) | ||||
| } | ||||
							
								
								
									
										28
									
								
								src/gateway/handlers/messageReactionRemoveEmoji.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/gateway/handlers/messageReactionRemoveEmoji.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | |||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| import { MessageReactionRemoveEmojiPayload } from '../../types/gateway.ts' | ||||
| import { TextChannel } from '../../structures/textChannel.ts' | ||||
| 
 | ||||
| export const messageReactionRemoveEmoji: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|   d: MessageReactionRemoveEmojiPayload | ||||
| ) => { | ||||
|   let channel = await gateway.client.channels.get<TextChannel>(d.channel_id) | ||||
|   if (channel === undefined) | ||||
|     channel = await gateway.client.channels.fetch<TextChannel>(d.channel_id) | ||||
|   if (channel === undefined) return | ||||
| 
 | ||||
|   let message = await channel.messages.get(d.message_id) | ||||
|   if (message === undefined) { | ||||
|     if (gateway.client.fetchUncachedReactions === true) { | ||||
|       message = await channel.messages.fetch(d.message_id) | ||||
|       if (message === undefined) return | ||||
|     } else return | ||||
|   } | ||||
| 
 | ||||
|   const reaction = await message.reactions.get(d.emoji.id) | ||||
|   if (reaction === undefined) return | ||||
| 
 | ||||
|   await reaction.users.flush() | ||||
| 
 | ||||
|   gateway.client.emit('messageReactionRemoveEmoji', message, reaction.emoji) | ||||
| } | ||||
|  | @ -1,6 +1,5 @@ | |||
| import { Message } from '../../structures/message.ts' | ||||
| import { TextChannel } from '../../structures/textChannel.ts' | ||||
| import { User } from '../../structures/user.ts' | ||||
| import { MessagePayload } from '../../types/channel.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) | ||||
|   // Fetch the channel if not cached
 | ||||
|   if (channel === undefined) | ||||
|     // 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) | ||||
| 
 | ||||
|   if (channel === undefined) return | ||||
| 
 | ||||
|   const message = await channel.messages.get(d.id) | ||||
|   const author = | ||||
|     message?.author !== undefined | ||||
|       ? message.author | ||||
|       : new User(gateway.client, d.author) | ||||
|   const newMsg = new Message(gateway.client, d, channel, author) | ||||
|   if (message === undefined) { | ||||
|     await channel.messages.set(d.id, d) | ||||
|     return gateway.client.emit('messageUpdateUncached', newMsg) | ||||
|   } | ||||
|   await channel.messages.set(d.id, d) | ||||
|   if (message === undefined) return | ||||
|   const raw = await channel.messages._get(d.id) | ||||
|   if (raw === undefined) return | ||||
| 
 | ||||
|   const newRaw = raw | ||||
|   Object.assign(newRaw, d) | ||||
|   await channel.messages.set(d.id, newRaw) | ||||
| 
 | ||||
|   const newMsg = ((await channel.messages.get(d.id)) as unknown) as Message | ||||
|   gateway.client.emit('messageUpdate', message, newMsg) | ||||
| } | ||||
|  |  | |||
							
								
								
									
										6
									
								
								src/gateway/handlers/presenceUpdate.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/gateway/handlers/presenceUpdate.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | |||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| 
 | ||||
| export const presenceUpdate: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|   d: any | ||||
| ) => {} | ||||
|  | @ -1,19 +1,22 @@ | |||
| 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 { 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() | ||||
| 
 | ||||
|   gateway.client.user = new User(gateway.client, d.user) | ||||
|   gateway.sessionID = d.session_id | ||||
|   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) => { | ||||
|     gateway.client.guilds.set(guild.id, guild) | ||||
|   }) | ||||
|    | ||||
| 
 | ||||
|   gateway.client.emit('ready') | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -1,5 +1,8 @@ | |||
| import { Gateway , GatewayEventHandler } from '../index.ts' | ||||
| 
 | ||||
| export const reconnect: GatewayEventHandler = async (gateway: Gateway, d: any) => { | ||||
|     gateway.reconnect() | ||||
| } | ||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| 
 | ||||
| export const reconnect: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|   d: any | ||||
| ) => { | ||||
|   gateway.reconnect() | ||||
| } | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| import { Guild } from "../../structures/guild.ts" | ||||
| import { VoiceServerUpdatePayload } from "../../types/gateway.ts" | ||||
| import { Guild } from '../../structures/guild.ts' | ||||
| import { VoiceServerUpdatePayload } from '../../types/gateway.ts' | ||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| 
 | ||||
| export const voiceServerUpdate: GatewayEventHandler = async ( | ||||
|  | @ -9,6 +9,6 @@ export const voiceServerUpdate: GatewayEventHandler = async ( | |||
|   gateway.client.emit('voiceServerUpdate', { | ||||
|     token: d.token, | ||||
|     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 { VoiceState } from "../../structures/voiceState.ts" | ||||
| import { VoiceStatePayload } from "../../types/voice.ts" | ||||
| import { Guild } from '../../structures/guild.ts' | ||||
| import { VoiceState } from '../../structures/voiceState.ts' | ||||
| import { MemberPayload } from '../../types/guild.ts' | ||||
| import { VoiceStatePayload } from '../../types/voice.ts' | ||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| 
 | ||||
| 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)
 | ||||
|   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) | ||||
| 
 | ||||
|   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
 | ||||
|     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 | ||||
|   } | ||||
| 
 | ||||
|   await guild.voiceStates.set(d.user_id, d) | ||||
|   const newVoiceState = await guild.voiceStates.get(d.user_id) | ||||
|   if (voiceState === undefined) { | ||||
|     gateway.client.emit('voiceStateAdd', (newVoiceState as unknown) as VoiceState) | ||||
|     gateway.client.emit( | ||||
|       'voiceStateAdd', | ||||
|       (newVoiceState as unknown) as VoiceState | ||||
|     ) | ||||
|   } 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 { Guild } from '../../structures/guild.ts' | ||||
| import { WebhooksUpdatePayload } from "../../types/gateway.ts" | ||||
| import { GuildTextChannel } from "../../structures/textChannel.ts" | ||||
| import { WebhooksUpdatePayload } from '../../types/gateway.ts' | ||||
| import { GuildTextChannel } from '../../structures/textChannel.ts' | ||||
| 
 | ||||
| export const webhooksUpdate: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|  | @ -10,7 +10,10 @@ export const webhooksUpdate: GatewayEventHandler = async ( | |||
|   const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) | ||||
|   if (guild === undefined) return | ||||
| 
 | ||||
|   const channel: GuildTextChannel | undefined = await guild.channels.get(d.channel_id) as GuildTextChannel | ||||
|   if (channel === undefined) gateway.client.emit('webhooksUpdateUncached', guild, d.channel_id) | ||||
|   const channel: GuildTextChannel | undefined = (await guild.channels.get( | ||||
|     d.channel_id | ||||
|   )) as GuildTextChannel | ||||
|   if (channel === undefined) | ||||
|     gateway.client.emit('webhooksUpdateUncached', guild, d.channel_id) | ||||
|   else gateway.client.emit('webhooksUpdate', guild, channel) | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -1,30 +1,48 @@ | |||
| import { Client } from '../models/client.ts' | ||||
| import { Guild } from "../structures/guild.ts" | ||||
| import { VoiceChannel } from "../structures/guildVoiceChannel.ts" | ||||
| import { User } from "../structures/user.ts" | ||||
| import { VoiceState } from "../structures/voiceState.ts" | ||||
| import { VoiceStatePayload } from "../types/voice.ts" | ||||
| import { Guild } from '../structures/guild.ts' | ||||
| import { VoiceChannel } from '../structures/guildVoiceChannel.ts' | ||||
| import { User } from '../structures/user.ts' | ||||
| import { VoiceState } from '../structures/voiceState.ts' | ||||
| import { VoiceStatePayload } from '../types/voice.ts' | ||||
| import { BaseManager } from './base.ts' | ||||
| 
 | ||||
| export class GuildVoiceStatesManager extends BaseManager<VoiceStatePayload, VoiceState> { | ||||
| export class GuildVoiceStatesManager extends BaseManager< | ||||
|   VoiceStatePayload, | ||||
|   VoiceState | ||||
| > { | ||||
|   guild: Guild | ||||
| 
 | ||||
|   async get (key: string): Promise<VoiceState | undefined> { | ||||
|     const raw = await this._get(key) | ||||
|     if (raw === undefined) return | ||||
| 
 | ||||
|     const guild = raw.guild_id === undefined ? undefined : await this.client.guilds.get(raw.guild_id) | ||||
| 
 | ||||
|     return new VoiceState(this.client, raw, { | ||||
|       user: (await this.client.users.get(raw.user_id) as unknown) as User, | ||||
|       channel: raw.channel_id == null ? null : (await this.client.channels.get<VoiceChannel>(raw.channel_id) as unknown) as VoiceChannel, | ||||
|       guild, | ||||
|       member: guild === undefined ? undefined : await guild.members.get(raw.user_id)  | ||||
|     }) | ||||
|   } | ||||
| 
 | ||||
|   constructor (client: Client, guild: Guild) { | ||||
|   constructor(client: Client, guild: Guild) { | ||||
|     super(client, `vs:${guild.id}`, VoiceState) | ||||
|     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) | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  |  | |||
							
								
								
									
										44
									
								
								src/managers/messageReactions.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/managers/messageReactions.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,44 @@ | |||
| import { Client } from '../models/client.ts' | ||||
| import { Emoji } from '../structures/emoji.ts' | ||||
| import { Guild } from '../structures/guild.ts' | ||||
| import { Message } from '../structures/message.ts' | ||||
| import { MessageReaction } from '../structures/messageReaction.ts' | ||||
| import { Reaction } from '../types/channel.ts' | ||||
| import { BaseManager } from './base.ts' | ||||
| 
 | ||||
| export class MessageReactionsManager extends BaseManager< | ||||
|   Reaction, | ||||
|   MessageReaction | ||||
| > { | ||||
|   message: Message | ||||
| 
 | ||||
|   constructor(client: Client, message: Message) { | ||||
|     super(client, `reactions:${message.id}`, Guild) | ||||
|     this.message = message | ||||
|   } | ||||
| 
 | ||||
|   async get(id: string): Promise<MessageReaction | undefined> { | ||||
|     const raw = await this._get(id) | ||||
|     if (raw === undefined) return | ||||
| 
 | ||||
|     let emoji = await this.client.emojis.get(raw.emoji.id) | ||||
|     if (emoji === undefined) emoji = new Emoji(this.client, raw.emoji) | ||||
| 
 | ||||
|     const reaction = new MessageReaction(this.client, raw, this.message, emoji) | ||||
|     return reaction | ||||
|   } | ||||
| 
 | ||||
|   async set(key: string, value: Reaction): Promise<any> { | ||||
|     return this.client.cache.set( | ||||
|       this.cacheName, | ||||
|       key, | ||||
|       value, | ||||
|       this.client.reactionCacheLifetime | ||||
|     ) | ||||
|   } | ||||
| 
 | ||||
|   async flush(): Promise<any> { | ||||
|     await this.client.cache.deleteCache(`reaction_users:${this.message.id}`) | ||||
|     return this.client.cache.deleteCache(this.cacheName) | ||||
|   } | ||||
| } | ||||
|  | @ -1,69 +1,80 @@ | |||
| import { Client } from '../models/client.ts' | ||||
| import { Message } from '../structures/message.ts' | ||||
| import { TextChannel } from '../structures/textChannel.ts' | ||||
| import { User } from '../structures/user.ts' | ||||
| import { MessagePayload } from '../types/channel.ts' | ||||
| import { CHANNEL_MESSAGE } from '../types/endpoint.ts' | ||||
| import { BaseManager } from './base.ts' | ||||
| 
 | ||||
| export class MessagesManager extends BaseManager<MessagePayload, Message> { | ||||
|   channel: TextChannel | ||||
| 
 | ||||
|   constructor (client: Client, channel: TextChannel) { | ||||
|     super(client, 'messages', Message) | ||||
|     this.channel = channel | ||||
|   } | ||||
| 
 | ||||
|   async get (key: string): Promise<Message | undefined> { | ||||
|     const raw = await this._get(key) | ||||
|     if (raw === undefined) return | ||||
| 
 | ||||
|     let channel = await this.client.channels.get(raw.channel_id) | ||||
|     if (channel === undefined) | ||||
|       channel = await this.client.channels.fetch(raw.channel_id) | ||||
| 
 | ||||
|     const author = new User(this.client, raw.author) | ||||
| 
 | ||||
|     const res = new this.DataType(this.client, raw, channel, author) as any | ||||
|     await res.mentions.fromPayload(raw) | ||||
|     return res | ||||
|   } | ||||
| 
 | ||||
|   async set (key: string, value: MessagePayload): Promise<any> { | ||||
|     return this.client.cache.set(this.cacheName, key, value, this.client.messageCacheLifetime) | ||||
|   } | ||||
| 
 | ||||
|   async fetch (id: string): Promise<Message> { | ||||
|     return await new Promise((resolve, reject) => { | ||||
|       this.client.rest | ||||
|         .get(CHANNEL_MESSAGE(this.channel.id, id)) | ||||
|         .then(async data => { | ||||
|           await this.set(id, data as MessagePayload) | ||||
| 
 | ||||
|           let channel: any = await this.client.channels.get<TextChannel>( | ||||
|             this.channel.id | ||||
|           ) | ||||
|           if (channel === undefined) | ||||
|             channel = await this.client.channels.fetch(this.channel.id) | ||||
| 
 | ||||
|           const author = new User(this.client, (data as MessagePayload).author) | ||||
|           await this.client.users.set( | ||||
|             author.id, | ||||
|             (data as MessagePayload).author | ||||
|           ) | ||||
| 
 | ||||
|           const res = new Message( | ||||
|             this.client, | ||||
|             data as MessagePayload, | ||||
|             channel as TextChannel, | ||||
|             author | ||||
|           ) | ||||
| 
 | ||||
|           await res.mentions.fromPayload(data) | ||||
| 
 | ||||
|           resolve(res) | ||||
|         }) | ||||
|         .catch(e => reject(e)) | ||||
|     }) | ||||
|   } | ||||
| } | ||||
| import { Client } from '../models/client.ts' | ||||
| import { Message } from '../structures/message.ts' | ||||
| import { TextChannel } from '../structures/textChannel.ts' | ||||
| import { User } from '../structures/user.ts' | ||||
| import { MessagePayload } from '../types/channel.ts' | ||||
| import { CHANNEL_MESSAGE } from '../types/endpoint.ts' | ||||
| import { BaseManager } from './base.ts' | ||||
| 
 | ||||
| export class MessagesManager extends BaseManager<MessagePayload, Message> { | ||||
|   channel: TextChannel | ||||
| 
 | ||||
|   constructor(client: Client, channel: TextChannel) { | ||||
|     super(client, 'messages', Message) | ||||
|     this.channel = channel | ||||
|   } | ||||
| 
 | ||||
|   async get(key: string): Promise<Message | undefined> { | ||||
|     const raw = await this._get(key) | ||||
|     if (raw === undefined) return | ||||
| 
 | ||||
|     if (raw.author === undefined) return | ||||
| 
 | ||||
|     let channel = await this.client.channels.get(raw.channel_id) | ||||
|     if (channel === undefined) | ||||
|       channel = await this.client.channels.fetch(raw.channel_id) | ||||
| 
 | ||||
|     let author = ((await this.client.users.get( | ||||
|       raw.author.id | ||||
|     )) as unknown) as User | ||||
| 
 | ||||
|     if (author === undefined) author = new User(this.client, raw.author) | ||||
| 
 | ||||
|     const res = new this.DataType(this.client, raw, channel, author) as any | ||||
|     await res.mentions.fromPayload(raw) | ||||
|     return res | ||||
|   } | ||||
| 
 | ||||
|   async set(key: string, value: MessagePayload): Promise<any> { | ||||
|     return this.client.cache.set( | ||||
|       this.cacheName, | ||||
|       key, | ||||
|       value, | ||||
|       this.client.messageCacheLifetime | ||||
|     ) | ||||
|   } | ||||
| 
 | ||||
|   async fetch(id: string): Promise<Message> { | ||||
|     return await new Promise((resolve, reject) => { | ||||
|       this.client.rest | ||||
|         .get(CHANNEL_MESSAGE(this.channel.id, id)) | ||||
|         .then(async (data) => { | ||||
|           await this.set(id, data as MessagePayload) | ||||
| 
 | ||||
|           let channel: any = await this.client.channels.get<TextChannel>( | ||||
|             this.channel.id | ||||
|           ) | ||||
|           if (channel === undefined) | ||||
|             channel = await this.client.channels.fetch(this.channel.id) | ||||
| 
 | ||||
|           const author = new User(this.client, (data as MessagePayload).author) | ||||
|           await this.client.users.set( | ||||
|             author.id, | ||||
|             (data as MessagePayload).author | ||||
|           ) | ||||
| 
 | ||||
|           const res = new Message( | ||||
|             this.client, | ||||
|             data as MessagePayload, | ||||
|             channel as TextChannel, | ||||
|             author | ||||
|           ) | ||||
| 
 | ||||
|           await res.mentions.fromPayload(data) | ||||
| 
 | ||||
|           resolve(res) | ||||
|         }) | ||||
|         .catch((e) => reject(e)) | ||||
|     }) | ||||
|   } | ||||
| } | ||||
|  |  | |||
							
								
								
									
										13
									
								
								src/managers/reactionUsers.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/managers/reactionUsers.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | |||
| import { Client } from '../models/client.ts' | ||||
| import { MessageReaction } from '../structures/messageReaction.ts' | ||||
| import { UserManager } from './users.ts' | ||||
| 
 | ||||
| export class ReactionUsersManager extends UserManager { | ||||
|   reaction: MessageReaction | ||||
| 
 | ||||
|   constructor(client: Client, reaction: MessageReaction) { | ||||
|     super(client) | ||||
|     this.cacheName = `reaction_users:${reaction.message.id}` | ||||
|     this.reaction = reaction | ||||
|   } | ||||
| } | ||||
|  | @ -7,12 +7,10 @@ import { DefaultCacheAdapter, ICacheAdapter } from './cacheAdapter.ts' | |||
| import { UserManager } from '../managers/users.ts' | ||||
| import { GuildManager } from '../managers/guilds.ts' | ||||
| import { ChannelsManager } from '../managers/channels.ts' | ||||
| import { | ||||
|   ClientPresence | ||||
| } from '../structures/presence.ts' | ||||
| import { ClientPresence } from '../structures/presence.ts' | ||||
| import { EmojisManager } from '../managers/emojis.ts' | ||||
| import { ActivityGame, ClientActivity } from "../types/presence.ts" | ||||
| import { ClientEvents } from "../gateway/handlers/index.ts" | ||||
| import { ActivityGame, ClientActivity } from '../types/presence.ts' | ||||
| import { ClientEvents } from '../gateway/handlers/index.ts' | ||||
| // import { Application } from "../../mod.ts"
 | ||||
| 
 | ||||
| /** Some Client Options to modify behaviour */ | ||||
|  | @ -22,9 +20,9 @@ export interface ClientOptions { | |||
|   /** Gateway Intents */ | ||||
|   intents?: GatewayIntents[] | ||||
|   /** Cache Adapter to use, defaults to Collections one */ | ||||
|   cache?: ICacheAdapter, | ||||
|   cache?: ICacheAdapter | ||||
|   /** Force New Session and don't use cached Session (by persistent caching) */ | ||||
|   forceNewSession?: boolean, | ||||
|   forceNewSession?: boolean | ||||
|   /** Startup presence of client */ | ||||
|   presence?: ClientPresence | ClientActivity | ActivityGame | ||||
|   /** Whether it's a bot user or not? Use this if selfbot! */ | ||||
|  | @ -33,19 +31,21 @@ export interface ClientOptions { | |||
|   canary?: boolean | ||||
|   /** Time till which Messages are to be cached, in MS. Default is 3600000 */ | ||||
|   messageCacheLifetime?: number | ||||
|   /** Time till which Message Reactions are to be cached, in MS. Default is 3600000 */ | ||||
|   reactionCacheLifetime?: number | ||||
|   /** Whether to fetch Uncached Message of Reaction or not? */ | ||||
|   fetchUncachedReactions?: boolean | ||||
| } | ||||
| 
 | ||||
| export declare interface Client { | ||||
|   on: <U extends string>( | ||||
|     event: U, listener: ClientEvents[U] | ||||
|   ) => this | ||||
|   on: <U extends string>(event: U, listener: ClientEvents[U]) => this | ||||
| 
 | ||||
|   emit: <U extends string>( | ||||
|     event: U, ...args: Parameters<ClientEvents[U]> | ||||
|     event: U, | ||||
|     ...args: Parameters<ClientEvents[U]> | ||||
|   ) => boolean | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Discord Client. | ||||
|  */ | ||||
|  | @ -68,12 +68,16 @@ export class Client extends EventEmitter { | |||
|   forceNewSession?: boolean | ||||
|   /** Time till messages to stay cached, in MS. */ | ||||
|   messageCacheLifetime: number = 3600000 | ||||
|   /** Time till messages to stay cached, in MS. */ | ||||
|   reactionCacheLifetime: number = 3600000 | ||||
|   /** Whether to fetch Uncached Message of Reaction or not? */ | ||||
|   fetchUncachedReactions: boolean = false | ||||
| 
 | ||||
|   users: UserManager = new UserManager(this) | ||||
|   guilds: GuildManager = new GuildManager(this) | ||||
|   channels: ChannelsManager = new ChannelsManager(this) | ||||
|   emojis: EmojisManager = new EmojisManager(this) | ||||
|    | ||||
| 
 | ||||
|   /** Whether this client will login as bot user or not */ | ||||
|   bot: boolean = true | ||||
|   /** Whether the REST Manager will use Canary API or not */ | ||||
|  | @ -81,7 +85,7 @@ export class Client extends EventEmitter { | |||
|   /** Client's presence. Startup one if set before connecting */ | ||||
|   presence: ClientPresence = new ClientPresence() | ||||
| 
 | ||||
|   constructor (options: ClientOptions = {}) { | ||||
|   constructor(options: ClientOptions = {}) { | ||||
|     super() | ||||
|     this.token = options.token | ||||
|     this.intents = options.intents | ||||
|  | @ -94,17 +98,22 @@ export class Client extends EventEmitter { | |||
|           : new ClientPresence(options.presence) | ||||
|     if (options.bot === false) this.bot = false | ||||
|     if (options.canary === true) this.canary = true | ||||
|     if (options.messageCacheLifetime !== undefined) this.messageCacheLifetime = options.messageCacheLifetime | ||||
|     if (options.messageCacheLifetime !== undefined) | ||||
|       this.messageCacheLifetime = options.messageCacheLifetime | ||||
|     if (options.reactionCacheLifetime !== undefined) | ||||
|       this.reactionCacheLifetime = options.reactionCacheLifetime | ||||
|     if (options.fetchUncachedReactions === true) | ||||
|       this.fetchUncachedReactions = true | ||||
|   } | ||||
| 
 | ||||
|   /** Set Cache Adapter */ | ||||
|   setAdapter (adapter: ICacheAdapter): Client { | ||||
|   setAdapter(adapter: ICacheAdapter): Client { | ||||
|     this.cache = adapter | ||||
|     return this | ||||
|   } | ||||
| 
 | ||||
|   /** Change Presence of Client */ | ||||
|   setPresence (presence: ClientPresence | ClientActivity | ActivityGame): void { | ||||
|   setPresence(presence: ClientPresence | ClientActivity | ActivityGame): void { | ||||
|     if (presence instanceof ClientPresence) { | ||||
|       this.presence = presence | ||||
|     } else this.presence = new ClientPresence(presence) | ||||
|  | @ -112,7 +121,7 @@ export class Client extends EventEmitter { | |||
|   } | ||||
| 
 | ||||
|   /** Emit debug event */ | ||||
|   debug (tag: string, msg: string): void { | ||||
|   debug(tag: string, msg: string): void { | ||||
|     this.emit('debug', `[${tag}] ${msg}`) | ||||
|   } | ||||
| 
 | ||||
|  | @ -124,7 +133,7 @@ export class Client extends EventEmitter { | |||
|    * @param token Your token. This is required. | ||||
|    * @param intents Gateway intents in array. This is required. | ||||
|    */ | ||||
|   connect (token?: string, intents?: GatewayIntents[]): void { | ||||
|   connect(token?: string, intents?: GatewayIntents[]): void { | ||||
|     if (token === undefined && this.token !== undefined) token = this.token | ||||
|     else if (this.token === undefined && token !== undefined) { | ||||
|       this.token = token | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ import { TextChannel } from '../structures/textChannel.ts' | |||
| import { User } from '../structures/user.ts' | ||||
| import { Collection } from '../utils/collection.ts' | ||||
| import { CommandClient } from './commandClient.ts' | ||||
| import { Extension } from "./extensions.ts" | ||||
| import { Extension } from './extensions.ts' | ||||
| 
 | ||||
| export interface CommandContext { | ||||
|   /** The Client object */ | ||||
|  | @ -34,6 +34,8 @@ export class Command { | |||
|   name: string = '' | ||||
|   /** Description of the Command */ | ||||
|   description?: string | ||||
|   /** Category of the Command */ | ||||
|   category?: string | ||||
|   /** Array of Aliases of Command, or only string */ | ||||
|   aliases?: string | string[] | ||||
|   /** Extension (Parent) of the Command */ | ||||
|  | @ -42,10 +44,12 @@ export class Command { | |||
|   usage?: string | string[] | ||||
|   /** Usage Example of Command, only Arguments (without Prefix and Name) */ | ||||
|   examples?: string | string[] | ||||
|   /** Does the Command take Arguments? Maybe number of required arguments? */ | ||||
|   args?: number | boolean | ||||
|   /** Permission(s) required for using Command */ | ||||
|   /** Does the Command take Arguments? Maybe number of required arguments? Or list of arguments? */ | ||||
|   args?: number | boolean | string[] | ||||
|   /** Permissions(s) required by both User and Bot in order to use Command */ | ||||
|   permissions?: string | string[] | ||||
|   /** Permission(s) required for using Command */ | ||||
|   userPermissions?: string | string[] | ||||
|   /** Permission(s) bot will need in order to execute Command */ | ||||
|   botPermissions?: string | string[] | ||||
|   /** 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 | ||||
| 
 | ||||
|   /** 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. */ | ||||
|   execute(ctx: CommandContext): any { } | ||||
|   execute(ctx: CommandContext): any {} | ||||
|   /** 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 { | ||||
|     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 */ | ||||
|   get count(): number { return this.list.size } | ||||
|   get count(): number { | ||||
|     return this.list.size | ||||
|   } | ||||
| 
 | ||||
|   /** Find a Command by name/alias */ | ||||
|   find(search: string): Command | undefined { | ||||
|  | @ -99,7 +280,7 @@ export class CommandsManager { | |||
|         if (typeof cmd.aliases === 'string') aliases = [cmd.aliases] | ||||
|         else aliases = cmd.aliases | ||||
|         if (this.client.caseSensitive === false) | ||||
|           aliases = aliases.map(e => e.toLowerCase()) | ||||
|           aliases = aliases.map((e) => e.toLowerCase()) | ||||
|         return aliases.includes(search) | ||||
|       } else return false | ||||
|     }) | ||||
|  | @ -123,8 +304,9 @@ export class CommandsManager { | |||
|         const aliases: string[] = | ||||
|           typeof search.aliases === 'string' ? [search.aliases] : search.aliases | ||||
|         exists = | ||||
|           aliases.map(alias => this.find(alias) !== undefined).find(e => e) ?? | ||||
|           false | ||||
|           aliases | ||||
|             .map((alias) => this.find(alias) !== undefined) | ||||
|             .find((e) => e) ?? false | ||||
|       } | ||||
|       return exists | ||||
|     } | ||||
|  | @ -134,7 +316,10 @@ export class CommandsManager { | |||
|   add(cmd: Command | typeof Command): boolean { | ||||
|     // eslint-disable-next-line new-cap
 | ||||
|     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) | ||||
|     return true | ||||
|   } | ||||
|  | @ -148,7 +333,7 @@ export class CommandsManager { | |||
| 
 | ||||
|   /** Check whether a Command is disabled or not */ | ||||
|   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 | ||||
|     const exists = this.exists(name) | ||||
|     if (!exists) return false | ||||
|  | @ -157,12 +342,65 @@ export class CommandsManager { | |||
| 
 | ||||
|   /** Disable a Command */ | ||||
|   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 (this.isDisabled(cmd)) return false | ||||
|     this.disabled.add(cmd.name) | ||||
|     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 { | ||||
|  | @ -185,6 +423,6 @@ export const parseCommand = ( | |||
|   return { | ||||
|     name, | ||||
|     args, | ||||
|     argString | ||||
|     argString, | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -1,198 +1,332 @@ | |||
| import { Message } from "../../mod.ts" | ||||
| import { awaitSync } from "../utils/mixedPromise.ts" | ||||
| import { Client, ClientOptions } from './client.ts' | ||||
| import { CommandContext, CommandsManager, parseCommand } from './command.ts' | ||||
| import { ExtensionsManager } from "./extensions.ts" | ||||
| 
 | ||||
| type PrefixReturnType = string | string[] | Promise<string | string[]> | ||||
| 
 | ||||
| export interface CommandClientOptions extends ClientOptions { | ||||
|   prefix: string | string[] | ||||
|   mentionPrefix?: boolean | ||||
|   getGuildPrefix?: (guildID: string) => PrefixReturnType | ||||
|   getUserPrefix?: (userID: string) => PrefixReturnType | ||||
|   isGuildBlacklisted?: (guildID: string) => boolean | Promise<boolean> | ||||
|   isUserBlacklisted?: (guildID: string) => boolean | Promise<boolean> | ||||
|   isChannelBlacklisted?: (guildID: string) => boolean | Promise<boolean> | ||||
|   spacesAfterPrefix?: boolean | ||||
|   betterArgs?: boolean | ||||
|   owners?: string[] | ||||
|   allowBots?: boolean | ||||
|   allowDMs?: boolean | ||||
|   caseSensitive?: boolean | ||||
| } | ||||
| 
 | ||||
| export class CommandClient extends Client implements CommandClientOptions { | ||||
|   prefix: string | string[] | ||||
|   mentionPrefix: boolean | ||||
|   getGuildPrefix: (guildID: string) => PrefixReturnType | ||||
|   getUserPrefix: (userID: string) => PrefixReturnType | ||||
|   isGuildBlacklisted: (guildID: string) => boolean | Promise<boolean> | ||||
|   isUserBlacklisted: (guildID: string) => boolean | Promise<boolean> | ||||
|   isChannelBlacklisted: (guildID: string) => boolean | Promise<boolean> | ||||
|   spacesAfterPrefix: boolean | ||||
|   betterArgs: boolean | ||||
|   owners: string[] | ||||
|   allowBots: boolean | ||||
|   allowDMs: boolean | ||||
|   caseSensitive: boolean | ||||
|   extensions: ExtensionsManager = new ExtensionsManager(this) | ||||
|   commands: CommandsManager = new CommandsManager(this) | ||||
| 
 | ||||
|   constructor(options: CommandClientOptions) { | ||||
|     super(options) | ||||
|     this.prefix = options.prefix | ||||
|     this.mentionPrefix = | ||||
|       options.mentionPrefix === undefined ? false : options.mentionPrefix | ||||
|     this.getGuildPrefix = | ||||
|       options.getGuildPrefix === undefined | ||||
|         ? (id: string) => this.prefix | ||||
|         : options.getGuildPrefix | ||||
|     this.getUserPrefix = | ||||
|       options.getUserPrefix === undefined | ||||
|         ? (id: string) => this.prefix | ||||
|         : options.getUserPrefix | ||||
|     this.isUserBlacklisted = | ||||
|       options.isUserBlacklisted === undefined | ||||
|         ? (id: string) => false | ||||
|         : options.isUserBlacklisted | ||||
|     this.isGuildBlacklisted = | ||||
|       options.isGuildBlacklisted === undefined | ||||
|         ? (id: string) => false | ||||
|         : options.isGuildBlacklisted | ||||
|     this.isChannelBlacklisted = | ||||
|       options.isChannelBlacklisted === undefined | ||||
|         ? (id: string) => false | ||||
|         : options.isChannelBlacklisted | ||||
|     this.spacesAfterPrefix = | ||||
|       options.spacesAfterPrefix === undefined | ||||
|         ? false | ||||
|         : options.spacesAfterPrefix | ||||
|     this.betterArgs = | ||||
|       options.betterArgs === undefined ? false : options.betterArgs | ||||
|     this.owners = options.owners === undefined ? [] : options.owners | ||||
|     this.allowBots = options.allowBots === undefined ? false : options.allowBots | ||||
|     this.allowDMs = options.allowDMs === undefined ? true : options.allowDMs | ||||
|     this.caseSensitive = | ||||
|       options.caseSensitive === undefined ? false : options.caseSensitive | ||||
| 
 | ||||
|     this.on( | ||||
|       'messageCreate', | ||||
|       async (msg: Message) => await this.processMessage(msg) | ||||
|     ) | ||||
|   } | ||||
| 
 | ||||
|   async processMessage(msg: Message): Promise<any> { | ||||
|     if (!this.allowBots && msg.author.bot === true) return | ||||
| 
 | ||||
|     const isUserBlacklisted = await awaitSync(this.isUserBlacklisted(msg.author.id)) | ||||
|     if (isUserBlacklisted === true) return | ||||
| 
 | ||||
|     const isChannelBlacklisted = await awaitSync(this.isChannelBlacklisted(msg.channel.id)) | ||||
|     if (isChannelBlacklisted === true) return | ||||
| 
 | ||||
|     if (msg.guild !== undefined) { | ||||
|       const isGuildBlacklisted = await awaitSync(this.isGuildBlacklisted(msg.guild.id)) | ||||
|       if (isGuildBlacklisted === true) return | ||||
|     } | ||||
| 
 | ||||
|     let prefix: string | string[] = this.prefix | ||||
| 
 | ||||
|     if (msg.guild !== undefined) { | ||||
|       prefix = await awaitSync(this.getGuildPrefix(msg.guild.id)) | ||||
|     } else { | ||||
|       prefix = await awaitSync(this.getUserPrefix(msg.author.id)) | ||||
|     } | ||||
| 
 | ||||
|     let mentionPrefix = false | ||||
| 
 | ||||
|     if (typeof prefix === 'string') { | ||||
|       if (msg.content.startsWith(prefix) === false) { | ||||
|         if (this.mentionPrefix) mentionPrefix = true | ||||
|         else return | ||||
|       } | ||||
|     } else { | ||||
|       const usedPrefix = prefix.find(v => msg.content.startsWith(v)) | ||||
|       if (usedPrefix === undefined) { | ||||
|         if (this.mentionPrefix) mentionPrefix = true | ||||
|         else return | ||||
|       } | ||||
|       else prefix = usedPrefix | ||||
|     } | ||||
| 
 | ||||
|     if (mentionPrefix) { | ||||
|       if (msg.content.startsWith(this.user?.mention as string) === true) prefix = this.user?.mention as string | ||||
|       else if (msg.content.startsWith(this.user?.nickMention as string) === true) prefix = this.user?.nickMention as string | ||||
|       else return | ||||
|     } | ||||
| 
 | ||||
|     if (typeof prefix !== 'string') return | ||||
| 
 | ||||
|     const parsed = parseCommand(this, msg, prefix) | ||||
|     const command = this.commands.find(parsed.name) | ||||
| 
 | ||||
|     if (command === undefined) return | ||||
| 
 | ||||
|     if (command.whitelistedGuilds !== undefined && msg.guild !== undefined && command.whitelistedGuilds.includes(msg.guild.id) === false) return; | ||||
|     if (command.whitelistedChannels !== undefined && command.whitelistedChannels.includes(msg.channel.id) === false) return; | ||||
|     if (command.whitelistedUsers !== undefined && command.whitelistedUsers.includes(msg.author.id) === false) 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 | ||||
|     } | ||||
| 
 | ||||
|     if (command.ownerOnly === true && !this.owners.includes(msg.author.id)) return this.emit('commandOwnerOnly', ctx, command) | ||||
|     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) | ||||
|      | ||||
|     if (command.botPermissions !== undefined && msg.guild !== undefined) { | ||||
|       // TODO: Check Overwrites too
 | ||||
|       const me = await msg.guild.me() | ||||
|       const missing: string[] = [] | ||||
|        | ||||
|       for (const perm of command.botPermissions) { | ||||
|         if (me.permissions.has(perm) === false) missing.push(perm) | ||||
|       } | ||||
| 
 | ||||
|       if (missing.length !== 0) return this.emit('commandBotMissingPermissions', ctx, command, missing) | ||||
|     } | ||||
| 
 | ||||
|     if (command.permissions !== undefined && msg.guild !== undefined) { | ||||
|       const missing: string[] = [] | ||||
|       let perms: string[] = [] | ||||
|       if (typeof command.permissions === 'string') perms = [command.permissions] | ||||
|       else perms = command.permissions | ||||
|       for (const perm of perms) { | ||||
|         const has = msg.member?.permissions.has(perm) | ||||
|         if (has !== true) missing.push(perm) | ||||
|       }  | ||||
|       if (missing.length !== 0) return this.emit('commandMissingPermissions', 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) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| import { Message } from '../../mod.ts' | ||||
| import { awaitSync } from '../utils/mixedPromise.ts' | ||||
| import { Client, ClientOptions } from './client.ts' | ||||
| import { | ||||
|   CategoriesManager, | ||||
|   CommandContext, | ||||
|   CommandsManager, | ||||
|   parseCommand, | ||||
| } from './command.ts' | ||||
| import { ExtensionsManager } from './extensions.ts' | ||||
| 
 | ||||
| type PrefixReturnType = string | string[] | Promise<string | string[]> | ||||
| 
 | ||||
| export interface CommandClientOptions extends ClientOptions { | ||||
|   prefix: string | string[] | ||||
|   mentionPrefix?: boolean | ||||
|   getGuildPrefix?: (guildID: string) => PrefixReturnType | ||||
|   getUserPrefix?: (userID: string) => PrefixReturnType | ||||
|   isGuildBlacklisted?: (guildID: string) => boolean | Promise<boolean> | ||||
|   isUserBlacklisted?: (guildID: string) => boolean | Promise<boolean> | ||||
|   isChannelBlacklisted?: (guildID: string) => boolean | Promise<boolean> | ||||
|   spacesAfterPrefix?: boolean | ||||
|   betterArgs?: boolean | ||||
|   owners?: string[] | ||||
|   allowBots?: boolean | ||||
|   allowDMs?: boolean | ||||
|   caseSensitive?: boolean | ||||
| } | ||||
| 
 | ||||
| export class CommandClient extends Client implements CommandClientOptions { | ||||
|   prefix: string | string[] | ||||
|   mentionPrefix: boolean | ||||
|   getGuildPrefix: (guildID: string) => PrefixReturnType | ||||
|   getUserPrefix: (userID: string) => PrefixReturnType | ||||
|   isGuildBlacklisted: (guildID: string) => boolean | Promise<boolean> | ||||
|   isUserBlacklisted: (guildID: string) => boolean | Promise<boolean> | ||||
|   isChannelBlacklisted: (guildID: string) => boolean | Promise<boolean> | ||||
|   spacesAfterPrefix: boolean | ||||
|   betterArgs: boolean | ||||
|   owners: string[] | ||||
|   allowBots: boolean | ||||
|   allowDMs: boolean | ||||
|   caseSensitive: boolean | ||||
|   extensions: ExtensionsManager = new ExtensionsManager(this) | ||||
|   commands: CommandsManager = new CommandsManager(this) | ||||
|   categories: CategoriesManager = new CategoriesManager(this) | ||||
| 
 | ||||
|   constructor(options: CommandClientOptions) { | ||||
|     super(options) | ||||
|     this.prefix = options.prefix | ||||
|     this.mentionPrefix = | ||||
|       options.mentionPrefix === undefined ? false : options.mentionPrefix | ||||
|     this.getGuildPrefix = | ||||
|       options.getGuildPrefix === undefined | ||||
|         ? (id: string) => this.prefix | ||||
|         : options.getGuildPrefix | ||||
|     this.getUserPrefix = | ||||
|       options.getUserPrefix === undefined | ||||
|         ? (id: string) => this.prefix | ||||
|         : options.getUserPrefix | ||||
|     this.isUserBlacklisted = | ||||
|       options.isUserBlacklisted === undefined | ||||
|         ? (id: string) => false | ||||
|         : options.isUserBlacklisted | ||||
|     this.isGuildBlacklisted = | ||||
|       options.isGuildBlacklisted === undefined | ||||
|         ? (id: string) => false | ||||
|         : options.isGuildBlacklisted | ||||
|     this.isChannelBlacklisted = | ||||
|       options.isChannelBlacklisted === undefined | ||||
|         ? (id: string) => false | ||||
|         : options.isChannelBlacklisted | ||||
|     this.spacesAfterPrefix = | ||||
|       options.spacesAfterPrefix === undefined | ||||
|         ? false | ||||
|         : options.spacesAfterPrefix | ||||
|     this.betterArgs = | ||||
|       options.betterArgs === undefined ? false : options.betterArgs | ||||
|     this.owners = options.owners === undefined ? [] : options.owners | ||||
|     this.allowBots = options.allowBots === undefined ? false : options.allowBots | ||||
|     this.allowDMs = options.allowDMs === undefined ? true : options.allowDMs | ||||
|     this.caseSensitive = | ||||
|       options.caseSensitive === undefined ? false : options.caseSensitive | ||||
| 
 | ||||
|     this.on( | ||||
|       'messageCreate', | ||||
|       async (msg: Message) => await this.processMessage(msg) | ||||
|     ) | ||||
|   } | ||||
| 
 | ||||
|   async processMessage(msg: Message): Promise<any> { | ||||
|     if (!this.allowBots && msg.author.bot === true) return | ||||
| 
 | ||||
|     const isUserBlacklisted = await awaitSync( | ||||
|       this.isUserBlacklisted(msg.author.id) | ||||
|     ) | ||||
|     if (isUserBlacklisted === true) return | ||||
| 
 | ||||
|     const isChannelBlacklisted = await awaitSync( | ||||
|       this.isChannelBlacklisted(msg.channel.id) | ||||
|     ) | ||||
|     if (isChannelBlacklisted === true) return | ||||
| 
 | ||||
|     if (msg.guild !== undefined) { | ||||
|       const isGuildBlacklisted = await awaitSync( | ||||
|         this.isGuildBlacklisted(msg.guild.id) | ||||
|       ) | ||||
|       if (isGuildBlacklisted === true) return | ||||
|     } | ||||
| 
 | ||||
|     let prefix: string | string[] = this.prefix | ||||
| 
 | ||||
|     if (msg.guild !== undefined) { | ||||
|       prefix = await awaitSync(this.getGuildPrefix(msg.guild.id)) | ||||
|     } else { | ||||
|       prefix = await awaitSync(this.getUserPrefix(msg.author.id)) | ||||
|     } | ||||
| 
 | ||||
|     let mentionPrefix = false | ||||
| 
 | ||||
|     if (typeof prefix === 'string') { | ||||
|       if (msg.content.startsWith(prefix) === false) { | ||||
|         if (this.mentionPrefix) mentionPrefix = true | ||||
|         else return | ||||
|       } | ||||
|     } else { | ||||
|       const usedPrefix = prefix.find((v) => msg.content.startsWith(v)) | ||||
|       if (usedPrefix === undefined) { | ||||
|         if (this.mentionPrefix) mentionPrefix = true | ||||
|         else return | ||||
|       } else prefix = usedPrefix | ||||
|     } | ||||
| 
 | ||||
|     if (mentionPrefix) { | ||||
|       if (msg.content.startsWith(this.user?.mention as string) === true) | ||||
|         prefix = this.user?.mention as string | ||||
|       else if ( | ||||
|         msg.content.startsWith(this.user?.nickMention as string) === true | ||||
|       ) | ||||
|         prefix = this.user?.nickMention as string | ||||
|       else return | ||||
|     } | ||||
| 
 | ||||
|     if (typeof prefix !== 'string') return | ||||
| 
 | ||||
|     const parsed = parseCommand(this, msg, prefix) | ||||
|     const command = this.commands.find(parsed.name) | ||||
| 
 | ||||
|     if (command === undefined) return | ||||
|     const category = | ||||
|       command.category !== undefined | ||||
|         ? this.categories.get(command.category) | ||||
|         : undefined | ||||
| 
 | ||||
|     // 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.whitelistedGuilds === undefined && | ||||
|       category?.whitelistedGuilds !== undefined && | ||||
|       msg.guild !== undefined && | ||||
|       category.whitelistedGuilds.includes(msg.guild.id) === false | ||||
|     ) | ||||
|       return | ||||
|     if ( | ||||
|       command.whitelistedGuilds !== undefined && | ||||
|       msg.guild !== undefined && | ||||
|       command.whitelistedGuilds.includes(msg.guild.id) === false | ||||
|     ) | ||||
|       return | ||||
| 
 | ||||
|     // Checks for Channel Whitelist
 | ||||
|     if ( | ||||
|       command.whitelistedChannels === undefined && | ||||
|       category?.whitelistedChannels !== undefined && | ||||
|       category.whitelistedChannels.includes(msg.channel.id) === false | ||||
|     ) | ||||
|       return | ||||
|     if ( | ||||
|       command.whitelistedChannels !== undefined && | ||||
|       command.whitelistedChannels.includes(msg.channel.id) === false | ||||
|     ) | ||||
|       return | ||||
| 
 | ||||
|     // Checks for Users Whitelist
 | ||||
|     if ( | ||||
|       command.whitelistedUsers === undefined && | ||||
|       category?.whitelistedUsers !== undefined && | ||||
|       category.whitelistedUsers.includes(msg.author.id) === false | ||||
|     ) | ||||
|       return | ||||
|     if ( | ||||
|       command.whitelistedUsers !== undefined && | ||||
|       command.whitelistedUsers.includes(msg.author.id) === false | ||||
|     ) | ||||
|       return | ||||
| 
 | ||||
|     const ctx: CommandContext = { | ||||
|       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,120 +1,129 @@ | |||
| import { Base } from './base.ts' | ||||
| import { | ||||
|   Attachment, | ||||
|   ChannelMention, | ||||
|   MessageActivity, | ||||
|   MessageApplication, | ||||
|   MessageOption, | ||||
|   MessagePayload, | ||||
|   MessageReference, | ||||
|   Reaction | ||||
| } from '../types/channel.ts' | ||||
| import { Client } from '../models/client.ts' | ||||
| import { User } from './user.ts' | ||||
| import { Member } from './member.ts' | ||||
| import { Embed } from './embed.ts' | ||||
| import { CHANNEL_MESSAGE } from '../types/endpoint.ts' | ||||
| import { MessageMentions } from './messageMentions.ts' | ||||
| import { TextChannel } from './textChannel.ts' | ||||
| import { Guild } from './guild.ts' | ||||
| 
 | ||||
| type AllMessageOptions = MessageOption | Embed | ||||
| 
 | ||||
| export class Message extends Base { | ||||
|   id: string | ||||
|   channelID: string | ||||
|   channel: TextChannel | ||||
|   guildID?: string | ||||
|   guild?: Guild | ||||
|   author: User | ||||
|   member?: Member | ||||
|   content: string | ||||
|   timestamp: string | ||||
|   editedTimestamp?: string | ||||
|   tts: boolean | ||||
|   mentionEveryone: boolean | ||||
|   mentions: MessageMentions | ||||
|   mentionRoles: string[] | ||||
|   mentionChannels?: ChannelMention[] | ||||
|   attachments: Attachment[] | ||||
|   embeds: Embed[] | ||||
|   reactions?: Reaction[] | ||||
|   nonce?: string | number | ||||
|   pinned: boolean | ||||
|   webhookID?: string | ||||
|   type: number | ||||
|   activity?: MessageActivity | ||||
|   application?: MessageApplication | ||||
|   messageReference?: MessageReference | ||||
|   flags?: number | ||||
| 
 | ||||
|   constructor ( | ||||
|     client: Client, | ||||
|     data: MessagePayload, | ||||
|     channel: TextChannel, | ||||
|     author: User | ||||
|   ) { | ||||
|     super(client) | ||||
|     this.id = data.id | ||||
|     this.channelID = data.channel_id | ||||
|     this.guildID = data.guild_id | ||||
|     this.author = author | ||||
|     this.content = data.content | ||||
|     this.timestamp = data.timestamp | ||||
|     this.editedTimestamp = data.edited_timestamp | ||||
|     this.tts = data.tts | ||||
|     this.mentionEveryone = data.mention_everyone | ||||
|     this.mentions = new MessageMentions(this.client, this) | ||||
|     this.mentionRoles = data.mention_roles | ||||
|     this.mentionChannels = data.mention_channels | ||||
|     this.attachments = data.attachments | ||||
|     this.embeds = data.embeds.map(v => new Embed(v)) | ||||
|     this.reactions = data.reactions | ||||
|     this.nonce = data.nonce | ||||
|     this.pinned = data.pinned | ||||
|     this.webhookID = data.webhook_id | ||||
|     this.type = data.type | ||||
|     this.activity = data.activity | ||||
|     this.application = data.application | ||||
|     this.messageReference = data.message_reference | ||||
|     this.flags = data.flags | ||||
|     this.channel = channel | ||||
|   } | ||||
| 
 | ||||
|   protected readFromData (data: MessagePayload): void { | ||||
|     super.readFromData(data) | ||||
|     this.channelID = data.channel_id ?? this.channelID | ||||
|     this.guildID = data.guild_id ?? this.guildID | ||||
|     this.content = data.content ?? this.content | ||||
|     this.timestamp = data.timestamp ?? this.timestamp | ||||
|     this.editedTimestamp = data.edited_timestamp ?? this.editedTimestamp | ||||
|     this.tts = data.tts ?? this.tts | ||||
|     this.mentionEveryone = data.mention_everyone ?? this.mentionEveryone | ||||
|     this.mentionRoles = data.mention_roles ?? this.mentionRoles | ||||
|     this.mentionChannels = data.mention_channels ?? this.mentionChannels | ||||
|     this.attachments = data.attachments ?? this.attachments | ||||
|     this.embeds = data.embeds.map(v => new Embed(v)) ?? this.embeds | ||||
|     this.reactions = data.reactions ?? this.reactions | ||||
|     this.nonce = data.nonce ?? this.nonce | ||||
|     this.pinned = data.pinned ?? this.pinned | ||||
|     this.webhookID = data.webhook_id ?? this.webhookID | ||||
|     this.type = data.type ?? this.type | ||||
|     this.activity = data.activity ?? this.activity | ||||
|     this.application = data.application ?? this.application | ||||
|     this.messageReference = data.message_reference ?? this.messageReference | ||||
|     this.flags = data.flags ?? this.flags | ||||
|   } | ||||
| 
 | ||||
|   async edit (text?: string, option?: MessageOption): Promise<Message> { | ||||
|     return this.channel.editMessage(this.id, text, option)   | ||||
|   } | ||||
| 
 | ||||
|   /** These will **not** work in all servers, as this feature is coming slowly. */ | ||||
|   async reply(text?: string | AllMessageOptions, option?: AllMessageOptions): Promise<Message> { | ||||
|     return this.channel.send(text, option, this) | ||||
|   } | ||||
| 
 | ||||
|   async delete (): Promise<void> { | ||||
|     return this.client.rest.delete(CHANNEL_MESSAGE(this.channelID, this.id)) | ||||
|   } | ||||
| } | ||||
| import { Base } from './base.ts' | ||||
| import { | ||||
|   Attachment, | ||||
|   ChannelMention, | ||||
|   MessageActivity, | ||||
|   MessageApplication, | ||||
|   MessageOption, | ||||
|   MessagePayload, | ||||
|   MessageReference, | ||||
| } from '../types/channel.ts' | ||||
| import { Client } from '../models/client.ts' | ||||
| import { User } from './user.ts' | ||||
| import { Member } from './member.ts' | ||||
| import { Embed } from './embed.ts' | ||||
| import { CHANNEL_MESSAGE } from '../types/endpoint.ts' | ||||
| import { MessageMentions } from './messageMentions.ts' | ||||
| import { TextChannel } from './textChannel.ts' | ||||
| import { Guild } from './guild.ts' | ||||
| import { MessageReactionsManager } from '../managers/messageReactions.ts' | ||||
| 
 | ||||
| type AllMessageOptions = MessageOption | Embed | ||||
| 
 | ||||
| export class Message extends Base { | ||||
|   id: string | ||||
|   channelID: string | ||||
|   channel: TextChannel | ||||
|   guildID?: string | ||||
|   guild?: Guild | ||||
|   author: User | ||||
|   member?: Member | ||||
|   content: string | ||||
|   timestamp: string | ||||
|   editedTimestamp?: string | ||||
|   tts: boolean | ||||
|   mentionEveryone: boolean | ||||
|   mentions: MessageMentions | ||||
|   mentionRoles: string[] | ||||
|   mentionChannels?: ChannelMention[] | ||||
|   attachments: Attachment[] | ||||
|   embeds: Embed[] | ||||
|   reactions: MessageReactionsManager | ||||
|   nonce?: string | number | ||||
|   pinned: boolean | ||||
|   webhookID?: string | ||||
|   type: number | ||||
|   activity?: MessageActivity | ||||
|   application?: MessageApplication | ||||
|   messageReference?: MessageReference | ||||
|   flags?: number | ||||
| 
 | ||||
|   constructor( | ||||
|     client: Client, | ||||
|     data: MessagePayload, | ||||
|     channel: TextChannel, | ||||
|     author: User | ||||
|   ) { | ||||
|     super(client) | ||||
|     this.id = data.id | ||||
|     this.channelID = data.channel_id | ||||
|     this.guildID = data.guild_id | ||||
|     this.author = author | ||||
|     this.content = data.content | ||||
|     this.timestamp = data.timestamp | ||||
|     this.editedTimestamp = data.edited_timestamp | ||||
|     this.tts = data.tts | ||||
|     this.mentionEveryone = data.mention_everyone | ||||
|     this.mentions = new MessageMentions(this.client, this) | ||||
|     this.mentionRoles = data.mention_roles | ||||
|     this.mentionChannels = data.mention_channels | ||||
|     this.attachments = data.attachments | ||||
|     this.embeds = data.embeds.map((v) => new Embed(v)) | ||||
|     this.reactions = new MessageReactionsManager(this.client, this) | ||||
|     this.nonce = data.nonce | ||||
|     this.pinned = data.pinned | ||||
|     this.webhookID = data.webhook_id | ||||
|     this.type = data.type | ||||
|     this.activity = data.activity | ||||
|     this.application = data.application | ||||
|     this.messageReference = data.message_reference | ||||
|     this.flags = data.flags | ||||
|     this.channel = channel | ||||
|   } | ||||
| 
 | ||||
|   protected readFromData(data: MessagePayload): void { | ||||
|     super.readFromData(data) | ||||
|     this.channelID = data.channel_id ?? this.channelID | ||||
|     this.guildID = data.guild_id ?? this.guildID | ||||
|     this.content = data.content ?? this.content | ||||
|     this.timestamp = data.timestamp ?? this.timestamp | ||||
|     this.editedTimestamp = data.edited_timestamp ?? this.editedTimestamp | ||||
|     this.tts = data.tts ?? this.tts | ||||
|     this.mentionEveryone = data.mention_everyone ?? this.mentionEveryone | ||||
|     this.mentionRoles = data.mention_roles ?? this.mentionRoles | ||||
|     this.mentionChannels = data.mention_channels ?? this.mentionChannels | ||||
|     this.attachments = data.attachments ?? this.attachments | ||||
|     this.embeds = data.embeds.map((v) => new Embed(v)) ?? this.embeds | ||||
|     this.nonce = data.nonce ?? this.nonce | ||||
|     this.pinned = data.pinned ?? this.pinned | ||||
|     this.webhookID = data.webhook_id ?? this.webhookID | ||||
|     this.type = data.type ?? this.type | ||||
|     this.activity = data.activity ?? this.activity | ||||
|     this.application = data.application ?? this.application | ||||
|     this.messageReference = data.message_reference ?? this.messageReference | ||||
|     this.flags = data.flags ?? this.flags | ||||
|   } | ||||
| 
 | ||||
|   /** Edit this message. */ | ||||
|   async edit(text?: string, option?: MessageOption): Promise<Message> { | ||||
|     if ( | ||||
|       this.client.user !== undefined && | ||||
|       this.author.id !== this.client.user?.id | ||||
|     ) | ||||
|       throw new Error("Cannot edit other users' messages") | ||||
|     return this.channel.editMessage(this.id, text, option) | ||||
|   } | ||||
| 
 | ||||
|   /** Create a Reply to this Message. */ | ||||
|   async reply( | ||||
|     text?: string | AllMessageOptions, | ||||
|     option?: AllMessageOptions | ||||
|   ): Promise<Message> { | ||||
|     return this.channel.send(text, option, this) | ||||
|   } | ||||
| 
 | ||||
|   /** Delete the Message. */ | ||||
|   async delete(): Promise<void> { | ||||
|     return this.client.rest.delete(CHANNEL_MESSAGE(this.channelID, this.id)) | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -1,55 +1,63 @@ | |||
| import { Client } from "../models/client.ts"; | ||||
| import { MessagePayload } from "../types/channel.ts"; | ||||
| import { Collection } from "../utils/collection.ts"; | ||||
| import { GuildTextChannel } from "./textChannel.ts"; | ||||
| import { Message } from "./message.ts"; | ||||
| import { Role } from "./role.ts"; | ||||
| import { User } from "./user.ts"; | ||||
| 
 | ||||
| export class MessageMentions { | ||||
|   client: Client | ||||
|   message: Message | ||||
|   users: Collection<string, User> = new Collection() | ||||
|   roles: Collection<string, Role> = new Collection() | ||||
|   channels: Collection<string, GuildTextChannel> = new Collection() | ||||
|   everyone: boolean = false | ||||
| 
 | ||||
|   static EVERYONE_MENTION = /@(everyone|here)/g | ||||
|   static USER_MENTION = /<@!?(\d{17,19})>/g | ||||
|   static ROLE_MENTION = /<@&(\d{17,19})>/g | ||||
|   static CHANNEL_MENTION = /<#(\d{17,19})>/g | ||||
| 
 | ||||
|   constructor(client: Client, message: Message) { | ||||
|     this.client = client | ||||
|     this.message = message | ||||
|   } | ||||
| 
 | ||||
|   async fromPayload(payload: MessagePayload): Promise<MessageMentions> { | ||||
|     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(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 (channel !== undefined) this.channels.set(channel.id, channel) | ||||
|       } | ||||
|     } | ||||
|     const matchChannels = this.message.content.match(MessageMentions.CHANNEL_MENTION) | ||||
|     if (matchChannels !== null) { | ||||
|       for (const id of matchChannels) { | ||||
|         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 | ||||
|   } | ||||
| } | ||||
| import { Client } from '../models/client.ts' | ||||
| import { MessagePayload } from '../types/channel.ts' | ||||
| import { Collection } from '../utils/collection.ts' | ||||
| import { GuildTextChannel } from './textChannel.ts' | ||||
| import { Message } from './message.ts' | ||||
| import { Role } from './role.ts' | ||||
| import { User } from './user.ts' | ||||
| 
 | ||||
| export class MessageMentions { | ||||
|   client: Client | ||||
|   message: Message | ||||
|   users: Collection<string, User> = new Collection() | ||||
|   roles: Collection<string, Role> = new Collection() | ||||
|   channels: Collection<string, GuildTextChannel> = new Collection() | ||||
|   everyone: boolean = false | ||||
| 
 | ||||
|   static EVERYONE_MENTION = /@(everyone|here)/g | ||||
|   static USER_MENTION = /<@!?(\d{17,19})>/g | ||||
|   static ROLE_MENTION = /<@&(\d{17,19})>/g | ||||
|   static CHANNEL_MENTION = /<#(\d{17,19})>/g | ||||
| 
 | ||||
|   constructor(client: Client, message: Message) { | ||||
|     this.client = client | ||||
|     this.message = message | ||||
|   } | ||||
| 
 | ||||
|   async fromPayload(payload: MessagePayload): Promise<MessageMentions> { | ||||
|     if (this.message === undefined) return this | ||||
|     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 (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 (channel !== undefined) this.channels.set(channel.id, channel) | ||||
|       } | ||||
|     } | ||||
|     const matchChannels = this.message.content.match( | ||||
|       MessageMentions.CHANNEL_MENTION | ||||
|     ) | ||||
|     if (matchChannels !== null) { | ||||
|       for (const id of matchChannels) { | ||||
|         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 | ||||
|   } | ||||
| } | ||||
|  |  | |||
							
								
								
									
										28
									
								
								src/structures/messageReaction.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/structures/messageReaction.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | |||
| import { ReactionUsersManager } from '../managers/reactionUsers.ts' | ||||
| import { Client } from '../models/client.ts' | ||||
| import { Reaction } from '../types/channel.ts' | ||||
| import { Base } from './base.ts' | ||||
| import { Emoji } from './emoji.ts' | ||||
| import { Message } from './message.ts' | ||||
| 
 | ||||
| export class MessageReaction extends Base { | ||||
|   message: Message | ||||
|   count: number = 0 | ||||
|   emoji: Emoji | ||||
|   me: boolean = false | ||||
|   users: ReactionUsersManager | ||||
| 
 | ||||
|   constructor(client: Client, data: Reaction, message: Message, emoji: Emoji) { | ||||
|     super(client, data) | ||||
|     this.message = message | ||||
|     this.emoji = emoji | ||||
|     this.count = data.count | ||||
|     this.me = data.me | ||||
|     this.users = new ReactionUsersManager(client, this) | ||||
|   } | ||||
| 
 | ||||
|   fromPayload(data: Reaction): void { | ||||
|     this.count = data.count | ||||
|     this.me = data.me | ||||
|   } | ||||
| } | ||||
|  | @ -63,6 +63,7 @@ client.on('webhooksUpdate', (guild, channel) => { | |||
|   console.log(`Webhooks Updated in #${channel.name} from ${guild.name}`) | ||||
| }) | ||||
| 
 | ||||
| client.on('commandError', console.error) | ||||
| client.on('inviteCreate', (invite: Invite) => { | ||||
|   console.log(`Invite Create: ${invite.code}`) | ||||
| }) | ||||
|  | @ -131,6 +132,22 @@ client.on('voiceStateRemove', (state) => { | |||
|   console.log('VC Leave', state) | ||||
| }) | ||||
| 
 | ||||
| client.on('messageReactionAdd', (reaction, user) => { | ||||
|   console.log(`${user.tag} reacted with ${reaction.emoji.name}`) | ||||
| }) | ||||
| 
 | ||||
| client.on('messageReactionRemove', (reaction, user) => { | ||||
|   console.log(`${user.tag} removed reaction ${reaction.emoji.name}`) | ||||
| }) | ||||
| 
 | ||||
| client.on('messageReactionRemoveEmoji', (message, emoji) => { | ||||
|   console.log(`All ${emoji.name} emoji reactions removed from ${message.id}`) | ||||
| }) | ||||
| 
 | ||||
| client.on('messageReactionRemoveAll', (message) => { | ||||
|   console.log(`All reactions remove from Message: ${message.id}`) | ||||
| }) | ||||
| 
 | ||||
| // client.on('raw', (evt: string) => console.log(`EVENT: ${evt}`))
 | ||||
| 
 | ||||
| const files = Deno.readDirSync('./src/test/cmds') | ||||
|  |  | |||
|  | @ -1,14 +1,14 @@ | |||
| // https://discord.com/developers/docs/topics/opcodes-and-status-codes#gateway
 | ||||
| // https://discord.com/developers/docs/topics/gateway#commands-and-events-gateway-events
 | ||||
| import { Guild } from "../structures/guild.ts" | ||||
| import { Member } from "../structures/member.ts" | ||||
| import { Guild } from '../structures/guild.ts' | ||||
| import { Member } from '../structures/member.ts' | ||||
| import { EmojiPayload } from './emoji.ts' | ||||
| import { MemberPayload } from './guild.ts' | ||||
| import { | ||||
|   ActivityGame, | ||||
|   ActivityPayload, | ||||
|   StatusType, | ||||
|   ClientStatus | ||||
|   ClientStatus, | ||||
| } from './presence.ts' | ||||
| import { RolePayload } from './role.ts' | ||||
| import { UserPayload } from './user.ts' | ||||
|  | @ -27,7 +27,7 @@ export enum GatewayOpcodes { // 문서를 확인해본 결과 Opcode 5번은 비 | |||
|   REQUEST_GUILD_MEMBERS = 8, | ||||
|   INVALID_SESSION = 9, | ||||
|   HELLO = 10, | ||||
|   HEARTBEAT_ACK = 11 | ||||
|   HEARTBEAT_ACK = 11, | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  | @ -47,7 +47,7 @@ export enum GatewayCloseCodes { | |||
|   SHARDING_REQUIRED = 4011, | ||||
|   INVALID_API_VERSION = 4012, | ||||
|   INVALID_INTENTS = 4013, | ||||
|   DISALLOWED_INTENTS = 4014 | ||||
|   DISALLOWED_INTENTS = 4014, | ||||
| } | ||||
| 
 | ||||
| export enum GatewayIntents { | ||||
|  | @ -65,7 +65,7 @@ export enum GatewayIntents { | |||
|   GUILD_MESSAGE_TYPING = 1 << 11, | ||||
|   DIRECT_MESSAGES = 1 << 12, | ||||
|   DIRECT_MESSAGE_REACTIONS = 1 << 13, | ||||
|   DIRECT_MESSAGE_TYPING = 1 << 13 | ||||
|   DIRECT_MESSAGE_TYPING = 1 << 13, | ||||
| } | ||||
| 
 | ||||
| export enum GatewayEvents { | ||||
|  | @ -105,7 +105,7 @@ export enum GatewayEvents { | |||
|   User_Update = 'USER_UPDATE', | ||||
|   Voice_Server_Update = 'VOICE_SERVER_UPDATE', | ||||
|   Voice_State_Update = 'VOICE_STATE_UPDATE', | ||||
|   Webhooks_Update = 'WEBHOOKS_UPDATE' | ||||
|   Webhooks_Update = 'WEBHOOKS_UPDATE', | ||||
| } | ||||
| 
 | ||||
| export interface IdentityPayload { | ||||
|  | @ -290,6 +290,13 @@ export interface MessageReactionRemoveAllPayload { | |||
|   message_id: string | ||||
| } | ||||
| 
 | ||||
| export interface MessageReactionRemoveEmojiPayload { | ||||
|   channel_id: string | ||||
|   message_id: string | ||||
|   guild_id?: string | ||||
|   emoji: EmojiPayload | ||||
| } | ||||
| 
 | ||||
| export interface PresenceUpdatePayload { | ||||
|   user: UserPayload | ||||
|   guild_id: string | ||||
|  | @ -335,4 +342,4 @@ export interface TypingStartPayload { | |||
| export interface TypingStartGuildData { | ||||
|   guild: Guild | ||||
|   member: Member | ||||
| } | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue