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,10 +6,12 @@ export const channelPinsUpdate: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|   d: ChannelPinsUpdatePayload |   d: ChannelPinsUpdatePayload | ||||||
| ) => { | ) => { | ||||||
|   const after: TextChannel | undefined = await gateway.client.channels.get<TextChannel>(d.channel_id) |   const after: | ||||||
|  |     | TextChannel | ||||||
|  |     | undefined = await gateway.client.channels.get<TextChannel>(d.channel_id) | ||||||
|   if (after !== undefined) { |   if (after !== undefined) { | ||||||
|     const before = after.refreshFromData({ |     const before = after.refreshFromData({ | ||||||
|       last_pin_timestamp: d.last_pin_timestamp |       last_pin_timestamp: d.last_pin_timestamp, | ||||||
|     }) |     }) | ||||||
|     const raw = await gateway.client.channels._get(d.channel_id) |     const raw = await gateway.client.channels._get(d.channel_id) | ||||||
|     await gateway.client.channels.set( |     await gateway.client.channels.set( | ||||||
|  |  | ||||||
|  | @ -8,7 +8,9 @@ export const guildBanAdd: GatewayEventHandler = async ( | ||||||
|   d: GuildBanAddPayload |   d: GuildBanAddPayload | ||||||
| ) => { | ) => { | ||||||
|   const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) |   const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) | ||||||
|   const user: User = await gateway.client.users.get(d.user.id) ?? new User(gateway.client, d.user) |   const user: User = | ||||||
|  |     (await gateway.client.users.get(d.user.id)) ?? | ||||||
|  |     new User(gateway.client, d.user) | ||||||
| 
 | 
 | ||||||
|   if (guild !== undefined) { |   if (guild !== undefined) { | ||||||
|     // We don't have to delete member, already done with guildMemberRemove event
 |     // We don't have to delete member, already done with guildMemberRemove event
 | ||||||
|  |  | ||||||
|  | @ -9,7 +9,8 @@ export const guildBanRemove: GatewayEventHandler = async ( | ||||||
| ) => { | ) => { | ||||||
|   const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) |   const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) | ||||||
|   const user: User = |   const user: User = | ||||||
|     await gateway.client.users.get(d.user.id) ?? new User(gateway.client, d.user) |     (await gateway.client.users.get(d.user.id)) ?? | ||||||
|  |     new User(gateway.client, d.user) | ||||||
| 
 | 
 | ||||||
|   if (guild !== undefined) { |   if (guild !== undefined) { | ||||||
|     gateway.client.emit('guildBanRemove', guild, user) |     gateway.client.emit('guildBanRemove', guild, user) | ||||||
|  |  | ||||||
|  | @ -1,24 +1,17 @@ | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| import { Guild } from '../../structures/guild.ts' | import { Guild } from '../../structures/guild.ts' | ||||||
| import { GuildPayload } from '../../types/guild.ts' | import { GuildPayload } from '../../types/guild.ts' | ||||||
| import { MembersManager } from '../../managers/members.ts' |  | ||||||
| import { GuildChannelPayload } from '../../types/channel.ts' | import { GuildChannelPayload } from '../../types/channel.ts' | ||||||
| import { RolesManager } from '../../managers/roles.ts' |  | ||||||
| 
 | 
 | ||||||
| export const guildCreate: GatewayEventHandler = async ( | export const guildCreate: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|   d: GuildPayload |   d: GuildPayload | ||||||
| ) => { | ) => { | ||||||
|   let guild: Guild | undefined = await gateway.client.guilds.get(d.id) |   const hasGuild: Guild | undefined = await gateway.client.guilds.get(d.id) | ||||||
|   if (guild !== undefined) { |  | ||||||
|     // It was just lazy load, so we don't fire the event as its gonna fire for every guild bot is in
 |  | ||||||
|   await gateway.client.guilds.set(d.id, d) |   await gateway.client.guilds.set(d.id, d) | ||||||
|  |   const guild = ((await gateway.client.guilds.get(d.id)) as unknown) as Guild | ||||||
| 
 | 
 | ||||||
|     if (d.members !== undefined) { |   if (d.members !== undefined) await guild.members.fromPayload(d.members) | ||||||
|       const members = new MembersManager(gateway.client, guild) |  | ||||||
|       await members.fromPayload(d.members) |  | ||||||
|       guild.members = members |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|   if (d.channels !== undefined) { |   if (d.channels !== undefined) { | ||||||
|     for (const ch of d.channels as GuildChannelPayload[]) { |     for (const ch of d.channels as GuildChannelPayload[]) { | ||||||
|  | @ -27,38 +20,13 @@ export const guildCreate: GatewayEventHandler = async ( | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|     if (d.roles !== undefined) { |  | ||||||
|       const roles = new RolesManager(gateway.client, guild) |  | ||||||
|       await roles.fromPayload(d.roles) |  | ||||||
|       guild.roles = roles |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     guild.refreshFromData(d) |  | ||||||
|   } else { |  | ||||||
|     await gateway.client.guilds.set(d.id, d) |  | ||||||
|     guild = new Guild(gateway.client, d) |  | ||||||
| 
 |  | ||||||
|     if (d.members !== undefined) { |  | ||||||
|       const members = new MembersManager(gateway.client, guild) |  | ||||||
|       await members.fromPayload(d.members) |  | ||||||
|       guild.members = members |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (d.channels !== undefined) { |  | ||||||
|       for (const ch of d.channels as GuildChannelPayload[]) { |  | ||||||
|         ch.guild_id = d.id |  | ||||||
|         await gateway.client.channels.set(ch.id, ch) |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (d.roles !== undefined) { |  | ||||||
|       const roles = new RolesManager(gateway.client, guild) |  | ||||||
|       await roles.fromPayload(d.roles) |  | ||||||
|       guild.roles = roles |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|   await guild.roles.fromPayload(d.roles) |   await guild.roles.fromPayload(d.roles) | ||||||
|     guild = new Guild(gateway.client, d) | 
 | ||||||
|  |   if (d.voice_states !== undefined) | ||||||
|  |     await guild.voiceStates.fromPayload(d.voice_states) | ||||||
|  | 
 | ||||||
|  |   if (hasGuild === undefined) { | ||||||
|  |     // It wasn't lazy load, so emit event
 | ||||||
|     gateway.client.emit('guildCreate', guild) |     gateway.client.emit('guildCreate', guild) | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| import { Emoji } from "../../structures/emoji.ts" | import { Emoji } from '../../structures/emoji.ts' | ||||||
| import { Guild } from '../../structures/guild.ts' | import { Guild } from '../../structures/guild.ts' | ||||||
| import { EmojiPayload } from "../../types/emoji.ts" | import { EmojiPayload } from '../../types/emoji.ts' | ||||||
| import { GuildEmojiUpdatePayload } from '../../types/gateway.ts' | import { GuildEmojiUpdatePayload } from '../../types/gateway.ts' | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| 
 | 
 | ||||||
|  | @ -13,27 +13,27 @@ export const guildEmojiUpdate: GatewayEventHandler = async ( | ||||||
|     const emojis = await guild.emojis.collection() |     const emojis = await guild.emojis.collection() | ||||||
|     const deleted: Emoji[] = [] |     const deleted: Emoji[] = [] | ||||||
|     const added: Emoji[] = [] |     const added: Emoji[] = [] | ||||||
|     const updated: Array<{ before: Emoji, after: Emoji }> = [] |     const updated: Array<{ before: Emoji; after: Emoji }> = [] | ||||||
|     const _updated: EmojiPayload[] = [] |     const _updated: EmojiPayload[] = [] | ||||||
| 
 | 
 | ||||||
|     for (const raw of d.emojis) { |     for (const raw of d.emojis) { | ||||||
|       const has = emojis.get(raw.id) |       const has = emojis.get(raw.id) | ||||||
|       if (has === undefined) { |       if (has === undefined) { | ||||||
|         await guild.emojis.set(raw.id, raw) |         await guild.emojis.set(raw.id, raw) | ||||||
|         const emoji = await guild.emojis.get(raw.id) as Emoji |         const emoji = (await guild.emojis.get(raw.id)) as Emoji | ||||||
|         added.push(emoji) |         added.push(emoji) | ||||||
|       } else _updated.push(raw) |       } else _updated.push(raw) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     for (const emoji of emojis.values()) { |     for (const emoji of emojis.values()) { | ||||||
|       const find = _updated.find(e => emoji.id === e.id) |       const find = _updated.find((e) => emoji.id === e.id) | ||||||
|       if (find === undefined) { |       if (find === undefined) { | ||||||
|         await guild.emojis.delete(emoji.id) |         await guild.emojis.delete(emoji.id) | ||||||
|         deleted.push(emoji) |         deleted.push(emoji) | ||||||
|       } else { |       } else { | ||||||
|         const before = await guild.emojis.get(find.id) as Emoji |         const before = (await guild.emojis.get(find.id)) as Emoji | ||||||
|         await guild.emojis.set(find.id, find) |         await guild.emojis.set(find.id, find) | ||||||
|         const after = await guild.emojis.get(find.id) as Emoji |         const after = (await guild.emojis.get(find.id)) as Emoji | ||||||
|         updated.push({ before, after }) |         updated.push({ before, after }) | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| import { Guild } from '../../structures/guild.ts' | import { Guild } from '../../structures/guild.ts' | ||||||
| import { GuildIntegrationsUpdatePayload } from "../../types/gateway.ts" | import { GuildIntegrationsUpdatePayload } from '../../types/gateway.ts' | ||||||
| 
 | 
 | ||||||
| export const guildIntegrationsUpdate: GatewayEventHandler = async ( | export const guildIntegrationsUpdate: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| import { Guild } from '../../structures/guild.ts' | import { Guild } from '../../structures/guild.ts' | ||||||
| import { GuildMemberAddPayload } from "../../types/gateway.ts" | import { GuildMemberAddPayload } from '../../types/gateway.ts' | ||||||
| import { Member } from "../../structures/member.ts" | import { Member } from '../../structures/member.ts' | ||||||
| 
 | 
 | ||||||
| export const guildMemberAdd: GatewayEventHandler = async ( | export const guildMemberAdd: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|  | @ -12,6 +12,6 @@ export const guildMemberAdd: GatewayEventHandler = async ( | ||||||
|   if (guild === undefined) return |   if (guild === undefined) return | ||||||
| 
 | 
 | ||||||
|   await guild.members.set(d.user.id, d) |   await guild.members.set(d.user.id, d) | ||||||
|   const member = await guild.members.get(d.user.id) as Member |   const member = (await guild.members.get(d.user.id)) as Member | ||||||
|   gateway.client.emit('guildMemberAdd', member) |   gateway.client.emit('guildMemberAdd', member) | ||||||
| } | } | ||||||
|  | @ -20,7 +20,7 @@ export const guildMemberUpdate: GatewayEventHandler = async ( | ||||||
|     nick: d.nick, |     nick: d.nick, | ||||||
|     premium_since: d.premium_since, |     premium_since: d.premium_since, | ||||||
|     deaf: member?.deaf ?? false, |     deaf: member?.deaf ?? false, | ||||||
|     mute: member?.mute ?? false |     mute: member?.mute ?? false, | ||||||
|   } |   } | ||||||
|   await guild.members.set(d.user.id, newMemberPayload) |   await guild.members.set(d.user.id, newMemberPayload) | ||||||
|   const newMember = await guild.members.get(d.user.id) |   const newMember = await guild.members.get(d.user.id) | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| import { Guild } from '../../structures/guild.ts' | import { Guild } from '../../structures/guild.ts' | ||||||
| import { GuildRoleDeletePayload } from "../../types/gateway.ts" | import { GuildRoleDeletePayload } from '../../types/gateway.ts' | ||||||
| 
 | 
 | ||||||
| export const guildRoleDelete: GatewayEventHandler = async ( | export const guildRoleDelete: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|  | @ -12,7 +12,7 @@ export const guildRoleDelete: GatewayEventHandler = async ( | ||||||
| 
 | 
 | ||||||
|   const role = await guild.roles.get(d.role_id) |   const role = await guild.roles.get(d.role_id) | ||||||
|   // Shouldn't happen either
 |   // Shouldn't happen either
 | ||||||
|   if(role === undefined) return |   if (role === undefined) return | ||||||
| 
 | 
 | ||||||
|   gateway.client.emit('guildRoleDelete', role) |   gateway.client.emit('guildRoleDelete', role) | ||||||
| } | } | ||||||
|  | @ -39,6 +39,12 @@ import { Collection } from '../../utils/collection.ts' | ||||||
| import { voiceServerUpdate } from './voiceServerUpdate.ts' | import { voiceServerUpdate } from './voiceServerUpdate.ts' | ||||||
| import { voiceStateUpdate } from './voiceStateUpdate.ts' | import { voiceStateUpdate } from './voiceStateUpdate.ts' | ||||||
| import { VoiceState } from '../../structures/voiceState.ts' | import { VoiceState } from '../../structures/voiceState.ts' | ||||||
|  | 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 { inviteCreate } from './inviteCreate.ts' | ||||||
| import { inviteDelete } from './inviteDelete.ts' | import { inviteDelete } from './inviteDelete.ts' | ||||||
| 
 | 
 | ||||||
|  | @ -62,7 +68,7 @@ export const gatewayHandlers: { | ||||||
|   GUILD_MEMBER_ADD: guildMemberAdd, |   GUILD_MEMBER_ADD: guildMemberAdd, | ||||||
|   GUILD_MEMBER_REMOVE: guildMemberRemove, |   GUILD_MEMBER_REMOVE: guildMemberRemove, | ||||||
|   GUILD_MEMBER_UPDATE: guildMemberUpdate, |   GUILD_MEMBER_UPDATE: guildMemberUpdate, | ||||||
|   GUILD_MEMBERS_CHUNK: undefined, |   GUILD_MEMBERS_CHUNK: guildMembersChunk, | ||||||
|   GUILD_ROLE_CREATE: guildRoleCreate, |   GUILD_ROLE_CREATE: guildRoleCreate, | ||||||
|   GUILD_ROLE_UPDATE: guildRoleUpdate, |   GUILD_ROLE_UPDATE: guildRoleUpdate, | ||||||
|   GUILD_ROLE_DELETE: guildRoleDelete, |   GUILD_ROLE_DELETE: guildRoleDelete, | ||||||
|  | @ -72,16 +78,16 @@ export const gatewayHandlers: { | ||||||
|   MESSAGE_UPDATE: messageUpdate, |   MESSAGE_UPDATE: messageUpdate, | ||||||
|   MESSAGE_DELETE: messageDelete, |   MESSAGE_DELETE: messageDelete, | ||||||
|   MESSAGE_DELETE_BULK: messageDeleteBulk, |   MESSAGE_DELETE_BULK: messageDeleteBulk, | ||||||
|   MESSAGE_REACTION_ADD: undefined, |   MESSAGE_REACTION_ADD: messageReactionAdd, | ||||||
|   MESSAGE_REACTION_REMOVE: undefined, |   MESSAGE_REACTION_REMOVE: messageReactionRemove, | ||||||
|   MESSAGE_REACTION_REMOVE_ALL: undefined, |   MESSAGE_REACTION_REMOVE_ALL: messageReactionRemoveAll, | ||||||
|   MESSAGE_REACTION_REMOVE_EMOJI: undefined, |   MESSAGE_REACTION_REMOVE_EMOJI: messageReactionRemoveEmoji, | ||||||
|   PRESENCE_UPDATE: undefined, |   PRESENCE_UPDATE: presenceUpdate, | ||||||
|   TYPING_START: typingStart, |   TYPING_START: typingStart, | ||||||
|   USER_UPDATE: userUpdate, |   USER_UPDATE: userUpdate, | ||||||
|   VOICE_STATE_UPDATE: voiceStateUpdate, |   VOICE_STATE_UPDATE: voiceStateUpdate, | ||||||
|   VOICE_SERVER_UPDATE: voiceServerUpdate, |   VOICE_SERVER_UPDATE: voiceServerUpdate, | ||||||
|   WEBHOOKS_UPDATE: webhooksUpdate |   WEBHOOKS_UPDATE: webhooksUpdate, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface EventTypes { | export interface EventTypes { | ||||||
|  | @ -95,37 +101,46 @@ export interface VoiceServerUpdateData { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface ClientEvents extends EventTypes { | export interface ClientEvents extends EventTypes { | ||||||
|   'ready': () => void |   ready: () => void | ||||||
|   'reconnect': () => void |   reconnect: () => void | ||||||
|   'resumed': () => void |   resumed: () => void | ||||||
|   'channelCreate': (channel: Channel) => void |   channelCreate: (channel: Channel) => void | ||||||
|   'channelDelete': (channel: Channel) => void |   channelDelete: (channel: Channel) => void | ||||||
|   'channelPinsUpdate': (before: TextChannel, after: TextChannel) => void |   channelPinsUpdate: (before: TextChannel, after: TextChannel) => void | ||||||
|   'channelUpdate': (before: Channel, after: Channel) => void |   channelUpdate: (before: Channel, after: Channel) => void | ||||||
|   'guildBanAdd': (guild: Guild, user: User) => void |   guildBanAdd: (guild: Guild, user: User) => void | ||||||
|   'guildBanRemove': (guild: Guild, user: User) => void |   guildBanRemove: (guild: Guild, user: User) => void | ||||||
|   'guildCreate': (guild: Guild) => void |   guildCreate: (guild: Guild) => void | ||||||
|   'guildDelete': (guild: Guild) => void |   guildDelete: (guild: Guild) => void | ||||||
|   'guildEmojiAdd': (guild: Guild, emoji: Emoji) => void |   guildEmojiAdd: (guild: Guild, emoji: Emoji) => void | ||||||
|   'guildEmojiDelete': (guild: Guild, emoji: Emoji) => void |   guildEmojiDelete: (guild: Guild, emoji: Emoji) => void | ||||||
|   'guildEmojiUpdate': (guild: Guild, before: Emoji, after: Emoji) => void |   guildEmojiUpdate: (guild: Guild, before: Emoji, after: Emoji) => void | ||||||
|   'guildIntegrationsUpdate': (guild: Guild) => void |   guildIntegrationsUpdate: (guild: Guild) => void | ||||||
|   'guildMemberAdd': (member: Member) => void |   guildMemberAdd: (member: Member) => void | ||||||
|   'guildMemberRemove': (member: Member) => void |   guildMemberRemove: (member: Member) => void | ||||||
|   'guildMemberUpdate': (before: Member, after: Member) => void |   guildMemberUpdate: (before: Member, after: Member) => void | ||||||
|   'guildRoleCreate': (role: Role) => void |   guildRoleCreate: (role: Role) => void | ||||||
|   'guildRoleDelete': (role: Role) => void |   guildRoleDelete: (role: Role) => void | ||||||
|   'guildRoleUpdate': (before: Role, after: Role) => void |   guildRoleUpdate: (before: Role, after: Role) => void | ||||||
|   'guildUpdate': (before: Guild, after: Guild) => void |   guildUpdate: (before: Guild, after: Guild) => void | ||||||
|   'messageCreate': (message: Message) => void |   messageCreate: (message: Message) => void | ||||||
|   'messageDelete': (message: Message) => void |   messageDelete: (message: Message) => void | ||||||
|   'messageDeleteBulk': (channel: GuildTextChannel, messages: Collection<string, Message>, uncached: Set<string>) => void |   messageDeleteBulk: ( | ||||||
|   'messageUpdate': (before: Message, after: Message) => void |     channel: GuildTextChannel, | ||||||
|   'typingStart': (user: User, channel: TextChannel, at: Date, guildData?: TypingStartGuildData) => void |     messages: Collection<string, Message>, | ||||||
|   'userUpdate': (before: User, after: User) => void |     uncached: Set<string> | ||||||
|   'voiceServerUpdate': (data: VoiceServerUpdateData) => void |   ) => void | ||||||
|   'voiceStateAdd': (state: VoiceState) => void |   messageUpdate: (before: Message, after: Message) => void | ||||||
|   'voiceStateRemove': (state: VoiceState) => void |   typingStart: ( | ||||||
|   'voiceStateUpdate': (state: VoiceState, after: VoiceState) => void |     user: User, | ||||||
|   'webhooksUpdate': (guild: Guild, channel: GuildTextChannel) => void |     channel: TextChannel, | ||||||
|  |     at: Date, | ||||||
|  |     guildData?: TypingStartGuildData | ||||||
|  |   ) => void | ||||||
|  |   userUpdate: (before: User, after: User) => void | ||||||
|  |   voiceServerUpdate: (data: VoiceServerUpdateData) => void | ||||||
|  |   voiceStateAdd: (state: VoiceState) => void | ||||||
|  |   voiceStateRemove: (state: VoiceState) => void | ||||||
|  |   voiceStateUpdate: (state: VoiceState, after: VoiceState) => void | ||||||
|  |   webhooksUpdate: (guild: Guild, channel: GuildTextChannel) => void | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| import { TextChannel } from '../../structures/textChannel.ts' | import { TextChannel } from '../../structures/textChannel.ts' | ||||||
| import { MessageDeletePayload } from "../../types/gateway.ts" | import { MessageDeletePayload } from '../../types/gateway.ts' | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| 
 | 
 | ||||||
| export const messageDelete: GatewayEventHandler = async ( | export const messageDelete: GatewayEventHandler = async ( | ||||||
|  | @ -13,7 +13,8 @@ export const messageDelete: GatewayEventHandler = async ( | ||||||
|     channel = (await gateway.client.channels.fetch(d.channel_id)) as TextChannel |     channel = (await gateway.client.channels.fetch(d.channel_id)) as TextChannel | ||||||
| 
 | 
 | ||||||
|   const message = await channel.messages.get(d.id) |   const message = await channel.messages.get(d.id) | ||||||
|   if (message === undefined) return gateway.client.emit('messageDeleteUncached', d) |   if (message === undefined) | ||||||
|  |     return gateway.client.emit('messageDeleteUncached', d) | ||||||
|   await channel.messages.delete(d.id) |   await channel.messages.delete(d.id) | ||||||
|   gateway.client.emit('messageDelete', message) |   gateway.client.emit('messageDelete', message) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,18 +1,22 @@ | ||||||
| import { Message } from "../../structures/message.ts" | import { Message } from '../../structures/message.ts' | ||||||
| import { GuildTextChannel } from '../../structures/textChannel.ts' | import { GuildTextChannel } from '../../structures/textChannel.ts' | ||||||
| import { MessageDeleteBulkPayload } from "../../types/gateway.ts" | import { MessageDeleteBulkPayload } from '../../types/gateway.ts' | ||||||
| import { Collection } from "../../utils/collection.ts" | import { Collection } from '../../utils/collection.ts' | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| 
 | 
 | ||||||
| export const messageDeleteBulk: GatewayEventHandler = async ( | export const messageDeleteBulk: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|   d: MessageDeleteBulkPayload |   d: MessageDeleteBulkPayload | ||||||
| ) => { | ) => { | ||||||
|   let channel = await gateway.client.channels.get<GuildTextChannel>(d.channel_id) |   let channel = await gateway.client.channels.get<GuildTextChannel>( | ||||||
|  |     d.channel_id | ||||||
|  |   ) | ||||||
|   // Fetch the channel if not cached
 |   // Fetch the channel if not cached
 | ||||||
|   if (channel === undefined) |   if (channel === undefined) | ||||||
|     // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
 |     // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
 | ||||||
|     channel = (await gateway.client.channels.fetch(d.channel_id)) as GuildTextChannel |     channel = (await gateway.client.channels.fetch( | ||||||
|  |       d.channel_id | ||||||
|  |     )) as GuildTextChannel | ||||||
| 
 | 
 | ||||||
|   const messages = new Collection<string, Message>() |   const messages = new Collection<string, Message>() | ||||||
|   const uncached = new Set<string>() |   const uncached = new Set<string>() | ||||||
|  |  | ||||||
							
								
								
									
										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 { Message } from '../../structures/message.ts' | ||||||
| import { TextChannel } from '../../structures/textChannel.ts' | import { TextChannel } from '../../structures/textChannel.ts' | ||||||
| import { User } from '../../structures/user.ts' |  | ||||||
| import { MessagePayload } from '../../types/channel.ts' | import { MessagePayload } from '../../types/channel.ts' | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| 
 | 
 | ||||||
|  | @ -11,19 +10,19 @@ export const messageUpdate: GatewayEventHandler = async ( | ||||||
|   let channel = await gateway.client.channels.get<TextChannel>(d.channel_id) |   let channel = await gateway.client.channels.get<TextChannel>(d.channel_id) | ||||||
|   // Fetch the channel if not cached
 |   // Fetch the channel if not cached
 | ||||||
|   if (channel === undefined) |   if (channel === undefined) | ||||||
|     // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
 |     channel = await gateway.client.channels.fetch(d.channel_id) | ||||||
|     channel = (await gateway.client.channels.fetch(d.channel_id)) as TextChannel | 
 | ||||||
|  |   if (channel === undefined) return | ||||||
| 
 | 
 | ||||||
|   const message = await channel.messages.get(d.id) |   const message = await channel.messages.get(d.id) | ||||||
|   const author = |   if (message === undefined) return | ||||||
|     message?.author !== undefined |   const raw = await channel.messages._get(d.id) | ||||||
|       ? message.author |   if (raw === undefined) return | ||||||
|       : new User(gateway.client, d.author) | 
 | ||||||
|   const newMsg = new Message(gateway.client, d, channel, author) |   const newRaw = raw | ||||||
|   if (message === undefined) { |   Object.assign(newRaw, d) | ||||||
|     await channel.messages.set(d.id, d) |   await channel.messages.set(d.id, newRaw) | ||||||
|     return gateway.client.emit('messageUpdateUncached', newMsg) | 
 | ||||||
|   } |   const newMsg = ((await channel.messages.get(d.id)) as unknown) as Message | ||||||
|   await channel.messages.set(d.id, d) |  | ||||||
|   gateway.client.emit('messageUpdate', message, newMsg) |   gateway.client.emit('messageUpdate', message, newMsg) | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										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,15 +1,18 @@ | ||||||
| import { User } from '../../structures/user.ts' | import { User } from '../../structures/user.ts' | ||||||
| import { Ready } from "../../types/gateway.ts" | import { Ready } from '../../types/gateway.ts' | ||||||
| import { GuildPayload } from '../../types/guild.ts' | import { GuildPayload } from '../../types/guild.ts' | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| 
 | 
 | ||||||
| export const ready: GatewayEventHandler = async (gateway: Gateway, d: Ready) => { | export const ready: GatewayEventHandler = async ( | ||||||
|  |   gateway: Gateway, | ||||||
|  |   d: Ready | ||||||
|  | ) => { | ||||||
|   await gateway.client.guilds.flush() |   await gateway.client.guilds.flush() | ||||||
| 
 | 
 | ||||||
|   gateway.client.user = new User(gateway.client, d.user) |   gateway.client.user = new User(gateway.client, d.user) | ||||||
|   gateway.sessionID = d.session_id |   gateway.sessionID = d.session_id | ||||||
|   gateway.debug(`Received READY. Session: ${gateway.sessionID}`) |   gateway.debug(`Received READY. Session: ${gateway.sessionID}`) | ||||||
|   await gateway.cache.set("session_id", gateway.sessionID) |   await gateway.cache.set('session_id', gateway.sessionID) | ||||||
| 
 | 
 | ||||||
|   d.guilds.forEach((guild: GuildPayload) => { |   d.guilds.forEach((guild: GuildPayload) => { | ||||||
|     gateway.client.guilds.set(guild.id, guild) |     gateway.client.guilds.set(guild.id, guild) | ||||||
|  |  | ||||||
|  | @ -1,5 +1,8 @@ | ||||||
| import { Gateway , GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| 
 | 
 | ||||||
| export const reconnect: GatewayEventHandler = async (gateway: Gateway, d: any) => { | export const reconnect: GatewayEventHandler = async ( | ||||||
|  |   gateway: Gateway, | ||||||
|  |   d: any | ||||||
|  | ) => { | ||||||
|   gateway.reconnect() |   gateway.reconnect() | ||||||
| } | } | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| import { Guild } from "../../structures/guild.ts" | import { Guild } from '../../structures/guild.ts' | ||||||
| import { VoiceServerUpdatePayload } from "../../types/gateway.ts" | import { VoiceServerUpdatePayload } from '../../types/gateway.ts' | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| 
 | 
 | ||||||
| export const voiceServerUpdate: GatewayEventHandler = async ( | export const voiceServerUpdate: GatewayEventHandler = async ( | ||||||
|  | @ -9,6 +9,6 @@ export const voiceServerUpdate: GatewayEventHandler = async ( | ||||||
|   gateway.client.emit('voiceServerUpdate', { |   gateway.client.emit('voiceServerUpdate', { | ||||||
|     token: d.token, |     token: d.token, | ||||||
|     endpoint: d.endpoint, |     endpoint: d.endpoint, | ||||||
|     guild: (await gateway.client.guilds.get(d.guild_id) as unknown) as Guild |     guild: ((await gateway.client.guilds.get(d.guild_id)) as unknown) as Guild, | ||||||
|   }) |   }) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| import { Guild } from "../../structures/guild.ts" | import { Guild } from '../../structures/guild.ts' | ||||||
| import { VoiceState } from "../../structures/voiceState.ts" | import { VoiceState } from '../../structures/voiceState.ts' | ||||||
| import { VoiceStatePayload } from "../../types/voice.ts" | import { MemberPayload } from '../../types/guild.ts' | ||||||
|  | import { VoiceStatePayload } from '../../types/voice.ts' | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| 
 | 
 | ||||||
| export const voiceStateUpdate: GatewayEventHandler = async ( | export const voiceStateUpdate: GatewayEventHandler = async ( | ||||||
|  | @ -9,22 +10,41 @@ export const voiceStateUpdate: GatewayEventHandler = async ( | ||||||
| ) => { | ) => { | ||||||
|   // TODO(DjDeveloperr): Support self-bot here; they can be in DMs (Call)
 |   // TODO(DjDeveloperr): Support self-bot here; they can be in DMs (Call)
 | ||||||
|   if (d.guild_id === undefined) return |   if (d.guild_id === undefined) return | ||||||
|   const guild = (await gateway.client.guilds.get(d.guild_id) as unknown) as Guild |   const guild = ((await gateway.client.guilds.get( | ||||||
|  |     d.guild_id | ||||||
|  |   )) as unknown) as Guild | ||||||
| 
 | 
 | ||||||
|   const voiceState = await guild.voiceStates.get(d.user_id) |   const voiceState = await guild.voiceStates.get(d.user_id) | ||||||
| 
 | 
 | ||||||
|   if (d.channel_id === null) { |   if (d.channel_id === null) { | ||||||
|  |     if (voiceState === undefined) { | ||||||
|  |       await guild.members.set(d.user_id, (d.member as unknown) as MemberPayload) | ||||||
|  |       const member = ((await guild.members.get( | ||||||
|  |         d.user_id | ||||||
|  |       )) as unknown) as MemberPayload | ||||||
|  |       return gateway.client.emit('voiceStateRemoveUncached', { guild, member }) | ||||||
|  |     } | ||||||
|     // No longer in the channel, so delete
 |     // No longer in the channel, so delete
 | ||||||
|     await guild.voiceStates.delete(d.user_id) |     await guild.voiceStates.delete(d.user_id) | ||||||
|     gateway.client.emit('voiceStateRemove', (voiceState as unknown) as VoiceState) |     gateway.client.emit( | ||||||
|  |       'voiceStateRemove', | ||||||
|  |       (voiceState as unknown) as VoiceState | ||||||
|  |     ) | ||||||
|     return |     return | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   await guild.voiceStates.set(d.user_id, d) |   await guild.voiceStates.set(d.user_id, d) | ||||||
|   const newVoiceState = await guild.voiceStates.get(d.user_id) |   const newVoiceState = await guild.voiceStates.get(d.user_id) | ||||||
|   if (voiceState === undefined) { |   if (voiceState === undefined) { | ||||||
|     gateway.client.emit('voiceStateAdd', (newVoiceState as unknown) as VoiceState) |     gateway.client.emit( | ||||||
|  |       'voiceStateAdd', | ||||||
|  |       (newVoiceState as unknown) as VoiceState | ||||||
|  |     ) | ||||||
|   } else { |   } else { | ||||||
|     gateway.client.emit('voiceStateUpdate', voiceState, (newVoiceState as unknown) as VoiceState) |     gateway.client.emit( | ||||||
|  |       'voiceStateUpdate', | ||||||
|  |       voiceState, | ||||||
|  |       (newVoiceState as unknown) as VoiceState | ||||||
|  |     ) | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| import { Guild } from '../../structures/guild.ts' | import { Guild } from '../../structures/guild.ts' | ||||||
| import { WebhooksUpdatePayload } from "../../types/gateway.ts" | import { WebhooksUpdatePayload } from '../../types/gateway.ts' | ||||||
| import { GuildTextChannel } from "../../structures/textChannel.ts" | import { GuildTextChannel } from '../../structures/textChannel.ts' | ||||||
| 
 | 
 | ||||||
| export const webhooksUpdate: GatewayEventHandler = async ( | export const webhooksUpdate: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|  | @ -10,7 +10,10 @@ export const webhooksUpdate: GatewayEventHandler = async ( | ||||||
|   const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) |   const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) | ||||||
|   if (guild === undefined) return |   if (guild === undefined) return | ||||||
| 
 | 
 | ||||||
|   const channel: GuildTextChannel | undefined = await guild.channels.get(d.channel_id) as GuildTextChannel |   const channel: GuildTextChannel | undefined = (await guild.channels.get( | ||||||
|   if (channel === undefined) gateway.client.emit('webhooksUpdateUncached', guild, d.channel_id) |     d.channel_id | ||||||
|  |   )) as GuildTextChannel | ||||||
|  |   if (channel === undefined) | ||||||
|  |     gateway.client.emit('webhooksUpdateUncached', guild, d.channel_id) | ||||||
|   else gateway.client.emit('webhooksUpdate', guild, channel) |   else gateway.client.emit('webhooksUpdate', guild, channel) | ||||||
| } | } | ||||||
|  | @ -1,30 +1,48 @@ | ||||||
| import { Client } from '../models/client.ts' | import { Client } from '../models/client.ts' | ||||||
| import { Guild } from "../structures/guild.ts" | import { Guild } from '../structures/guild.ts' | ||||||
| import { VoiceChannel } from "../structures/guildVoiceChannel.ts" | import { VoiceChannel } from '../structures/guildVoiceChannel.ts' | ||||||
| import { User } from "../structures/user.ts" | import { User } from '../structures/user.ts' | ||||||
| import { VoiceState } from "../structures/voiceState.ts" | import { VoiceState } from '../structures/voiceState.ts' | ||||||
| import { VoiceStatePayload } from "../types/voice.ts" | import { VoiceStatePayload } from '../types/voice.ts' | ||||||
| import { BaseManager } from './base.ts' | import { BaseManager } from './base.ts' | ||||||
| 
 | 
 | ||||||
| export class GuildVoiceStatesManager extends BaseManager<VoiceStatePayload, VoiceState> { | export class GuildVoiceStatesManager extends BaseManager< | ||||||
|  |   VoiceStatePayload, | ||||||
|  |   VoiceState | ||||||
|  | > { | ||||||
|   guild: Guild |   guild: Guild | ||||||
| 
 | 
 | ||||||
|   async get (key: string): Promise<VoiceState | undefined> { |   constructor(client: Client, guild: Guild) { | ||||||
|     const raw = await this._get(key) |  | ||||||
|     if (raw === undefined) return |  | ||||||
| 
 |  | ||||||
|     const guild = raw.guild_id === undefined ? undefined : await this.client.guilds.get(raw.guild_id) |  | ||||||
| 
 |  | ||||||
|     return new VoiceState(this.client, raw, { |  | ||||||
|       user: (await this.client.users.get(raw.user_id) as unknown) as User, |  | ||||||
|       channel: raw.channel_id == null ? null : (await this.client.channels.get<VoiceChannel>(raw.channel_id) as unknown) as VoiceChannel, |  | ||||||
|       guild, |  | ||||||
|       member: guild === undefined ? undefined : await guild.members.get(raw.user_id)  |  | ||||||
|     }) |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   constructor (client: Client, guild: Guild) { |  | ||||||
|     super(client, `vs:${guild.id}`, VoiceState) |     super(client, `vs:${guild.id}`, VoiceState) | ||||||
|     this.guild = guild |     this.guild = guild | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   async get(key: string): Promise<VoiceState | undefined> { | ||||||
|  |     const raw = await this._get(key) | ||||||
|  |     if (raw === undefined) return | ||||||
|  | 
 | ||||||
|  |     const guild = | ||||||
|  |       raw.guild_id === undefined | ||||||
|  |         ? undefined | ||||||
|  |         : await this.client.guilds.get(raw.guild_id) | ||||||
|  | 
 | ||||||
|  |     return new VoiceState(this.client, raw, { | ||||||
|  |       user: ((await this.client.users.get(raw.user_id)) as unknown) as User, | ||||||
|  |       channel: | ||||||
|  |         raw.channel_id == null | ||||||
|  |           ? null | ||||||
|  |           : (((await this.client.channels.get<VoiceChannel>( | ||||||
|  |               raw.channel_id | ||||||
|  |             )) as unknown) as VoiceChannel), | ||||||
|  |       guild, | ||||||
|  |       member: | ||||||
|  |         guild === undefined ? undefined : await guild.members.get(raw.user_id), | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async fromPayload(d: VoiceStatePayload[]): Promise<void> { | ||||||
|  |     for (const data of d) { | ||||||
|  |       await this.set(data.user_id, data) | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										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) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | @ -9,35 +9,46 @@ import { BaseManager } from './base.ts' | ||||||
| export class MessagesManager extends BaseManager<MessagePayload, Message> { | export class MessagesManager extends BaseManager<MessagePayload, Message> { | ||||||
|   channel: TextChannel |   channel: TextChannel | ||||||
| 
 | 
 | ||||||
|   constructor (client: Client, channel: TextChannel) { |   constructor(client: Client, channel: TextChannel) { | ||||||
|     super(client, 'messages', Message) |     super(client, 'messages', Message) | ||||||
|     this.channel = channel |     this.channel = channel | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async get (key: string): Promise<Message | undefined> { |   async get(key: string): Promise<Message | undefined> { | ||||||
|     const raw = await this._get(key) |     const raw = await this._get(key) | ||||||
|     if (raw === undefined) return |     if (raw === undefined) return | ||||||
| 
 | 
 | ||||||
|  |     if (raw.author === undefined) return | ||||||
|  | 
 | ||||||
|     let channel = await this.client.channels.get(raw.channel_id) |     let channel = await this.client.channels.get(raw.channel_id) | ||||||
|     if (channel === undefined) |     if (channel === undefined) | ||||||
|       channel = await this.client.channels.fetch(raw.channel_id) |       channel = await this.client.channels.fetch(raw.channel_id) | ||||||
| 
 | 
 | ||||||
|     const author = new User(this.client, raw.author) |     let author = ((await this.client.users.get( | ||||||
|  |       raw.author.id | ||||||
|  |     )) as unknown) as User | ||||||
|  | 
 | ||||||
|  |     if (author === undefined) author = new User(this.client, raw.author) | ||||||
| 
 | 
 | ||||||
|     const res = new this.DataType(this.client, raw, channel, author) as any |     const res = new this.DataType(this.client, raw, channel, author) as any | ||||||
|     await res.mentions.fromPayload(raw) |     await res.mentions.fromPayload(raw) | ||||||
|     return res |     return res | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async set (key: string, value: MessagePayload): Promise<any> { |   async set(key: string, value: MessagePayload): Promise<any> { | ||||||
|     return this.client.cache.set(this.cacheName, key, value, this.client.messageCacheLifetime) |     return this.client.cache.set( | ||||||
|  |       this.cacheName, | ||||||
|  |       key, | ||||||
|  |       value, | ||||||
|  |       this.client.messageCacheLifetime | ||||||
|  |     ) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async fetch (id: string): Promise<Message> { |   async fetch(id: string): Promise<Message> { | ||||||
|     return await new Promise((resolve, reject) => { |     return await new Promise((resolve, reject) => { | ||||||
|       this.client.rest |       this.client.rest | ||||||
|         .get(CHANNEL_MESSAGE(this.channel.id, id)) |         .get(CHANNEL_MESSAGE(this.channel.id, id)) | ||||||
|         .then(async data => { |         .then(async (data) => { | ||||||
|           await this.set(id, data as MessagePayload) |           await this.set(id, data as MessagePayload) | ||||||
| 
 | 
 | ||||||
|           let channel: any = await this.client.channels.get<TextChannel>( |           let channel: any = await this.client.channels.get<TextChannel>( | ||||||
|  | @ -63,7 +74,7 @@ export class MessagesManager extends BaseManager<MessagePayload, Message> { | ||||||
| 
 | 
 | ||||||
|           resolve(res) |           resolve(res) | ||||||
|         }) |         }) | ||||||
|         .catch(e => reject(e)) |         .catch((e) => reject(e)) | ||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										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 { UserManager } from '../managers/users.ts' | ||||||
| import { GuildManager } from '../managers/guilds.ts' | import { GuildManager } from '../managers/guilds.ts' | ||||||
| import { ChannelsManager } from '../managers/channels.ts' | import { ChannelsManager } from '../managers/channels.ts' | ||||||
| import { | import { ClientPresence } from '../structures/presence.ts' | ||||||
|   ClientPresence |  | ||||||
| } from '../structures/presence.ts' |  | ||||||
| import { EmojisManager } from '../managers/emojis.ts' | import { EmojisManager } from '../managers/emojis.ts' | ||||||
| import { ActivityGame, ClientActivity } from "../types/presence.ts" | import { ActivityGame, ClientActivity } from '../types/presence.ts' | ||||||
| import { ClientEvents } from "../gateway/handlers/index.ts" | import { ClientEvents } from '../gateway/handlers/index.ts' | ||||||
| // import { Application } from "../../mod.ts"
 | // import { Application } from "../../mod.ts"
 | ||||||
| 
 | 
 | ||||||
| /** Some Client Options to modify behaviour */ | /** Some Client Options to modify behaviour */ | ||||||
|  | @ -22,9 +20,9 @@ export interface ClientOptions { | ||||||
|   /** Gateway Intents */ |   /** Gateway Intents */ | ||||||
|   intents?: GatewayIntents[] |   intents?: GatewayIntents[] | ||||||
|   /** Cache Adapter to use, defaults to Collections one */ |   /** Cache Adapter to use, defaults to Collections one */ | ||||||
|   cache?: ICacheAdapter, |   cache?: ICacheAdapter | ||||||
|   /** Force New Session and don't use cached Session (by persistent caching) */ |   /** Force New Session and don't use cached Session (by persistent caching) */ | ||||||
|   forceNewSession?: boolean, |   forceNewSession?: boolean | ||||||
|   /** Startup presence of client */ |   /** Startup presence of client */ | ||||||
|   presence?: ClientPresence | ClientActivity | ActivityGame |   presence?: ClientPresence | ClientActivity | ActivityGame | ||||||
|   /** Whether it's a bot user or not? Use this if selfbot! */ |   /** Whether it's a bot user or not? Use this if selfbot! */ | ||||||
|  | @ -33,19 +31,21 @@ export interface ClientOptions { | ||||||
|   canary?: boolean |   canary?: boolean | ||||||
|   /** Time till which Messages are to be cached, in MS. Default is 3600000 */ |   /** Time till which Messages are to be cached, in MS. Default is 3600000 */ | ||||||
|   messageCacheLifetime?: number |   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 { | export declare interface Client { | ||||||
|   on: <U extends string>( |   on: <U extends string>(event: U, listener: ClientEvents[U]) => this | ||||||
|     event: U, listener: ClientEvents[U] |  | ||||||
|   ) => this |  | ||||||
| 
 | 
 | ||||||
|   emit: <U extends string>( |   emit: <U extends string>( | ||||||
|     event: U, ...args: Parameters<ClientEvents[U]> |     event: U, | ||||||
|  |     ...args: Parameters<ClientEvents[U]> | ||||||
|   ) => boolean |   ) => boolean | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| /** | /** | ||||||
|  * Discord Client. |  * Discord Client. | ||||||
|  */ |  */ | ||||||
|  | @ -68,6 +68,10 @@ export class Client extends EventEmitter { | ||||||
|   forceNewSession?: boolean |   forceNewSession?: boolean | ||||||
|   /** Time till messages to stay cached, in MS. */ |   /** Time till messages to stay cached, in MS. */ | ||||||
|   messageCacheLifetime: number = 3600000 |   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) |   users: UserManager = new UserManager(this) | ||||||
|   guilds: GuildManager = new GuildManager(this) |   guilds: GuildManager = new GuildManager(this) | ||||||
|  | @ -81,7 +85,7 @@ export class Client extends EventEmitter { | ||||||
|   /** Client's presence. Startup one if set before connecting */ |   /** Client's presence. Startup one if set before connecting */ | ||||||
|   presence: ClientPresence = new ClientPresence() |   presence: ClientPresence = new ClientPresence() | ||||||
| 
 | 
 | ||||||
|   constructor (options: ClientOptions = {}) { |   constructor(options: ClientOptions = {}) { | ||||||
|     super() |     super() | ||||||
|     this.token = options.token |     this.token = options.token | ||||||
|     this.intents = options.intents |     this.intents = options.intents | ||||||
|  | @ -94,17 +98,22 @@ export class Client extends EventEmitter { | ||||||
|           : new ClientPresence(options.presence) |           : new ClientPresence(options.presence) | ||||||
|     if (options.bot === false) this.bot = false |     if (options.bot === false) this.bot = false | ||||||
|     if (options.canary === true) this.canary = true |     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 */ |   /** Set Cache Adapter */ | ||||||
|   setAdapter (adapter: ICacheAdapter): Client { |   setAdapter(adapter: ICacheAdapter): Client { | ||||||
|     this.cache = adapter |     this.cache = adapter | ||||||
|     return this |     return this | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** Change Presence of Client */ |   /** Change Presence of Client */ | ||||||
|   setPresence (presence: ClientPresence | ClientActivity | ActivityGame): void { |   setPresence(presence: ClientPresence | ClientActivity | ActivityGame): void { | ||||||
|     if (presence instanceof ClientPresence) { |     if (presence instanceof ClientPresence) { | ||||||
|       this.presence = presence |       this.presence = presence | ||||||
|     } else this.presence = new ClientPresence(presence) |     } else this.presence = new ClientPresence(presence) | ||||||
|  | @ -112,7 +121,7 @@ export class Client extends EventEmitter { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** Emit debug event */ |   /** Emit debug event */ | ||||||
|   debug (tag: string, msg: string): void { |   debug(tag: string, msg: string): void { | ||||||
|     this.emit('debug', `[${tag}] ${msg}`) |     this.emit('debug', `[${tag}] ${msg}`) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -124,7 +133,7 @@ export class Client extends EventEmitter { | ||||||
|    * @param token Your token. This is required. |    * @param token Your token. This is required. | ||||||
|    * @param intents Gateway intents in array. 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 |     if (token === undefined && this.token !== undefined) token = this.token | ||||||
|     else if (this.token === undefined && token !== undefined) { |     else if (this.token === undefined && token !== undefined) { | ||||||
|       this.token = token |       this.token = token | ||||||
|  |  | ||||||
|  | @ -4,7 +4,7 @@ import { TextChannel } from '../structures/textChannel.ts' | ||||||
| import { User } from '../structures/user.ts' | import { User } from '../structures/user.ts' | ||||||
| import { Collection } from '../utils/collection.ts' | import { Collection } from '../utils/collection.ts' | ||||||
| import { CommandClient } from './commandClient.ts' | import { CommandClient } from './commandClient.ts' | ||||||
| import { Extension } from "./extensions.ts" | import { Extension } from './extensions.ts' | ||||||
| 
 | 
 | ||||||
| export interface CommandContext { | export interface CommandContext { | ||||||
|   /** The Client object */ |   /** The Client object */ | ||||||
|  | @ -34,6 +34,8 @@ export class Command { | ||||||
|   name: string = '' |   name: string = '' | ||||||
|   /** Description of the Command */ |   /** Description of the Command */ | ||||||
|   description?: string |   description?: string | ||||||
|  |   /** Category of the Command */ | ||||||
|  |   category?: string | ||||||
|   /** Array of Aliases of Command, or only string */ |   /** Array of Aliases of Command, or only string */ | ||||||
|   aliases?: string | string[] |   aliases?: string | string[] | ||||||
|   /** Extension (Parent) of the Command */ |   /** Extension (Parent) of the Command */ | ||||||
|  | @ -42,10 +44,12 @@ export class Command { | ||||||
|   usage?: string | string[] |   usage?: string | string[] | ||||||
|   /** Usage Example of Command, only Arguments (without Prefix and Name) */ |   /** Usage Example of Command, only Arguments (without Prefix and Name) */ | ||||||
|   examples?: string | string[] |   examples?: string | string[] | ||||||
|   /** Does the Command take Arguments? Maybe number of required arguments? */ |   /** Does the Command take Arguments? Maybe number of required arguments? Or list of arguments? */ | ||||||
|   args?: number | boolean |   args?: number | boolean | string[] | ||||||
|   /** Permission(s) required for using Command */ |   /** Permissions(s) required by both User and Bot in order to use Command */ | ||||||
|   permissions?: string | string[] |   permissions?: string | string[] | ||||||
|  |   /** Permission(s) required for using Command */ | ||||||
|  |   userPermissions?: string | string[] | ||||||
|   /** Permission(s) bot will need in order to execute Command */ |   /** Permission(s) bot will need in order to execute Command */ | ||||||
|   botPermissions?: string | string[] |   botPermissions?: string | string[] | ||||||
|   /** Role(s) user will require in order to use Command. List or one of ID or name */ |   /** Role(s) user will require in order to use Command. List or one of ID or name */ | ||||||
|  | @ -64,14 +68,189 @@ export class Command { | ||||||
|   ownerOnly?: boolean |   ownerOnly?: boolean | ||||||
| 
 | 
 | ||||||
|   /** Method executed before executing actual command. Returns bool value - whether to continue or not (optional) */ |   /** Method executed before executing actual command. Returns bool value - whether to continue or not (optional) */ | ||||||
|   beforeExecute(ctx: CommandContext): boolean | Promise<boolean> { return true } |   beforeExecute(ctx: CommandContext): boolean | Promise<boolean> { | ||||||
|  |     return true | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   /** Actual command code, which is executed when all checks have passed. */ |   /** Actual command code, which is executed when all checks have passed. */ | ||||||
|   execute(ctx: CommandContext): any { } |   execute(ctx: CommandContext): any {} | ||||||
|   /** Method executed after executing command, passes on CommandContext and the value returned by execute too. (optional) */ |   /** Method executed after executing command, passes on CommandContext and the value returned by execute too. (optional) */ | ||||||
|   afterExecute(ctx: CommandContext, executeResult: any): any { } |   afterExecute(ctx: CommandContext, executeResult: any): any {} | ||||||
| 
 | 
 | ||||||
|   toString(): string { |   toString(): string { | ||||||
|     return `Command: ${this.name}${this.extension !== undefined ? ` [${this.extension.name}]` : ''}` |     return `Command: ${this.name}${ | ||||||
|  |       this.extension !== undefined | ||||||
|  |         ? ` [${this.extension.name}]` | ||||||
|  |         : this.category !== undefined | ||||||
|  |         ? ` [${this.category}]` | ||||||
|  |         : '' | ||||||
|  |     }` | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export class CommandCategory { | ||||||
|  |   /** Name of the Category. */ | ||||||
|  |   name: string = '' | ||||||
|  |   /** Permissions(s) required by both User and Bot in order to use Category Commands */ | ||||||
|  |   permissions?: string | string[] | ||||||
|  |   /** Permission(s) required for using Category Commands */ | ||||||
|  |   userPermissions?: string | string[] | ||||||
|  |   /** Permission(s) bot will need in order to execute Category Commands */ | ||||||
|  |   botPermissions?: string | string[] | ||||||
|  |   /** Role(s) user will require in order to use Category Commands. List or one of ID or name */ | ||||||
|  |   roles?: string | string[] | ||||||
|  |   /** Whitelisted Guilds. Only these Guild(s) can execute Category Commands. (List or one of IDs) */ | ||||||
|  |   whitelistedGuilds?: string | string[] | ||||||
|  |   /** Whitelisted Channels. Category Commands can be executed only in these channels. (List or one of IDs) */ | ||||||
|  |   whitelistedChannels?: string | string[] | ||||||
|  |   /** Whitelisted Users. Category Commands can be executed only by these Users (List or one of IDs) */ | ||||||
|  |   whitelistedUsers?: string | string[] | ||||||
|  |   /** Whether the Category Commands can only be used in Guild (if allowed in DMs) */ | ||||||
|  |   guildOnly?: boolean | ||||||
|  |   /** Whether the Category Commands can only be used in Bot's DMs (if allowed) */ | ||||||
|  |   dmOnly?: boolean | ||||||
|  |   /** Whether the Category Commands can only be used by Bot Owners */ | ||||||
|  |   ownerOnly?: boolean | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export class CommandBuilder extends Command { | ||||||
|  |   setName(name: string): CommandBuilder { | ||||||
|  |     this.name = name | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setDescription(description?: string): CommandBuilder { | ||||||
|  |     this.description = description | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setCategory(category?: string): CommandBuilder { | ||||||
|  |     this.category = category | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setAlias(alias: string | string[]): CommandBuilder { | ||||||
|  |     this.aliases = alias | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   addAlias(alias: string | string[]): CommandBuilder { | ||||||
|  |     if (this.aliases === undefined) this.aliases = [] | ||||||
|  |     if (typeof this.aliases === 'string') this.aliases = [this.aliases] | ||||||
|  | 
 | ||||||
|  |     this.aliases = [ | ||||||
|  |       ...new Set( | ||||||
|  |         ...this.aliases, | ||||||
|  |         ...(typeof alias === 'string' ? [alias] : alias) | ||||||
|  |       ), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setExtension(extension?: Extension): CommandBuilder { | ||||||
|  |     this.extension = extension | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setUsage(usage: string | string[]): CommandBuilder { | ||||||
|  |     this.usage = usage | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   addUsage(usage: string | string[]): CommandBuilder { | ||||||
|  |     if (this.usage === undefined) this.usage = [] | ||||||
|  |     if (typeof this.usage === 'string') this.usage = [this.usage] | ||||||
|  | 
 | ||||||
|  |     this.aliases = [ | ||||||
|  |       ...new Set( | ||||||
|  |         ...this.usage, | ||||||
|  |         ...(typeof usage === 'string' ? [usage] : usage) | ||||||
|  |       ), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setExample(examples: string | string[]): CommandBuilder { | ||||||
|  |     this.examples = examples | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   addExample(examples: string | string[]): CommandBuilder { | ||||||
|  |     if (this.examples === undefined) this.examples = [] | ||||||
|  |     if (typeof this.examples === 'string') this.examples = [this.examples] | ||||||
|  | 
 | ||||||
|  |     this.examples = [ | ||||||
|  |       ...new Set( | ||||||
|  |         ...this.examples, | ||||||
|  |         ...(typeof examples === 'string' ? [examples] : examples) | ||||||
|  |       ), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setPermissions(perms?: string | string[]): CommandBuilder { | ||||||
|  |     this.permissions = perms | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setUserPermissions(perms?: string | string[]): CommandBuilder { | ||||||
|  |     this.userPermissions = perms | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setBotPermissions(perms?: string | string[]): CommandBuilder { | ||||||
|  |     this.botPermissions = perms | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setRoles(roles: string | string[]): CommandBuilder { | ||||||
|  |     this.roles = roles | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setWhitelistedGuilds(list: string | string[]): CommandBuilder { | ||||||
|  |     this.whitelistedGuilds = list | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setWhitelistedUsers(list: string | string[]): CommandBuilder { | ||||||
|  |     this.whitelistedUsers = list | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setWhitelistedChannels(list: string | string[]): CommandBuilder { | ||||||
|  |     this.whitelistedChannels = list | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setGuildOnly(value: boolean = true): CommandBuilder { | ||||||
|  |     this.guildOnly = value | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setOwnerOnly(value: boolean = true): CommandBuilder { | ||||||
|  |     this.ownerOnly = value | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   onBeforeExecute(fn: (ctx: CommandContext) => boolean | any): CommandBuilder { | ||||||
|  |     this.beforeExecute = fn | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   onExecute(fn: (ctx: CommandContext) => any): CommandBuilder { | ||||||
|  |     this.execute = fn | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   onAfterExecute( | ||||||
|  |     fn: (ctx: CommandContext, executeResult?: any) => any | ||||||
|  |   ): CommandBuilder { | ||||||
|  |     this.afterExecute = fn | ||||||
|  |     return this | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -85,7 +264,9 @@ export class CommandsManager { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** Number of loaded Commands */ |   /** Number of loaded Commands */ | ||||||
|   get count(): number { return this.list.size } |   get count(): number { | ||||||
|  |     return this.list.size | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|   /** Find a Command by name/alias */ |   /** Find a Command by name/alias */ | ||||||
|   find(search: string): Command | undefined { |   find(search: string): Command | undefined { | ||||||
|  | @ -99,7 +280,7 @@ export class CommandsManager { | ||||||
|         if (typeof cmd.aliases === 'string') aliases = [cmd.aliases] |         if (typeof cmd.aliases === 'string') aliases = [cmd.aliases] | ||||||
|         else aliases = cmd.aliases |         else aliases = cmd.aliases | ||||||
|         if (this.client.caseSensitive === false) |         if (this.client.caseSensitive === false) | ||||||
|           aliases = aliases.map(e => e.toLowerCase()) |           aliases = aliases.map((e) => e.toLowerCase()) | ||||||
|         return aliases.includes(search) |         return aliases.includes(search) | ||||||
|       } else return false |       } else return false | ||||||
|     }) |     }) | ||||||
|  | @ -123,8 +304,9 @@ export class CommandsManager { | ||||||
|         const aliases: string[] = |         const aliases: string[] = | ||||||
|           typeof search.aliases === 'string' ? [search.aliases] : search.aliases |           typeof search.aliases === 'string' ? [search.aliases] : search.aliases | ||||||
|         exists = |         exists = | ||||||
|           aliases.map(alias => this.find(alias) !== undefined).find(e => e) ?? |           aliases | ||||||
|           false |             .map((alias) => this.find(alias) !== undefined) | ||||||
|  |             .find((e) => e) ?? false | ||||||
|       } |       } | ||||||
|       return exists |       return exists | ||||||
|     } |     } | ||||||
|  | @ -134,7 +316,10 @@ export class CommandsManager { | ||||||
|   add(cmd: Command | typeof Command): boolean { |   add(cmd: Command | typeof Command): boolean { | ||||||
|     // eslint-disable-next-line new-cap
 |     // eslint-disable-next-line new-cap
 | ||||||
|     if (!(cmd instanceof Command)) cmd = new cmd() |     if (!(cmd instanceof Command)) cmd = new cmd() | ||||||
|     if (this.exists(cmd)) throw new Error(`Failed to add Command '${cmd.toString()}' with name/alias already exists.`) |     if (this.exists(cmd)) | ||||||
|  |       throw new Error( | ||||||
|  |         `Failed to add Command '${cmd.toString()}' with name/alias already exists.` | ||||||
|  |       ) | ||||||
|     this.list.set(cmd.name, cmd) |     this.list.set(cmd.name, cmd) | ||||||
|     return true |     return true | ||||||
|   } |   } | ||||||
|  | @ -148,7 +333,7 @@ export class CommandsManager { | ||||||
| 
 | 
 | ||||||
|   /** Check whether a Command is disabled or not */ |   /** Check whether a Command is disabled or not */ | ||||||
|   isDisabled(name: string | Command): boolean { |   isDisabled(name: string | Command): boolean { | ||||||
|     const cmd = typeof name === "string" ? this.find(name) : name |     const cmd = typeof name === 'string' ? this.find(name) : name | ||||||
|     if (cmd === undefined) return false |     if (cmd === undefined) return false | ||||||
|     const exists = this.exists(name) |     const exists = this.exists(name) | ||||||
|     if (!exists) return false |     if (!exists) return false | ||||||
|  | @ -157,12 +342,65 @@ export class CommandsManager { | ||||||
| 
 | 
 | ||||||
|   /** Disable a Command */ |   /** Disable a Command */ | ||||||
|   disable(name: string | Command): boolean { |   disable(name: string | Command): boolean { | ||||||
|     const cmd = typeof name === "string" ? this.find(name) : name |     const cmd = typeof name === 'string' ? this.find(name) : name | ||||||
|     if (cmd === undefined) return false |     if (cmd === undefined) return false | ||||||
|     if (this.isDisabled(cmd)) return false |     if (this.isDisabled(cmd)) return false | ||||||
|     this.disabled.add(cmd.name) |     this.disabled.add(cmd.name) | ||||||
|     return true |     return true | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   /** Get all commands of a Category */ | ||||||
|  |   category(category: string): Collection<string, Command> { | ||||||
|  |     return this.list.filter( | ||||||
|  |       (cmd) => cmd.category !== undefined && cmd.category === category | ||||||
|  |     ) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export class CategoriesManager { | ||||||
|  |   client: CommandClient | ||||||
|  |   list: Collection<string, CommandCategory> = new Collection() | ||||||
|  | 
 | ||||||
|  |   constructor(client: CommandClient) { | ||||||
|  |     this.client = client | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Get a Collection of Categories */ | ||||||
|  |   all(): Collection<string, CommandCategory> { | ||||||
|  |     return this.list | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Get a list of names of Categories added */ | ||||||
|  |   names(): string[] { | ||||||
|  |     return [...this.list.keys()] | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Check if a Category exists or not */ | ||||||
|  |   has(category: string | CommandCategory): boolean { | ||||||
|  |     return this.list.has( | ||||||
|  |       typeof category === 'string' ? category : category.name | ||||||
|  |     ) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Get a Category by name */ | ||||||
|  |   get(name: string): CommandCategory | undefined { | ||||||
|  |     return this.list.get(name) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Add a Category to the Manager */ | ||||||
|  |   add(category: CommandCategory): CategoriesManager { | ||||||
|  |     if (this.has(category)) | ||||||
|  |       throw new Error(`Category ${category.name} already exists`) | ||||||
|  |     this.list.set(category.name, category) | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Remove a Category from the Manager */ | ||||||
|  |   remove(category: string | CommandCategory): boolean { | ||||||
|  |     if (!this.has(category)) return false | ||||||
|  |     this.list.delete(typeof category === 'string' ? category : category.name) | ||||||
|  |     return true | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface ParsedCommand { | export interface ParsedCommand { | ||||||
|  | @ -185,6 +423,6 @@ export const parseCommand = ( | ||||||
|   return { |   return { | ||||||
|     name, |     name, | ||||||
|     args, |     args, | ||||||
|     argString |     argString, | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,8 +1,13 @@ | ||||||
| import { Message } from "../../mod.ts" | import { Message } from '../../mod.ts' | ||||||
| import { awaitSync } from "../utils/mixedPromise.ts" | import { awaitSync } from '../utils/mixedPromise.ts' | ||||||
| import { Client, ClientOptions } from './client.ts' | import { Client, ClientOptions } from './client.ts' | ||||||
| import { CommandContext, CommandsManager, parseCommand } from './command.ts' | import { | ||||||
| import { ExtensionsManager } from "./extensions.ts" |   CategoriesManager, | ||||||
|  |   CommandContext, | ||||||
|  |   CommandsManager, | ||||||
|  |   parseCommand, | ||||||
|  | } from './command.ts' | ||||||
|  | import { ExtensionsManager } from './extensions.ts' | ||||||
| 
 | 
 | ||||||
| type PrefixReturnType = string | string[] | Promise<string | string[]> | type PrefixReturnType = string | string[] | Promise<string | string[]> | ||||||
| 
 | 
 | ||||||
|  | @ -38,6 +43,7 @@ export class CommandClient extends Client implements CommandClientOptions { | ||||||
|   caseSensitive: boolean |   caseSensitive: boolean | ||||||
|   extensions: ExtensionsManager = new ExtensionsManager(this) |   extensions: ExtensionsManager = new ExtensionsManager(this) | ||||||
|   commands: CommandsManager = new CommandsManager(this) |   commands: CommandsManager = new CommandsManager(this) | ||||||
|  |   categories: CategoriesManager = new CategoriesManager(this) | ||||||
| 
 | 
 | ||||||
|   constructor(options: CommandClientOptions) { |   constructor(options: CommandClientOptions) { | ||||||
|     super(options) |     super(options) | ||||||
|  | @ -85,14 +91,20 @@ export class CommandClient extends Client implements CommandClientOptions { | ||||||
|   async processMessage(msg: Message): Promise<any> { |   async processMessage(msg: Message): Promise<any> { | ||||||
|     if (!this.allowBots && msg.author.bot === true) return |     if (!this.allowBots && msg.author.bot === true) return | ||||||
| 
 | 
 | ||||||
|     const isUserBlacklisted = await awaitSync(this.isUserBlacklisted(msg.author.id)) |     const isUserBlacklisted = await awaitSync( | ||||||
|  |       this.isUserBlacklisted(msg.author.id) | ||||||
|  |     ) | ||||||
|     if (isUserBlacklisted === true) return |     if (isUserBlacklisted === true) return | ||||||
| 
 | 
 | ||||||
|     const isChannelBlacklisted = await awaitSync(this.isChannelBlacklisted(msg.channel.id)) |     const isChannelBlacklisted = await awaitSync( | ||||||
|  |       this.isChannelBlacklisted(msg.channel.id) | ||||||
|  |     ) | ||||||
|     if (isChannelBlacklisted === true) return |     if (isChannelBlacklisted === true) return | ||||||
| 
 | 
 | ||||||
|     if (msg.guild !== undefined) { |     if (msg.guild !== undefined) { | ||||||
|       const isGuildBlacklisted = await awaitSync(this.isGuildBlacklisted(msg.guild.id)) |       const isGuildBlacklisted = await awaitSync( | ||||||
|  |         this.isGuildBlacklisted(msg.guild.id) | ||||||
|  |       ) | ||||||
|       if (isGuildBlacklisted === true) return |       if (isGuildBlacklisted === true) return | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -112,17 +124,20 @@ export class CommandClient extends Client implements CommandClientOptions { | ||||||
|         else return |         else return | ||||||
|       } |       } | ||||||
|     } else { |     } else { | ||||||
|       const usedPrefix = prefix.find(v => msg.content.startsWith(v)) |       const usedPrefix = prefix.find((v) => msg.content.startsWith(v)) | ||||||
|       if (usedPrefix === undefined) { |       if (usedPrefix === undefined) { | ||||||
|         if (this.mentionPrefix) mentionPrefix = true |         if (this.mentionPrefix) mentionPrefix = true | ||||||
|         else return |         else return | ||||||
|       } |       } else prefix = usedPrefix | ||||||
|       else prefix = usedPrefix |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (mentionPrefix) { |     if (mentionPrefix) { | ||||||
|       if (msg.content.startsWith(this.user?.mention as string) === true) prefix = this.user?.mention as string |       if (msg.content.startsWith(this.user?.mention as string) === true) | ||||||
|       else if (msg.content.startsWith(this.user?.nickMention as string) === true) prefix = this.user?.nickMention as string |         prefix = this.user?.mention as string | ||||||
|  |       else if ( | ||||||
|  |         msg.content.startsWith(this.user?.nickMention as string) === true | ||||||
|  |       ) | ||||||
|  |         prefix = this.user?.nickMention as string | ||||||
|       else return |       else return | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -132,10 +147,52 @@ export class CommandClient extends Client implements CommandClientOptions { | ||||||
|     const command = this.commands.find(parsed.name) |     const command = this.commands.find(parsed.name) | ||||||
| 
 | 
 | ||||||
|     if (command === undefined) return |     if (command === undefined) return | ||||||
|  |     const category = | ||||||
|  |       command.category !== undefined | ||||||
|  |         ? this.categories.get(command.category) | ||||||
|  |         : undefined | ||||||
| 
 | 
 | ||||||
|     if (command.whitelistedGuilds !== undefined && msg.guild !== undefined && command.whitelistedGuilds.includes(msg.guild.id) === false) return; |     // Guild whitelist exists, and if does and Command used in a Guild, is this Guild allowed?
 | ||||||
|     if (command.whitelistedChannels !== undefined && command.whitelistedChannels.includes(msg.channel.id) === false) return; |     // This is a bit confusing here, if these settings on a Command exist, and also do on Category, Command overrides them
 | ||||||
|     if (command.whitelistedUsers !== undefined && command.whitelistedUsers.includes(msg.author.id) === false) return; |     if ( | ||||||
|  |       command.whitelistedGuilds === undefined && | ||||||
|  |       category?.whitelistedGuilds !== undefined && | ||||||
|  |       msg.guild !== undefined && | ||||||
|  |       category.whitelistedGuilds.includes(msg.guild.id) === false | ||||||
|  |     ) | ||||||
|  |       return | ||||||
|  |     if ( | ||||||
|  |       command.whitelistedGuilds !== undefined && | ||||||
|  |       msg.guild !== undefined && | ||||||
|  |       command.whitelistedGuilds.includes(msg.guild.id) === false | ||||||
|  |     ) | ||||||
|  |       return | ||||||
|  | 
 | ||||||
|  |     // Checks for Channel Whitelist
 | ||||||
|  |     if ( | ||||||
|  |       command.whitelistedChannels === undefined && | ||||||
|  |       category?.whitelistedChannels !== undefined && | ||||||
|  |       category.whitelistedChannels.includes(msg.channel.id) === false | ||||||
|  |     ) | ||||||
|  |       return | ||||||
|  |     if ( | ||||||
|  |       command.whitelistedChannels !== undefined && | ||||||
|  |       command.whitelistedChannels.includes(msg.channel.id) === false | ||||||
|  |     ) | ||||||
|  |       return | ||||||
|  | 
 | ||||||
|  |     // Checks for Users Whitelist
 | ||||||
|  |     if ( | ||||||
|  |       command.whitelistedUsers === undefined && | ||||||
|  |       category?.whitelistedUsers !== undefined && | ||||||
|  |       category.whitelistedUsers.includes(msg.author.id) === false | ||||||
|  |     ) | ||||||
|  |       return | ||||||
|  |     if ( | ||||||
|  |       command.whitelistedUsers !== undefined && | ||||||
|  |       command.whitelistedUsers.includes(msg.author.id) === false | ||||||
|  |     ) | ||||||
|  |       return | ||||||
| 
 | 
 | ||||||
|     const ctx: CommandContext = { |     const ctx: CommandContext = { | ||||||
|       client: this, |       client: this, | ||||||
|  | @ -147,40 +204,117 @@ export class CommandClient extends Client implements CommandClientOptions { | ||||||
|       author: msg.author, |       author: msg.author, | ||||||
|       command, |       command, | ||||||
|       channel: msg.channel, |       channel: msg.channel, | ||||||
|       guild: msg.guild |       guild: msg.guild, | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (command.ownerOnly === true && !this.owners.includes(msg.author.id)) return this.emit('commandOwnerOnly', ctx, command) |     // In these checks too, Command overrides Category if present
 | ||||||
|     if (command.guildOnly === true && msg.guild === undefined) return this.emit('commandGuildOnly', ctx, command) |     // Check if Command is only for Owners
 | ||||||
|     if (command.dmOnly === true && msg.guild !== undefined) return this.emit('commandDmOnly', ctx, command) |     if ( | ||||||
|  |       (command.ownerOnly !== undefined || category === undefined | ||||||
|  |         ? command.ownerOnly | ||||||
|  |         : category.ownerOnly) === true && | ||||||
|  |       !this.owners.includes(msg.author.id) | ||||||
|  |     ) | ||||||
|  |       return this.emit('commandOwnerOnly', ctx, command) | ||||||
| 
 | 
 | ||||||
|     if (command.botPermissions !== undefined && msg.guild !== undefined) { |     // Check if Command is only for Guild
 | ||||||
|  |     if ( | ||||||
|  |       (command.guildOnly !== undefined || category === undefined | ||||||
|  |         ? command.guildOnly | ||||||
|  |         : category.guildOnly) === true && | ||||||
|  |       msg.guild === undefined | ||||||
|  |     ) | ||||||
|  |       return this.emit('commandGuildOnly', ctx, command) | ||||||
|  | 
 | ||||||
|  |     // Check if Command is only for DMs
 | ||||||
|  |     if ( | ||||||
|  |       (command.dmOnly !== undefined || category === undefined | ||||||
|  |         ? command.dmOnly | ||||||
|  |         : category.dmOnly) === true && | ||||||
|  |       msg.guild !== undefined | ||||||
|  |     ) | ||||||
|  |       return this.emit('commandDmOnly', ctx, command) | ||||||
|  | 
 | ||||||
|  |     const allPermissions = | ||||||
|  |       command.permissions !== undefined | ||||||
|  |         ? command.permissions | ||||||
|  |         : category?.permissions | ||||||
|  | 
 | ||||||
|  |     if ( | ||||||
|  |       (command.botPermissions !== undefined || | ||||||
|  |         category?.permissions !== undefined) && | ||||||
|  |       msg.guild !== undefined | ||||||
|  |     ) { | ||||||
|       // TODO: Check Overwrites too
 |       // TODO: Check Overwrites too
 | ||||||
|       const me = await msg.guild.me() |       const me = await msg.guild.me() | ||||||
|       const missing: string[] = [] |       const missing: string[] = [] | ||||||
| 
 | 
 | ||||||
|       for (const perm of command.botPermissions) { |       let permissions = | ||||||
|  |         command.botPermissions === undefined | ||||||
|  |           ? category?.permissions | ||||||
|  |           : command.botPermissions | ||||||
|  | 
 | ||||||
|  |       if (permissions !== undefined) { | ||||||
|  |         if (typeof permissions === 'string') permissions = [permissions] | ||||||
|  | 
 | ||||||
|  |         if (allPermissions !== undefined) | ||||||
|  |           permissions = [...new Set(...permissions, ...allPermissions)] | ||||||
|  | 
 | ||||||
|  |         for (const perm of permissions) { | ||||||
|           if (me.permissions.has(perm) === false) missing.push(perm) |           if (me.permissions.has(perm) === false) missing.push(perm) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|       if (missing.length !== 0) return this.emit('commandBotMissingPermissions', ctx, command, missing) |         if (missing.length !== 0) | ||||||
|  |           return this.emit( | ||||||
|  |             'commandBotMissingPermissions', | ||||||
|  |             ctx, | ||||||
|  |             command, | ||||||
|  |             missing | ||||||
|  |           ) | ||||||
|  |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (command.permissions !== undefined && msg.guild !== undefined) { |     if ( | ||||||
|  |       (command.userPermissions !== undefined || | ||||||
|  |         category?.userPermissions !== undefined) && | ||||||
|  |       msg.guild !== undefined | ||||||
|  |     ) { | ||||||
|  |       let permissions = | ||||||
|  |         command.userPermissions !== undefined | ||||||
|  |           ? command.userPermissions | ||||||
|  |           : category?.userPermissions | ||||||
|  | 
 | ||||||
|  |       if (permissions !== undefined) { | ||||||
|  |         if (typeof permissions === 'string') permissions = [permissions] | ||||||
|  | 
 | ||||||
|  |         if (allPermissions !== undefined) | ||||||
|  |           permissions = [...new Set(...permissions, ...allPermissions)] | ||||||
|  | 
 | ||||||
|         const missing: string[] = [] |         const missing: string[] = [] | ||||||
|       let perms: string[] = [] | 
 | ||||||
|       if (typeof command.permissions === 'string') perms = [command.permissions] |         for (const perm of permissions) { | ||||||
|       else perms = command.permissions |  | ||||||
|       for (const perm of perms) { |  | ||||||
|           const has = msg.member?.permissions.has(perm) |           const has = msg.member?.permissions.has(perm) | ||||||
|           if (has !== true) missing.push(perm) |           if (has !== true) missing.push(perm) | ||||||
|         } |         } | ||||||
|       if (missing.length !== 0) return this.emit('commandMissingPermissions', command, missing, ctx) | 
 | ||||||
|  |         if (missing.length !== 0) | ||||||
|  |           return this.emit( | ||||||
|  |             'commandUserMissingPermissions', | ||||||
|  |             command, | ||||||
|  |             missing, | ||||||
|  |             ctx | ||||||
|  |           ) | ||||||
|  |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (command.args !== undefined) { |     if (command.args !== undefined) { | ||||||
|       if (typeof command.args === 'boolean' && parsed.args.length === 0) return this.emit('commandMissingArgs', ctx, command) |       if (typeof command.args === 'boolean' && parsed.args.length === 0) | ||||||
|       else if (typeof command.args === 'number' && parsed.args.length < command.args) this.emit('commandMissingArgs', ctx, command)  |         return this.emit('commandMissingArgs', ctx, command) | ||||||
|  |       else if ( | ||||||
|  |         typeof command.args === 'number' && | ||||||
|  |         parsed.args.length < command.args | ||||||
|  |       ) | ||||||
|  |         this.emit('commandMissingArgs', ctx, command) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     try { |     try { | ||||||
|  |  | ||||||
|  | @ -7,7 +7,6 @@ import { | ||||||
|   MessageOption, |   MessageOption, | ||||||
|   MessagePayload, |   MessagePayload, | ||||||
|   MessageReference, |   MessageReference, | ||||||
|   Reaction |  | ||||||
| } from '../types/channel.ts' | } from '../types/channel.ts' | ||||||
| import { Client } from '../models/client.ts' | import { Client } from '../models/client.ts' | ||||||
| import { User } from './user.ts' | import { User } from './user.ts' | ||||||
|  | @ -17,6 +16,7 @@ import { CHANNEL_MESSAGE } from '../types/endpoint.ts' | ||||||
| import { MessageMentions } from './messageMentions.ts' | import { MessageMentions } from './messageMentions.ts' | ||||||
| import { TextChannel } from './textChannel.ts' | import { TextChannel } from './textChannel.ts' | ||||||
| import { Guild } from './guild.ts' | import { Guild } from './guild.ts' | ||||||
|  | import { MessageReactionsManager } from '../managers/messageReactions.ts' | ||||||
| 
 | 
 | ||||||
| type AllMessageOptions = MessageOption | Embed | type AllMessageOptions = MessageOption | Embed | ||||||
| 
 | 
 | ||||||
|  | @ -38,7 +38,7 @@ export class Message extends Base { | ||||||
|   mentionChannels?: ChannelMention[] |   mentionChannels?: ChannelMention[] | ||||||
|   attachments: Attachment[] |   attachments: Attachment[] | ||||||
|   embeds: Embed[] |   embeds: Embed[] | ||||||
|   reactions?: Reaction[] |   reactions: MessageReactionsManager | ||||||
|   nonce?: string | number |   nonce?: string | number | ||||||
|   pinned: boolean |   pinned: boolean | ||||||
|   webhookID?: string |   webhookID?: string | ||||||
|  | @ -48,7 +48,7 @@ export class Message extends Base { | ||||||
|   messageReference?: MessageReference |   messageReference?: MessageReference | ||||||
|   flags?: number |   flags?: number | ||||||
| 
 | 
 | ||||||
|   constructor ( |   constructor( | ||||||
|     client: Client, |     client: Client, | ||||||
|     data: MessagePayload, |     data: MessagePayload, | ||||||
|     channel: TextChannel, |     channel: TextChannel, | ||||||
|  | @ -68,8 +68,8 @@ export class Message extends Base { | ||||||
|     this.mentionRoles = data.mention_roles |     this.mentionRoles = data.mention_roles | ||||||
|     this.mentionChannels = data.mention_channels |     this.mentionChannels = data.mention_channels | ||||||
|     this.attachments = data.attachments |     this.attachments = data.attachments | ||||||
|     this.embeds = data.embeds.map(v => new Embed(v)) |     this.embeds = data.embeds.map((v) => new Embed(v)) | ||||||
|     this.reactions = data.reactions |     this.reactions = new MessageReactionsManager(this.client, this) | ||||||
|     this.nonce = data.nonce |     this.nonce = data.nonce | ||||||
|     this.pinned = data.pinned |     this.pinned = data.pinned | ||||||
|     this.webhookID = data.webhook_id |     this.webhookID = data.webhook_id | ||||||
|  | @ -81,7 +81,7 @@ export class Message extends Base { | ||||||
|     this.channel = channel |     this.channel = channel | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   protected readFromData (data: MessagePayload): void { |   protected readFromData(data: MessagePayload): void { | ||||||
|     super.readFromData(data) |     super.readFromData(data) | ||||||
|     this.channelID = data.channel_id ?? this.channelID |     this.channelID = data.channel_id ?? this.channelID | ||||||
|     this.guildID = data.guild_id ?? this.guildID |     this.guildID = data.guild_id ?? this.guildID | ||||||
|  | @ -93,8 +93,7 @@ export class Message extends Base { | ||||||
|     this.mentionRoles = data.mention_roles ?? this.mentionRoles |     this.mentionRoles = data.mention_roles ?? this.mentionRoles | ||||||
|     this.mentionChannels = data.mention_channels ?? this.mentionChannels |     this.mentionChannels = data.mention_channels ?? this.mentionChannels | ||||||
|     this.attachments = data.attachments ?? this.attachments |     this.attachments = data.attachments ?? this.attachments | ||||||
|     this.embeds = data.embeds.map(v => new Embed(v)) ?? this.embeds |     this.embeds = data.embeds.map((v) => new Embed(v)) ?? this.embeds | ||||||
|     this.reactions = data.reactions ?? this.reactions |  | ||||||
|     this.nonce = data.nonce ?? this.nonce |     this.nonce = data.nonce ?? this.nonce | ||||||
|     this.pinned = data.pinned ?? this.pinned |     this.pinned = data.pinned ?? this.pinned | ||||||
|     this.webhookID = data.webhook_id ?? this.webhookID |     this.webhookID = data.webhook_id ?? this.webhookID | ||||||
|  | @ -105,16 +104,26 @@ export class Message extends Base { | ||||||
|     this.flags = data.flags ?? this.flags |     this.flags = data.flags ?? this.flags | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async edit (text?: string, option?: MessageOption): Promise<Message> { |   /** 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) |     return this.channel.editMessage(this.id, text, option) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** These will **not** work in all servers, as this feature is coming slowly. */ |   /** Create a Reply to this Message. */ | ||||||
|   async reply(text?: string | AllMessageOptions, option?: AllMessageOptions): Promise<Message> { |   async reply( | ||||||
|  |     text?: string | AllMessageOptions, | ||||||
|  |     option?: AllMessageOptions | ||||||
|  |   ): Promise<Message> { | ||||||
|     return this.channel.send(text, option, this) |     return this.channel.send(text, option, this) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async delete (): Promise<void> { |   /** Delete the Message. */ | ||||||
|  |   async delete(): Promise<void> { | ||||||
|     return this.client.rest.delete(CHANNEL_MESSAGE(this.channelID, this.id)) |     return this.client.rest.delete(CHANNEL_MESSAGE(this.channelID, this.id)) | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,10 +1,10 @@ | ||||||
| import { Client } from "../models/client.ts"; | import { Client } from '../models/client.ts' | ||||||
| import { MessagePayload } from "../types/channel.ts"; | import { MessagePayload } from '../types/channel.ts' | ||||||
| import { Collection } from "../utils/collection.ts"; | import { Collection } from '../utils/collection.ts' | ||||||
| import { GuildTextChannel } from "./textChannel.ts"; | import { GuildTextChannel } from './textChannel.ts' | ||||||
| import { Message } from "./message.ts"; | import { Message } from './message.ts' | ||||||
| import { Role } from "./role.ts"; | import { Role } from './role.ts' | ||||||
| import { User } from "./user.ts"; | import { User } from './user.ts' | ||||||
| 
 | 
 | ||||||
| export class MessageMentions { | export class MessageMentions { | ||||||
|   client: Client |   client: Client | ||||||
|  | @ -25,27 +25,35 @@ export class MessageMentions { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async fromPayload(payload: MessagePayload): Promise<MessageMentions> { |   async fromPayload(payload: MessagePayload): Promise<MessageMentions> { | ||||||
|     payload.mentions.forEach(rawUser => { |     if (this.message === undefined) return this | ||||||
|  |     if (payload.mentions !== undefined) | ||||||
|  |       payload.mentions.forEach((rawUser) => { | ||||||
|         this.users.set(rawUser.id, new User(this.client, rawUser)) |         this.users.set(rawUser.id, new User(this.client, rawUser)) | ||||||
|       }) |       }) | ||||||
| 
 | 
 | ||||||
|     if (this.message.guild !== undefined) { |     if (this.message.guild !== undefined) { | ||||||
|       for (const id of payload.mention_roles) { |       for (const id of payload.mention_roles) { | ||||||
|         const role = await this.message.guild.roles.get(id) |         const role = await this.message.guild.roles.get(id) | ||||||
|         if(role !== undefined) this.roles.set(role.id, role) |         if (role !== undefined) this.roles.set(role.id, role) | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     if (payload.mention_channels !== undefined) { |     if (payload.mention_channels !== undefined) { | ||||||
|       for (const mentionChannel of payload.mention_channels) { |       for (const mentionChannel of payload.mention_channels) { | ||||||
|         const channel = await this.client.channels.get<GuildTextChannel>(mentionChannel.id) |         const channel = await this.client.channels.get<GuildTextChannel>( | ||||||
|  |           mentionChannel.id | ||||||
|  |         ) | ||||||
|         if (channel !== undefined) this.channels.set(channel.id, channel) |         if (channel !== undefined) this.channels.set(channel.id, channel) | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     const matchChannels = this.message.content.match(MessageMentions.CHANNEL_MENTION) |     const matchChannels = this.message.content.match( | ||||||
|  |       MessageMentions.CHANNEL_MENTION | ||||||
|  |     ) | ||||||
|     if (matchChannels !== null) { |     if (matchChannels !== null) { | ||||||
|       for (const id of matchChannels) { |       for (const id of matchChannels) { | ||||||
|         const parsedID = id.substr(2, id.length - 3) |         const parsedID = id.substr(2, id.length - 3) | ||||||
|         const channel = await this.client.channels.get<GuildTextChannel>(parsedID) |         const channel = await this.client.channels.get<GuildTextChannel>( | ||||||
|  |           parsedID | ||||||
|  |         ) | ||||||
|         if (channel !== undefined) this.channels.set(channel.id, channel) |         if (channel !== undefined) this.channels.set(channel.id, channel) | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
							
								
								
									
										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}`) |   console.log(`Webhooks Updated in #${channel.name} from ${guild.name}`) | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
|  | client.on('commandError', console.error) | ||||||
| client.on('inviteCreate', (invite: Invite) => { | client.on('inviteCreate', (invite: Invite) => { | ||||||
|   console.log(`Invite Create: ${invite.code}`) |   console.log(`Invite Create: ${invite.code}`) | ||||||
| }) | }) | ||||||
|  | @ -131,6 +132,22 @@ client.on('voiceStateRemove', (state) => { | ||||||
|   console.log('VC Leave', 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}`))
 | // client.on('raw', (evt: string) => console.log(`EVENT: ${evt}`))
 | ||||||
| 
 | 
 | ||||||
| const files = Deno.readDirSync('./src/test/cmds') | 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/opcodes-and-status-codes#gateway
 | ||||||
| // https://discord.com/developers/docs/topics/gateway#commands-and-events-gateway-events
 | // https://discord.com/developers/docs/topics/gateway#commands-and-events-gateway-events
 | ||||||
| import { Guild } from "../structures/guild.ts" | import { Guild } from '../structures/guild.ts' | ||||||
| import { Member } from "../structures/member.ts" | import { Member } from '../structures/member.ts' | ||||||
| import { EmojiPayload } from './emoji.ts' | import { EmojiPayload } from './emoji.ts' | ||||||
| import { MemberPayload } from './guild.ts' | import { MemberPayload } from './guild.ts' | ||||||
| import { | import { | ||||||
|   ActivityGame, |   ActivityGame, | ||||||
|   ActivityPayload, |   ActivityPayload, | ||||||
|   StatusType, |   StatusType, | ||||||
|   ClientStatus |   ClientStatus, | ||||||
| } from './presence.ts' | } from './presence.ts' | ||||||
| import { RolePayload } from './role.ts' | import { RolePayload } from './role.ts' | ||||||
| import { UserPayload } from './user.ts' | import { UserPayload } from './user.ts' | ||||||
|  | @ -27,7 +27,7 @@ export enum GatewayOpcodes { // 문서를 확인해본 결과 Opcode 5번은 비 | ||||||
|   REQUEST_GUILD_MEMBERS = 8, |   REQUEST_GUILD_MEMBERS = 8, | ||||||
|   INVALID_SESSION = 9, |   INVALID_SESSION = 9, | ||||||
|   HELLO = 10, |   HELLO = 10, | ||||||
|   HEARTBEAT_ACK = 11 |   HEARTBEAT_ACK = 11, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  | @ -47,7 +47,7 @@ export enum GatewayCloseCodes { | ||||||
|   SHARDING_REQUIRED = 4011, |   SHARDING_REQUIRED = 4011, | ||||||
|   INVALID_API_VERSION = 4012, |   INVALID_API_VERSION = 4012, | ||||||
|   INVALID_INTENTS = 4013, |   INVALID_INTENTS = 4013, | ||||||
|   DISALLOWED_INTENTS = 4014 |   DISALLOWED_INTENTS = 4014, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export enum GatewayIntents { | export enum GatewayIntents { | ||||||
|  | @ -65,7 +65,7 @@ export enum GatewayIntents { | ||||||
|   GUILD_MESSAGE_TYPING = 1 << 11, |   GUILD_MESSAGE_TYPING = 1 << 11, | ||||||
|   DIRECT_MESSAGES = 1 << 12, |   DIRECT_MESSAGES = 1 << 12, | ||||||
|   DIRECT_MESSAGE_REACTIONS = 1 << 13, |   DIRECT_MESSAGE_REACTIONS = 1 << 13, | ||||||
|   DIRECT_MESSAGE_TYPING = 1 << 13 |   DIRECT_MESSAGE_TYPING = 1 << 13, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export enum GatewayEvents { | export enum GatewayEvents { | ||||||
|  | @ -105,7 +105,7 @@ export enum GatewayEvents { | ||||||
|   User_Update = 'USER_UPDATE', |   User_Update = 'USER_UPDATE', | ||||||
|   Voice_Server_Update = 'VOICE_SERVER_UPDATE', |   Voice_Server_Update = 'VOICE_SERVER_UPDATE', | ||||||
|   Voice_State_Update = 'VOICE_STATE_UPDATE', |   Voice_State_Update = 'VOICE_STATE_UPDATE', | ||||||
|   Webhooks_Update = 'WEBHOOKS_UPDATE' |   Webhooks_Update = 'WEBHOOKS_UPDATE', | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface IdentityPayload { | export interface IdentityPayload { | ||||||
|  | @ -290,6 +290,13 @@ export interface MessageReactionRemoveAllPayload { | ||||||
|   message_id: string |   message_id: string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | export interface MessageReactionRemoveEmojiPayload { | ||||||
|  |   channel_id: string | ||||||
|  |   message_id: string | ||||||
|  |   guild_id?: string | ||||||
|  |   emoji: EmojiPayload | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export interface PresenceUpdatePayload { | export interface PresenceUpdatePayload { | ||||||
|   user: UserPayload |   user: UserPayload | ||||||
|   guild_id: string |   guild_id: string | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue