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