From 5e5b4076ce7f7a4ede2ceb5d547489308284aca0 Mon Sep 17 00:00:00 2001 From: Helloyunho Date: Wed, 2 Dec 2020 21:29:52 +0900 Subject: [PATCH] format files and ready for v0.9.0 --- .github/workflows/deno.yml | 2 +- .github/workflows/lint.yml | 21 +- .prettierrc | 4 +- .vscode/settings.json | 22 +- README.md | 6 +- mod.ts | 140 +-- src/consts/urlsAndVersions.ts | 18 +- src/gateway/handlers/channelDelete.ts | 26 +- src/gateway/handlers/channelPinsUpdate.ts | 46 +- src/gateway/handlers/channelUpdate.ts | 44 +- src/gateway/handlers/guildBanAdd.ts | 38 +- src/gateway/handlers/guildBanRemove.ts | 36 +- src/gateway/handlers/guildDelete.ts | 44 +- src/gateway/handlers/guildEmojiUpdate.ts | 106 +-- .../handlers/guildIntegrationsUpdate.ts | 28 +- src/gateway/handlers/guildMemberUpdate.ts | 2 +- src/gateway/handlers/guildMembersChunk.ts | 74 +- src/gateway/handlers/guildRoleCreate.ts | 34 +- src/gateway/handlers/guildRoleDelete.ts | 36 +- src/gateway/handlers/guildRoleUpdate.ts | 46 +- src/gateway/handlers/guildUpdate.ts | 28 +- src/gateway/handlers/index.ts | 318 +++---- src/gateway/handlers/inviteCreate.ts | 6 +- src/gateway/handlers/inviteDelete.ts | 4 +- src/gateway/handlers/messageDelete.ts | 40 +- src/gateway/handlers/messageDeleteBulk.ts | 66 +- src/gateway/handlers/messageReactionAdd.ts | 102 +-- src/gateway/handlers/messageReactionRemove.ts | 72 +- .../handlers/messageReactionRemoveAll.ts | 50 +- .../handlers/messageReactionRemoveEmoji.ts | 56 +- src/gateway/handlers/presenceUpdate.ts | 32 +- src/gateway/handlers/reconnect.ts | 16 +- src/gateway/handlers/typingStart.ts | 78 +- src/gateway/handlers/userUpdate.ts | 34 +- src/gateway/handlers/voiceServerUpdate.ts | 28 +- src/gateway/handlers/voiceStateUpdate.ts | 100 +- src/gateway/handlers/webhooksUpdate.ts | 38 +- src/gateway/index.ts | 26 +- src/managers/base.ts | 18 +- src/managers/baseChild.ts | 4 +- src/managers/channels.ts | 20 +- src/managers/emojis.ts | 11 +- src/managers/gatewayCache.ts | 8 +- src/managers/guildChannels.ts | 10 +- src/managers/guildEmojis.ts | 29 +- src/managers/guildVoiceStates.ts | 96 +- src/managers/guilds.ts | 6 +- src/managers/memberRoles.ts | 162 ++-- src/managers/members.ts | 54 +- src/managers/messageReactions.ts | 88 +- src/managers/messages.ts | 160 ++-- src/managers/presences.ts | 78 +- src/managers/reactionUsers.ts | 26 +- src/managers/roles.ts | 8 +- src/managers/users.ts | 8 +- src/models/cacheAdapter.ts | 37 +- src/models/client.ts | 295 +++--- src/models/command.ts | 856 +++++++++--------- src/models/commandClient.ts | 664 +++++++------- src/models/extensions.ts | 27 +- src/models/rest.ts | 28 +- src/models/shard.ts | 2 +- src/models/voice.ts | 52 +- src/structures/application.ts | 48 +- src/structures/base.ts | 15 +- src/structures/channel.ts | 6 +- src/structures/dmChannel.ts | 4 +- src/structures/embed.ts | 32 +- src/structures/emoji.ts | 8 +- src/structures/groupChannel.ts | 4 +- src/structures/guild.ts | 754 +++++++-------- src/structures/guildCategoryChannel.ts | 9 +- src/structures/guildNewsChannel.ts | 4 +- src/structures/guildVoiceChannel.ts | 4 +- src/structures/invite.ts | 94 +- src/structures/member.ts | 346 +++---- src/structures/message.ts | 258 +++--- src/structures/messageMentions.ts | 126 +-- src/structures/messageReaction.ts | 56 +- src/structures/presence.ts | 6 +- src/structures/role.ts | 17 +- src/structures/snowflake.ts | 10 +- src/structures/textChannel.ts | 323 +++---- src/structures/user.ts | 156 ++-- src/structures/voiceState.ts | 110 +-- src/structures/webhook.ts | 388 ++++---- src/test/cmd.ts | 330 +++---- src/test/cmds/addemoji.ts | 17 +- src/test/cmds/mentions.ts | 32 +- src/test/cmds/ping.ts | 4 +- src/test/cmds/userinfo.ts | 35 +- src/test/hook.ts | 20 +- src/test/index.ts | 83 +- src/types/application.ts | 20 +- src/types/cdn.ts | 2 +- src/types/gateway.ts | 10 +- src/types/gatewayBot.ts | 2 +- src/types/guild.ts | 296 +++--- src/types/permissionFlags.ts | 4 +- src/types/presence.ts | 2 +- src/types/userFlags.ts | 2 +- src/types/voice.ts | 90 +- src/utils/bitfield.ts | 31 +- src/utils/collection.ts | 4 +- src/utils/delay.ts | 7 +- src/utils/getChannelByType.ts | 74 +- src/utils/index.ts | 4 +- src/utils/intents.ts | 119 +-- src/utils/mixedPromise.ts | 6 +- src/utils/permissions.ts | 22 +- src/utils/userFlags.ts | 12 +- tsconfig.json | 140 +-- 112 files changed, 4478 insertions(+), 4282 deletions(-) diff --git a/.github/workflows/deno.yml b/.github/workflows/deno.yml index 0e5c4d71..7f76e22e 100644 --- a/.github/workflows/deno.yml +++ b/.github/workflows/deno.yml @@ -20,7 +20,7 @@ jobs: strategy: matrix: - deno: ["v1.x", "nightly"] + deno: ['v1.x', 'nightly'] steps: - name: Setup repo diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 241be985..88db429e 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -5,23 +5,22 @@ name: Lint Test on: push: - branches: [ main ] + branches: [main] pull_request: - branches: [ main ] + branches: [main] jobs: build: - runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v2 + + - name: Setup Node.js + uses: actions/setup-node@v2.1.2 - - name: Setup Node.js - uses: actions/setup-node@v2.1.2 + - name: Setup ESLint + run: npm install - - name: Setup ESLint - run: npm install - - - name: Test ESLint - run: npx eslint src/ + - name: Test ESLint + run: npx eslint src/ diff --git a/.prettierrc b/.prettierrc index 6fed3d0f..ee9808fc 100644 --- a/.prettierrc +++ b/.prettierrc @@ -2,5 +2,7 @@ "tabWidth": 2, "useTabs": false, "semi": false, - "singleQuote": true + "singleQuote": true, + "trailingComma": "none", + "arrowParens": "always" } diff --git a/.vscode/settings.json b/.vscode/settings.json index 233ca92a..baca545c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,11 +1,11 @@ -{ - "deno.enable": true, - "deno.lint": false, - "deno.unstable": false, - "deepscan.enable": true, - "deno.import_intellisense_origins": { - "https://deno.land": true - }, - "editor.tabSize": 2, - "editor.formatOnSave": true -} \ No newline at end of file +{ + "deno.enable": true, + "deno.lint": false, + "deno.unstable": false, + "deepscan.enable": true, + "deno.import_intellisense_origins": { + "https://deno.land": true + }, + "editor.tabSize": 2, + "editor.formatOnSave": true +} diff --git a/README.md b/README.md index 1d4e620d..3e882805 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ Here is a small example of how to use harmony, import { Client, Message, - Intents, + Intents } from 'https://raw.githubusercontent.com/harmony-org/harmony/main/mod.ts' const client = new Client() @@ -78,11 +78,11 @@ import { Command, CommandContext, Message, - Intents, + Intents } from 'https://raw.githubusercontent.com/harmony-org/harmony/main/mod.ts' const client = new CommandClient({ - prefix: '!', + prefix: '!' }) // Listen for event when client is ready (Identified through gateway / Resumed) diff --git a/mod.ts b/mod.ts index e228e288..d3f91031 100644 --- a/mod.ts +++ b/mod.ts @@ -1,70 +1,70 @@ -export * from './src/gateway/index.ts' -export * from './src/models/client.ts' -export * from './src/models/rest.ts' -export * from './src/models/cacheAdapter.ts' -export * from './src/models/shard.ts' -export * from './src/models/command.ts' -export * from './src/models/extensions.ts' -export * from './src/models/commandClient.ts' -export * from './src/managers/base.ts' -export * from './src/managers/baseChild.ts' -export * from './src/managers/channels.ts' -export * from './src/managers/emojis.ts' -export * from './src/managers/gatewayCache.ts' -export * from './src/managers/guildChannels.ts' -export * from './src/managers/guilds.ts' -export * from './src/managers/guildChannels.ts' -export * from './src/managers/guildEmojis.ts' -export * from './src/managers/members.ts' -export * from './src/managers/messageReactions.ts' -export * from './src/managers/reactionUsers.ts' -export * from './src/managers/messages.ts' -export * from './src/managers/roles.ts' -export * from './src/managers/users.ts' -export * from './src/structures/application.ts' -export * from './src/structures/base.ts' -export * from './src/structures/cdn.ts' -export * from './src/structures/channel.ts' -export * from './src/structures/dmChannel.ts' -export * from './src/structures/embed.ts' -export * from './src/structures/emoji.ts' -export * from './src/structures/groupChannel.ts' -export * from './src/structures/guild.ts' -export * from './src/structures/guildCategoryChannel.ts' -export * from './src/structures/guildNewsChannel.ts' -export * from './src/structures/guildVoiceChannel.ts' -export * from './src/structures/invite.ts' -export * from './src/structures/member.ts' -export * from './src/structures/message.ts' -export * from './src/structures/messageMentions.ts' -export * from './src/structures/presence.ts' -export * from './src/structures/role.ts' -export * from './src/structures/snowflake.ts' -export * from './src/structures/textChannel.ts' -export * from './src/structures/messageReaction.ts' -export * from './src/structures/user.ts' -export * from './src/structures/webhook.ts' -export * from './src/types/application.ts' -export * from './src/types/cdn.ts' -export * from './src/types/channel.ts' -export * from './src/types/emoji.ts' -export * from './src/types/endpoint.ts' -export * from './src/types/gateway.ts' -export * from './src/types/gatewayBot.ts' -export * from './src/types/gatewayResponse.ts' -export * from './src/types/guild.ts' -export * from './src/types/invite.ts' -export * from './src/types/permissionFlags.ts' -export * from './src/types/presence.ts' -export * from './src/types/role.ts' -export * from './src/types/template.ts' -export * from './src/types/user.ts' -export * from './src/types/voice.ts' -export * from './src/types/webhook.ts' -export * from './src/utils/collection.ts' -export * from './src/utils/intents.ts' -export * from './src/utils/buildInfo.ts' -export * from './src/utils/permissions.ts' -export * from './src/utils/userFlags.ts' -export * from './src/utils/bitfield.ts' -export * from './src/utils/getChannelByType.ts' +export * from './src/gateway/index.ts' +export * from './src/models/client.ts' +export * from './src/models/rest.ts' +export * from './src/models/cacheAdapter.ts' +export * from './src/models/shard.ts' +export * from './src/models/command.ts' +export * from './src/models/extensions.ts' +export * from './src/models/commandClient.ts' +export * from './src/managers/base.ts' +export * from './src/managers/baseChild.ts' +export * from './src/managers/channels.ts' +export * from './src/managers/emojis.ts' +export * from './src/managers/gatewayCache.ts' +export * from './src/managers/guildChannels.ts' +export * from './src/managers/guilds.ts' +export * from './src/managers/guildChannels.ts' +export * from './src/managers/guildEmojis.ts' +export * from './src/managers/members.ts' +export * from './src/managers/messageReactions.ts' +export * from './src/managers/reactionUsers.ts' +export * from './src/managers/messages.ts' +export * from './src/managers/roles.ts' +export * from './src/managers/users.ts' +export * from './src/structures/application.ts' +export * from './src/structures/base.ts' +export * from './src/structures/cdn.ts' +export * from './src/structures/channel.ts' +export * from './src/structures/dmChannel.ts' +export * from './src/structures/embed.ts' +export * from './src/structures/emoji.ts' +export * from './src/structures/groupChannel.ts' +export * from './src/structures/guild.ts' +export * from './src/structures/guildCategoryChannel.ts' +export * from './src/structures/guildNewsChannel.ts' +export * from './src/structures/guildVoiceChannel.ts' +export * from './src/structures/invite.ts' +export * from './src/structures/member.ts' +export * from './src/structures/message.ts' +export * from './src/structures/messageMentions.ts' +export * from './src/structures/presence.ts' +export * from './src/structures/role.ts' +export * from './src/structures/snowflake.ts' +export * from './src/structures/textChannel.ts' +export * from './src/structures/messageReaction.ts' +export * from './src/structures/user.ts' +export * from './src/structures/webhook.ts' +export * from './src/types/application.ts' +export * from './src/types/cdn.ts' +export * from './src/types/channel.ts' +export * from './src/types/emoji.ts' +export * from './src/types/endpoint.ts' +export * from './src/types/gateway.ts' +export * from './src/types/gatewayBot.ts' +export * from './src/types/gatewayResponse.ts' +export * from './src/types/guild.ts' +export * from './src/types/invite.ts' +export * from './src/types/permissionFlags.ts' +export * from './src/types/presence.ts' +export * from './src/types/role.ts' +export * from './src/types/template.ts' +export * from './src/types/user.ts' +export * from './src/types/voice.ts' +export * from './src/types/webhook.ts' +export * from './src/utils/collection.ts' +export * from './src/utils/intents.ts' +export * from './src/utils/buildInfo.ts' +export * from './src/utils/permissions.ts' +export * from './src/utils/userFlags.ts' +export * from './src/utils/bitfield.ts' +export * from './src/utils/getChannelByType.ts' diff --git a/src/consts/urlsAndVersions.ts b/src/consts/urlsAndVersions.ts index e368d328..4ca5cea9 100644 --- a/src/consts/urlsAndVersions.ts +++ b/src/consts/urlsAndVersions.ts @@ -1,9 +1,9 @@ -export const DISCORD_API_URL: string = 'https://discord.com/api' - -export const DISCORD_GATEWAY_URL: string = 'wss://gateway.discord.gg' - -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_API_URL: string = 'https://discord.com/api' + +export const DISCORD_GATEWAY_URL: string = 'wss://gateway.discord.gg' + +export const DISCORD_CDN_URL: string = 'https://cdn.discordapp.com' + +export const DISCORD_API_VERSION: number = 8 + +export const DISCORD_VOICE_VERSION: number = 4 diff --git a/src/gateway/handlers/channelDelete.ts b/src/gateway/handlers/channelDelete.ts index f17beb86..37cd2b48 100644 --- a/src/gateway/handlers/channelDelete.ts +++ b/src/gateway/handlers/channelDelete.ts @@ -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) + } +} diff --git a/src/gateway/handlers/channelPinsUpdate.ts b/src/gateway/handlers/channelPinsUpdate.ts index 0394a084..14237871 100644 --- a/src/gateway/handlers/channelPinsUpdate.ts +++ b/src/gateway/handlers/channelPinsUpdate.ts @@ -1,23 +1,23 @@ -import { Gateway, GatewayEventHandler } from '../index.ts' -import { TextChannel } from '../../structures/textChannel.ts' -import { ChannelPinsUpdatePayload } from '../../types/gateway.ts' - -export const channelPinsUpdate: GatewayEventHandler = async ( - gateway: Gateway, - d: ChannelPinsUpdatePayload -) => { - const after: - | TextChannel - | undefined = await gateway.client.channels.get(d.channel_id) - if (after !== undefined) { - const before = after.refreshFromData({ - last_pin_timestamp: d.last_pin_timestamp, - }) - const raw = await gateway.client.channels._get(d.channel_id) - await gateway.client.channels.set( - after.id, - Object.assign(raw, { last_pin_timestamp: d.last_pin_timestamp }) - ) - gateway.client.emit('channelPinsUpdate', before, after) - } -} +import { Gateway, GatewayEventHandler } from '../index.ts' +import { TextChannel } from '../../structures/textChannel.ts' +import { ChannelPinsUpdatePayload } from '../../types/gateway.ts' + +export const channelPinsUpdate: GatewayEventHandler = async ( + gateway: Gateway, + d: ChannelPinsUpdatePayload +) => { + const after: + | TextChannel + | undefined = await gateway.client.channels.get(d.channel_id) + if (after !== undefined) { + const before = after.refreshFromData({ + last_pin_timestamp: d.last_pin_timestamp + }) + const raw = await gateway.client.channels._get(d.channel_id) + await gateway.client.channels.set( + after.id, + Object.assign(raw, { last_pin_timestamp: d.last_pin_timestamp }) + ) + gateway.client.emit('channelPinsUpdate', before, after) + } +} diff --git a/src/gateway/handlers/channelUpdate.ts b/src/gateway/handlers/channelUpdate.ts index 7c426c28..1c81aa6d 100644 --- a/src/gateway/handlers/channelUpdate.ts +++ b/src/gateway/handlers/channelUpdate.ts @@ -1,22 +1,22 @@ -import { Channel } from '../../structures/channel.ts' -import { ChannelPayload } from '../../types/channel.ts' -import { Gateway, GatewayEventHandler } from '../index.ts' - -export const channelUpdate: GatewayEventHandler = async ( - gateway: Gateway, - d: ChannelPayload -) => { - const oldChannel = await gateway.client.channels.get(d.id) - await gateway.client.channels.set(d.id, d) - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion - const newChannel = (await gateway.client.channels.get(d.id)) as Channel - - if (oldChannel !== undefined) { - // (DjDeveloperr): Already done by ChannelsManager. I'll recheck later - // if ('guild_id' in d) { - // // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion - // (newChannel as GuildChannel).guild = await gateway.client.guilds.get((d as GuildChannelPayload).guild_id) as Guild - // } - gateway.client.emit('channelUpdate', oldChannel, newChannel) - } else gateway.client.emit('channelUpdateUncached', newChannel) -} +import { Channel } from '../../structures/channel.ts' +import { ChannelPayload } from '../../types/channel.ts' +import { Gateway, GatewayEventHandler } from '../index.ts' + +export const channelUpdate: GatewayEventHandler = async ( + gateway: Gateway, + d: ChannelPayload +) => { + const oldChannel = await gateway.client.channels.get(d.id) + await gateway.client.channels.set(d.id, d) + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + const newChannel = (await gateway.client.channels.get(d.id)) as Channel + + if (oldChannel !== undefined) { + // (DjDeveloperr): Already done by ChannelsManager. I'll recheck later + // if ('guild_id' in d) { + // // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + // (newChannel as GuildChannel).guild = await gateway.client.guilds.get((d as GuildChannelPayload).guild_id) as Guild + // } + gateway.client.emit('channelUpdate', oldChannel, newChannel) + } else gateway.client.emit('channelUpdateUncached', newChannel) +} diff --git a/src/gateway/handlers/guildBanAdd.ts b/src/gateway/handlers/guildBanAdd.ts index 17901e9a..ddc810a4 100644 --- a/src/gateway/handlers/guildBanAdd.ts +++ b/src/gateway/handlers/guildBanAdd.ts @@ -1,19 +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) + } +} diff --git a/src/gateway/handlers/guildBanRemove.ts b/src/gateway/handlers/guildBanRemove.ts index 1b824fd9..00bbdfec 100644 --- a/src/gateway/handlers/guildBanRemove.ts +++ b/src/gateway/handlers/guildBanRemove.ts @@ -1,18 +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) + } +} diff --git a/src/gateway/handlers/guildDelete.ts b/src/gateway/handlers/guildDelete.ts index 11048402..286ffc73 100644 --- a/src/gateway/handlers/guildDelete.ts +++ b/src/gateway/handlers/guildDelete.ts @@ -1,22 +1,22 @@ -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 guild.presences.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 guild.presences.flush() + await gateway.client.guilds.delete(d.id) + + gateway.client.emit('guildDelete', guild) + } +} diff --git a/src/gateway/handlers/guildEmojiUpdate.ts b/src/gateway/handlers/guildEmojiUpdate.ts index 1e9eba01..5af394f7 100644 --- a/src/gateway/handlers/guildEmojiUpdate.ts +++ b/src/gateway/handlers/guildEmojiUpdate.ts @@ -1,53 +1,53 @@ -import { Emoji } from '../../structures/emoji.ts' -import { Guild } from '../../structures/guild.ts' -import { EmojiPayload } from '../../types/emoji.ts' -import { GuildEmojiUpdatePayload } from '../../types/gateway.ts' -import { Gateway, GatewayEventHandler } from '../index.ts' - -export const guildEmojiUpdate: GatewayEventHandler = async ( - gateway: Gateway, - d: GuildEmojiUpdatePayload -) => { - const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) - if (guild !== undefined) { - const emojis = await guild.emojis.collection() - const deleted: Emoji[] = [] - const added: 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 - added.push(emoji) - } else _updated.push(raw) - } - - for (const emoji of emojis.values()) { - 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 - await guild.emojis.set(find.id, find) - const after = (await guild.emojis.get(find.id)) as Emoji - updated.push({ before, after }) - } - } - - for (const emoji of deleted) { - gateway.client.emit('guildEmojiDelete', guild, emoji) - } - - for (const emoji of added) { - gateway.client.emit('guildEmojiAdd', guild, emoji) - } - - for (const emoji of updated) { - gateway.client.emit('guildEmojiUpdate', guild, emoji.before, emoji.after) - } - } -} +import { Emoji } from '../../structures/emoji.ts' +import { Guild } from '../../structures/guild.ts' +import { EmojiPayload } from '../../types/emoji.ts' +import { GuildEmojiUpdatePayload } from '../../types/gateway.ts' +import { Gateway, GatewayEventHandler } from '../index.ts' + +export const guildEmojiUpdate: GatewayEventHandler = async ( + gateway: Gateway, + d: GuildEmojiUpdatePayload +) => { + const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) + if (guild !== undefined) { + const emojis = await guild.emojis.collection() + const deleted: Emoji[] = [] + const added: 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 + added.push(emoji) + } else _updated.push(raw) + } + + for (const emoji of emojis.values()) { + 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 + await guild.emojis.set(find.id, find) + const after = (await guild.emojis.get(find.id)) as Emoji + updated.push({ before, after }) + } + } + + for (const emoji of deleted) { + gateway.client.emit('guildEmojiDelete', guild, emoji) + } + + for (const emoji of added) { + gateway.client.emit('guildEmojiAdd', guild, emoji) + } + + for (const emoji of updated) { + gateway.client.emit('guildEmojiUpdate', guild, emoji.before, emoji.after) + } + } +} diff --git a/src/gateway/handlers/guildIntegrationsUpdate.ts b/src/gateway/handlers/guildIntegrationsUpdate.ts index 13b7e37b..0cc31ee4 100644 --- a/src/gateway/handlers/guildIntegrationsUpdate.ts +++ b/src/gateway/handlers/guildIntegrationsUpdate.ts @@ -1,14 +1,14 @@ -import { Gateway, GatewayEventHandler } from '../index.ts' -import { Guild } from '../../structures/guild.ts' -import { GuildIntegrationsUpdatePayload } from '../../types/gateway.ts' - -export const guildIntegrationsUpdate: GatewayEventHandler = async ( - gateway: Gateway, - d: GuildIntegrationsUpdatePayload -) => { - console.log(d) - const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) - if (guild === undefined) return - - gateway.client.emit('guildIntegrationsUpdate', guild) -} +import { Gateway, GatewayEventHandler } from '../index.ts' +import { Guild } from '../../structures/guild.ts' +import { GuildIntegrationsUpdatePayload } from '../../types/gateway.ts' + +export const guildIntegrationsUpdate: GatewayEventHandler = async ( + gateway: Gateway, + d: GuildIntegrationsUpdatePayload +) => { + console.log(d) + const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) + if (guild === undefined) return + + gateway.client.emit('guildIntegrationsUpdate', guild) +} diff --git a/src/gateway/handlers/guildMemberUpdate.ts b/src/gateway/handlers/guildMemberUpdate.ts index 29843acb..6267c0c5 100644 --- a/src/gateway/handlers/guildMemberUpdate.ts +++ b/src/gateway/handlers/guildMemberUpdate.ts @@ -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) diff --git a/src/gateway/handlers/guildMembersChunk.ts b/src/gateway/handlers/guildMembersChunk.ts index 3a7e9888..f67fa30a 100644 --- a/src/gateway/handlers/guildMembersChunk.ts +++ b/src/gateway/handlers/guildMembersChunk.ts @@ -1,37 +1,37 @@ -import { Gateway, GatewayEventHandler } from '../index.ts' -import { Guild } from '../../structures/guild.ts' -import { GuildMemberChunkPayload } from '../../types/gateway.ts' - -export const guildMembersChunk: GatewayEventHandler = async ( - gateway: Gateway, - d: GuildMemberChunkPayload -) => { - const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) - // Weird case, shouldn't happen - if (guild === undefined) return - - for (const member of d.members) { - await guild.members.set(member.user.id, member) - } - - if (d.chunk_index === 0) await guild.presences.flush() - - if (d.presences !== undefined) { - for (const pres of d.presences) { - await guild.presences.set(pres.user.id, pres) - } - } - - gateway.client.emit('guildMembersChunk', guild, { - members: d.members.map((m) => m.user.id), - presences: - d.presences === undefined ? undefined : d.presences.map((p) => p.user.id), - chunkIndex: d.chunk_index, - chunkCount: d.chunk_count, - }) - - // Guild is now completely chunked. Emit an event for that. - if (d.chunk_index >= d.chunk_count - 1) { - gateway.client.emit('guildMembersChunked', guild, d.chunk_count) - } -} +import { Gateway, GatewayEventHandler } from '../index.ts' +import { Guild } from '../../structures/guild.ts' +import { GuildMemberChunkPayload } from '../../types/gateway.ts' + +export const guildMembersChunk: GatewayEventHandler = async ( + gateway: Gateway, + d: GuildMemberChunkPayload +) => { + const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) + // Weird case, shouldn't happen + if (guild === undefined) return + + for (const member of d.members) { + await guild.members.set(member.user.id, member) + } + + if (d.chunk_index === 0) await guild.presences.flush() + + if (d.presences !== undefined) { + for (const pres of d.presences) { + await guild.presences.set(pres.user.id, pres) + } + } + + gateway.client.emit('guildMembersChunk', guild, { + members: d.members.map((m) => m.user.id), + presences: + d.presences === undefined ? undefined : d.presences.map((p) => p.user.id), + chunkIndex: d.chunk_index, + chunkCount: d.chunk_count + }) + + // Guild is now completely chunked. Emit an event for that. + if (d.chunk_index >= d.chunk_count - 1) { + gateway.client.emit('guildMembersChunked', guild, d.chunk_count) + } +} diff --git a/src/gateway/handlers/guildRoleCreate.ts b/src/gateway/handlers/guildRoleCreate.ts index 4ce88a54..7200ca3b 100644 --- a/src/gateway/handlers/guildRoleCreate.ts +++ b/src/gateway/handlers/guildRoleCreate.ts @@ -1,17 +1,17 @@ -import { Gateway, GatewayEventHandler } from '../index.ts' -import { Guild } from '../../structures/guild.ts' -import { GuildRoleCreatePayload } from '../../types/gateway.ts' -import { Role } from '../../structures/role.ts' - -export const guildRoleCreate: GatewayEventHandler = async ( - gateway: Gateway, - d: GuildRoleCreatePayload -) => { - const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) - // Weird case, shouldn't happen - if (guild === undefined) return - - await guild.roles.set(d.role.id, d.role) - const role = (await guild.roles.get(d.role.id)) as Role - gateway.client.emit('guildRoleCreate', role) -} +import { Gateway, GatewayEventHandler } from '../index.ts' +import { Guild } from '../../structures/guild.ts' +import { GuildRoleCreatePayload } from '../../types/gateway.ts' +import { Role } from '../../structures/role.ts' + +export const guildRoleCreate: GatewayEventHandler = async ( + gateway: Gateway, + d: GuildRoleCreatePayload +) => { + const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) + // Weird case, shouldn't happen + if (guild === undefined) return + + await guild.roles.set(d.role.id, d.role) + const role = (await guild.roles.get(d.role.id)) as Role + gateway.client.emit('guildRoleCreate', role) +} diff --git a/src/gateway/handlers/guildRoleDelete.ts b/src/gateway/handlers/guildRoleDelete.ts index 711833d1..b1e63da2 100644 --- a/src/gateway/handlers/guildRoleDelete.ts +++ b/src/gateway/handlers/guildRoleDelete.ts @@ -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) +} diff --git a/src/gateway/handlers/guildRoleUpdate.ts b/src/gateway/handlers/guildRoleUpdate.ts index d2105b9f..e5702105 100644 --- a/src/gateway/handlers/guildRoleUpdate.ts +++ b/src/gateway/handlers/guildRoleUpdate.ts @@ -1,23 +1,23 @@ -import { Gateway, GatewayEventHandler } from '../index.ts' -import { Guild } from '../../structures/guild.ts' -import { GuildRoleUpdatePayload } from '../../types/gateway.ts' -import { Role } from '../../structures/role.ts' - -export const guildRoleUpdate: GatewayEventHandler = async ( - gateway: Gateway, - d: GuildRoleUpdatePayload -) => { - 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) - await guild.roles.set(d.role.id, d.role) - const newRole = (await guild.roles.get(d.role.id)) as Role - - // Shouldn't happen either - if (role === undefined) - return gateway.client.emit('guildRoleUpdateUncached', newRole) - - gateway.client.emit('guildRoleUpdate', role, newRole) -} +import { Gateway, GatewayEventHandler } from '../index.ts' +import { Guild } from '../../structures/guild.ts' +import { GuildRoleUpdatePayload } from '../../types/gateway.ts' +import { Role } from '../../structures/role.ts' + +export const guildRoleUpdate: GatewayEventHandler = async ( + gateway: Gateway, + d: GuildRoleUpdatePayload +) => { + 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) + await guild.roles.set(d.role.id, d.role) + const newRole = (await guild.roles.get(d.role.id)) as Role + + // Shouldn't happen either + if (role === undefined) + return gateway.client.emit('guildRoleUpdateUncached', newRole) + + gateway.client.emit('guildRoleUpdate', role, newRole) +} diff --git a/src/gateway/handlers/guildUpdate.ts b/src/gateway/handlers/guildUpdate.ts index 3bb23917..c7e7cc49 100644 --- a/src/gateway/handlers/guildUpdate.ts +++ b/src/gateway/handlers/guildUpdate.ts @@ -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) +} diff --git a/src/gateway/handlers/index.ts b/src/gateway/handlers/index.ts index 7cc08798..01282ef7 100644 --- a/src/gateway/handlers/index.ts +++ b/src/gateway/handlers/index.ts @@ -1,156 +1,162 @@ -import { GatewayEventHandler } from '../index.ts' -import { GatewayEvents, TypingStartGuildData } from '../../types/gateway.ts' -import { channelCreate } from './channelCreate.ts' -import { channelDelete } from './channelDelete.ts' -import { channelUpdate } from './channelUpdate.ts' -import { channelPinsUpdate } from './channelPinsUpdate.ts' -import { guildCreate } from './guildCreate.ts' -import { guildDelte as guildDelete } from './guildDelete.ts' -import { guildUpdate } from './guildUpdate.ts' -import { guildBanAdd } from './guildBanAdd.ts' -import { ready } from './ready.ts' -import { guildBanRemove } from './guildBanRemove.ts' -import { messageCreate } from './messageCreate.ts' -import { resume } from './resume.ts' -import { reconnect } from './reconnect.ts' -import { messageDelete } from './messageDelete.ts' -import { messageUpdate } from './messageUpdate.ts' -import { guildEmojiUpdate } from './guildEmojiUpdate.ts' -import { guildMemberAdd } from './guildMemberAdd.ts' -import { guildMemberRemove } from './guildMemberRemove.ts' -import { guildMemberUpdate } from './guildMemberUpdate.ts' -import { guildRoleCreate } from './guildRoleCreate.ts' -import { guildRoleDelete } from './guildRoleDelete.ts' -import { guildRoleUpdate } from './guildRoleUpdate.ts' -import { guildIntegrationsUpdate } from './guildIntegrationsUpdate.ts' -import { webhooksUpdate } from './webhooksUpdate.ts' -import { messageDeleteBulk } from './messageDeleteBulk.ts' -import { userUpdate } from './userUpdate.ts' -import { typingStart } from './typingStart.ts' -import { Channel } from '../../structures/channel.ts' -import { GuildTextChannel, TextChannel } from '../../structures/textChannel.ts' -import { Guild } from '../../structures/guild.ts' -import { User } from '../../structures/user.ts' -import { Emoji } from '../../structures/emoji.ts' -import { Member } from '../../structures/member.ts' -import { Role } from '../../structures/role.ts' -import { Message } from '../../structures/message.ts' -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' -import { MessageReaction } from '../../structures/messageReaction.ts' -import { Invite } from '../../structures/invite.ts' -import { Presence } from '../../structures/presence.ts' - -export const gatewayHandlers: { - [eventCode in GatewayEvents]: GatewayEventHandler | undefined -} = { - READY: ready, - RECONNECT: reconnect, - RESUMED: resume, - CHANNEL_CREATE: channelCreate, - CHANNEL_DELETE: channelDelete, - CHANNEL_UPDATE: channelUpdate, - CHANNEL_PINS_UPDATE: channelPinsUpdate, - GUILD_CREATE: guildCreate, - GUILD_DELETE: guildDelete, - GUILD_UPDATE: guildUpdate, - GUILD_BAN_ADD: guildBanAdd, - GUILD_BAN_REMOVE: guildBanRemove, - GUILD_EMOJIS_UPDATE: guildEmojiUpdate, - GUILD_INTEGRATIONS_UPDATE: guildIntegrationsUpdate, - GUILD_MEMBER_ADD: guildMemberAdd, - GUILD_MEMBER_REMOVE: guildMemberRemove, - GUILD_MEMBER_UPDATE: guildMemberUpdate, - GUILD_MEMBERS_CHUNK: guildMembersChunk, - GUILD_ROLE_CREATE: guildRoleCreate, - GUILD_ROLE_UPDATE: guildRoleUpdate, - GUILD_ROLE_DELETE: guildRoleDelete, - INVITE_CREATE: inviteCreate, - INVITE_DELETE: inviteDelete, - MESSAGE_CREATE: messageCreate, - MESSAGE_UPDATE: messageUpdate, - MESSAGE_DELETE: messageDelete, - MESSAGE_DELETE_BULK: messageDeleteBulk, - 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, -} - -export interface EventTypes { - [name: string]: (...args: any[]) => void -} - -export interface VoiceServerUpdateData { - token: string - endpoint: string - guild: Guild -} - -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, - uncached: Set - ) => void - messageUpdate: (before: Message, after: Message) => void - messageReactionAdd: (reaction: MessageReaction, user: User) => void - messageReactionRemove: (reaction: MessageReaction, user: User) => void - messageReactionRemoveAll: (message: Message) => void - messageReactionRemoveEmoji: (message: Message, emoji: Emoji) => void - typingStart: ( - user: User, - channel: TextChannel, - at: Date, - guildData?: TypingStartGuildData - ) => void - inviteCreate: (invite: Invite) => void - inviteDelete: (invite: Invite) => 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 - presenceUpdate: (presence: Presence) => void - webhooksUpdate: (guild: Guild, channel: GuildTextChannel) => void -} +import { GatewayEventHandler } from '../index.ts' +import { GatewayEvents, TypingStartGuildData } from '../../types/gateway.ts' +import { channelCreate } from './channelCreate.ts' +import { channelDelete } from './channelDelete.ts' +import { channelUpdate } from './channelUpdate.ts' +import { channelPinsUpdate } from './channelPinsUpdate.ts' +import { guildCreate } from './guildCreate.ts' +import { guildDelte as guildDelete } from './guildDelete.ts' +import { guildUpdate } from './guildUpdate.ts' +import { guildBanAdd } from './guildBanAdd.ts' +import { ready } from './ready.ts' +import { guildBanRemove } from './guildBanRemove.ts' +import { messageCreate } from './messageCreate.ts' +import { resume } from './resume.ts' +import { reconnect } from './reconnect.ts' +import { messageDelete } from './messageDelete.ts' +import { messageUpdate } from './messageUpdate.ts' +import { guildEmojiUpdate } from './guildEmojiUpdate.ts' +import { guildMemberAdd } from './guildMemberAdd.ts' +import { guildMemberRemove } from './guildMemberRemove.ts' +import { guildMemberUpdate } from './guildMemberUpdate.ts' +import { guildRoleCreate } from './guildRoleCreate.ts' +import { guildRoleDelete } from './guildRoleDelete.ts' +import { guildRoleUpdate } from './guildRoleUpdate.ts' +import { guildIntegrationsUpdate } from './guildIntegrationsUpdate.ts' +import { webhooksUpdate } from './webhooksUpdate.ts' +import { messageDeleteBulk } from './messageDeleteBulk.ts' +import { userUpdate } from './userUpdate.ts' +import { typingStart } from './typingStart.ts' +import { GuildTextChannel } from '../../structures/textChannel.ts' +import { Guild } from '../../structures/guild.ts' +import { User } from '../../structures/user.ts' +import { Emoji } from '../../structures/emoji.ts' +import { Member } from '../../structures/member.ts' +import { Role } from '../../structures/role.ts' +import { Message } from '../../structures/message.ts' +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' +import { MessageReaction } from '../../structures/messageReaction.ts' +import { Invite } from '../../structures/invite.ts' +import { Presence } from '../../structures/presence.ts' +import { + EveryChannelTypes, + EveryTextChannelTypes +} from '../../utils/getChannelByType.ts' + +export const gatewayHandlers: { + [eventCode in GatewayEvents]: GatewayEventHandler | undefined +} = { + READY: ready, + RECONNECT: reconnect, + RESUMED: resume, + CHANNEL_CREATE: channelCreate, + CHANNEL_DELETE: channelDelete, + CHANNEL_UPDATE: channelUpdate, + CHANNEL_PINS_UPDATE: channelPinsUpdate, + GUILD_CREATE: guildCreate, + GUILD_DELETE: guildDelete, + GUILD_UPDATE: guildUpdate, + GUILD_BAN_ADD: guildBanAdd, + GUILD_BAN_REMOVE: guildBanRemove, + GUILD_EMOJIS_UPDATE: guildEmojiUpdate, + GUILD_INTEGRATIONS_UPDATE: guildIntegrationsUpdate, + GUILD_MEMBER_ADD: guildMemberAdd, + GUILD_MEMBER_REMOVE: guildMemberRemove, + GUILD_MEMBER_UPDATE: guildMemberUpdate, + GUILD_MEMBERS_CHUNK: guildMembersChunk, + GUILD_ROLE_CREATE: guildRoleCreate, + GUILD_ROLE_UPDATE: guildRoleUpdate, + GUILD_ROLE_DELETE: guildRoleDelete, + INVITE_CREATE: inviteCreate, + INVITE_DELETE: inviteDelete, + MESSAGE_CREATE: messageCreate, + MESSAGE_UPDATE: messageUpdate, + MESSAGE_DELETE: messageDelete, + MESSAGE_DELETE_BULK: messageDeleteBulk, + 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 +} + +export interface EventTypes { + [name: string]: (...args: any[]) => void +} + +export interface VoiceServerUpdateData { + token: string + endpoint: string + guild: Guild +} + +export interface ClientEvents extends EventTypes { + ready: () => void + reconnect: () => void + resumed: () => void + channelCreate: (channel: EveryChannelTypes) => void + channelDelete: (channel: EveryChannelTypes) => void + channelPinsUpdate: ( + before: EveryTextChannelTypes, + after: EveryTextChannelTypes + ) => void + channelUpdate: (before: EveryChannelTypes, after: EveryChannelTypes) => 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, + uncached: Set + ) => void + messageUpdate: (before: Message, after: Message) => void + messageReactionAdd: (reaction: MessageReaction, user: User) => void + messageReactionRemove: (reaction: MessageReaction, user: User) => void + messageReactionRemoveAll: (message: Message) => void + messageReactionRemoveEmoji: (message: Message, emoji: Emoji) => void + typingStart: ( + user: User, + channel: EveryChannelTypes, + at: Date, + guildData?: TypingStartGuildData + ) => void + inviteCreate: (invite: Invite) => void + inviteDelete: (invite: Invite) => 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 + presenceUpdate: (presence: Presence) => void + webhooksUpdate: (guild: Guild, channel: GuildTextChannel) => void +} diff --git a/src/gateway/handlers/inviteCreate.ts b/src/gateway/handlers/inviteCreate.ts index b1b745a6..2414181f 100644 --- a/src/gateway/handlers/inviteCreate.ts +++ b/src/gateway/handlers/inviteCreate.ts @@ -1,7 +1,9 @@ import { Gateway, GatewayEventHandler } from '../index.ts' import { Guild } from '../../structures/guild.ts' import { InviteCreatePayload } from '../../types/gateway.ts' -import { ChannelPayload, GuildPayload, InvitePayload } from '../../../mod.ts' +import { ChannelPayload } from '../../types/channel.ts' +import { GuildPayload } from '../../types/guild.ts' +import { InvitePayload } from '../../types/invite.ts' import { Invite } from '../../structures/invite.ts' export const inviteCreate: GatewayEventHandler = async ( @@ -32,7 +34,7 @@ export const inviteCreate: GatewayEventHandler = async ( channel: (cachedChannel as unknown) as ChannelPayload, inviter: d.inviter, target_user: d.target_user, - target_user_type: d.target_user_type, + target_user_type: d.target_user_type } await guild.invites.set(d.code, dataConverted) diff --git a/src/gateway/handlers/inviteDelete.ts b/src/gateway/handlers/inviteDelete.ts index 8e77d134..b05c18c8 100644 --- a/src/gateway/handlers/inviteDelete.ts +++ b/src/gateway/handlers/inviteDelete.ts @@ -2,7 +2,7 @@ import { Gateway, GatewayEventHandler } from '../index.ts' import { Guild } from '../../structures/guild.ts' import { InviteDeletePayload } from '../../types/gateway.ts' import { PartialInvitePayload } from '../../types/invite.ts' -import { Channel } from '../../../mod.ts' +import { Channel } from '../../structures/channel.ts' export const inviteDelete: GatewayEventHandler = async ( gateway: Gateway, @@ -24,7 +24,7 @@ export const inviteDelete: GatewayEventHandler = async ( const uncachedInvite: PartialInvitePayload = { guild: (cachedGuild as unknown) as Guild, channel: (cachedChannel as unknown) as Channel, - code: d.code, + code: d.code } return gateway.client.emit('inviteDeleteUncached', uncachedInvite) } else { diff --git a/src/gateway/handlers/messageDelete.ts b/src/gateway/handlers/messageDelete.ts index 74fcf661..efccc701 100644 --- a/src/gateway/handlers/messageDelete.ts +++ b/src/gateway/handlers/messageDelete.ts @@ -1,20 +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(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(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) +} diff --git a/src/gateway/handlers/messageDeleteBulk.ts b/src/gateway/handlers/messageDeleteBulk.ts index a98fdfc9..d9149119 100644 --- a/src/gateway/handlers/messageDeleteBulk.ts +++ b/src/gateway/handlers/messageDeleteBulk.ts @@ -1,33 +1,33 @@ -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 { Gateway, GatewayEventHandler } from '../index.ts' - -export const messageDeleteBulk: GatewayEventHandler = async ( - gateway: Gateway, - d: MessageDeleteBulkPayload -) => { - let channel = await gateway.client.channels.get( - 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 - - const messages = new Collection() - const uncached = new Set() - for (const id of d.ids) { - const message = await channel.messages.get(id) - if (message === undefined) uncached.add(id) - else { - messages.set(id, message) - await channel.messages.delete(id) - } - } - - gateway.client.emit('messageDeleteBulk', channel, messages, uncached) -} +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 { Gateway, GatewayEventHandler } from '../index.ts' + +export const messageDeleteBulk: GatewayEventHandler = async ( + gateway: Gateway, + d: MessageDeleteBulkPayload +) => { + let channel = await gateway.client.channels.get( + 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 + + const messages = new Collection() + const uncached = new Set() + for (const id of d.ids) { + const message = await channel.messages.get(id) + if (message === undefined) uncached.add(id) + else { + messages.set(id, message) + await channel.messages.delete(id) + } + } + + gateway.client.emit('messageDeleteBulk', channel, messages, uncached) +} diff --git a/src/gateway/handlers/messageReactionAdd.ts b/src/gateway/handlers/messageReactionAdd.ts index f465a84b..17dbaf7a 100644 --- a/src/gateway/handlers/messageReactionAdd.ts +++ b/src/gateway/handlers/messageReactionAdd.ts @@ -1,51 +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(d.channel_id) - if (channel === undefined) - channel = await gateway.client.channels.fetch(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) -} +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(d.channel_id) + if (channel === undefined) + channel = await gateway.client.channels.fetch(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) +} diff --git a/src/gateway/handlers/messageReactionRemove.ts b/src/gateway/handlers/messageReactionRemove.ts index c809cc50..56748da5 100644 --- a/src/gateway/handlers/messageReactionRemove.ts +++ b/src/gateway/handlers/messageReactionRemove.ts @@ -1,36 +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(d.channel_id) - if (channel === undefined) - channel = await gateway.client.channels.fetch(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) -} +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(d.channel_id) + if (channel === undefined) + channel = await gateway.client.channels.fetch(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) +} diff --git a/src/gateway/handlers/messageReactionRemoveAll.ts b/src/gateway/handlers/messageReactionRemoveAll.ts index 415b2d92..bfcfd649 100644 --- a/src/gateway/handlers/messageReactionRemoveAll.ts +++ b/src/gateway/handlers/messageReactionRemoveAll.ts @@ -1,25 +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(d.channel_id) - if (channel === undefined) - channel = await gateway.client.channels.fetch(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) -} +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(d.channel_id) + if (channel === undefined) + channel = await gateway.client.channels.fetch(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) +} diff --git a/src/gateway/handlers/messageReactionRemoveEmoji.ts b/src/gateway/handlers/messageReactionRemoveEmoji.ts index b700d559..e62c172b 100644 --- a/src/gateway/handlers/messageReactionRemoveEmoji.ts +++ b/src/gateway/handlers/messageReactionRemoveEmoji.ts @@ -1,28 +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(d.channel_id) - if (channel === undefined) - channel = await gateway.client.channels.fetch(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) -} +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(d.channel_id) + if (channel === undefined) + channel = await gateway.client.channels.fetch(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) +} diff --git a/src/gateway/handlers/presenceUpdate.ts b/src/gateway/handlers/presenceUpdate.ts index 58dbe842..8f03fb72 100644 --- a/src/gateway/handlers/presenceUpdate.ts +++ b/src/gateway/handlers/presenceUpdate.ts @@ -1,16 +1,16 @@ -import { PresenceUpdatePayload } from '../../types/gateway.ts' -import { Gateway, GatewayEventHandler } from '../index.ts' - -export const presenceUpdate: GatewayEventHandler = async ( - gateway: Gateway, - d: PresenceUpdatePayload -) => { - const guild = await gateway.client.guilds.get(d.guild_id) - if (guild === undefined) return - - await guild.presences.set(d.user.id, d) - const presence = await guild.presences.get(d.user.id) - if (presence === undefined) return - - gateway.client.emit('presenceUpdate', presence) -} +import { PresenceUpdatePayload } from '../../types/gateway.ts' +import { Gateway, GatewayEventHandler } from '../index.ts' + +export const presenceUpdate: GatewayEventHandler = async ( + gateway: Gateway, + d: PresenceUpdatePayload +) => { + const guild = await gateway.client.guilds.get(d.guild_id) + if (guild === undefined) return + + await guild.presences.set(d.user.id, d) + const presence = await guild.presences.get(d.user.id) + if (presence === undefined) return + + gateway.client.emit('presenceUpdate', presence) +} diff --git a/src/gateway/handlers/reconnect.ts b/src/gateway/handlers/reconnect.ts index 75f7b48a..747273da 100644 --- a/src/gateway/handlers/reconnect.ts +++ b/src/gateway/handlers/reconnect.ts @@ -1,8 +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() +} diff --git a/src/gateway/handlers/typingStart.ts b/src/gateway/handlers/typingStart.ts index 9afcc799..5118b196 100644 --- a/src/gateway/handlers/typingStart.ts +++ b/src/gateway/handlers/typingStart.ts @@ -1,39 +1,39 @@ -import { Member } from '../../structures/member.ts' -import { TextChannel } from '../../structures/textChannel.ts' -import { TypingStartPayload } from '../../types/gateway.ts' -import { Gateway, GatewayEventHandler } from '../index.ts' - -// TODO: Do we need to add uncached events here? -export const typingStart: GatewayEventHandler = async ( - gateway: Gateway, - d: TypingStartPayload -) => { - const user = await gateway.client.users.get(d.user_id) - if (user === undefined) return console.log('user not cached') - - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion - const channel = (await gateway.client.channels.get( - d.channel_id - )) as TextChannel - if (channel === undefined) return console.log(`channel not cached`) - - const guild = - d.guild_id !== undefined - ? await gateway.client.guilds.get(d.guild_id) - : undefined - if (guild === undefined && d.guild_id !== undefined) - return console.log('guild not cached') - - const member = - d.member !== undefined && guild !== undefined - ? new Member(gateway.client, d.member, user, guild) - : undefined - - gateway.client.emit( - 'typingStart', - user, - channel, - new Date(d.timestamp), - guild !== undefined && member !== undefined ? { guild, member } : undefined - ) -} +import { Member } from '../../structures/member.ts' +import { TextChannel } from '../../structures/textChannel.ts' +import { TypingStartPayload } from '../../types/gateway.ts' +import { Gateway, GatewayEventHandler } from '../index.ts' + +// TODO: Do we need to add uncached events here? +export const typingStart: GatewayEventHandler = async ( + gateway: Gateway, + d: TypingStartPayload +) => { + const user = await gateway.client.users.get(d.user_id) + if (user === undefined) return console.log('user not cached') + + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + const channel = (await gateway.client.channels.get( + d.channel_id + )) as TextChannel + if (channel === undefined) return console.log(`channel not cached`) + + const guild = + d.guild_id !== undefined + ? await gateway.client.guilds.get(d.guild_id) + : undefined + if (guild === undefined && d.guild_id !== undefined) + return console.log('guild not cached') + + const member = + d.member !== undefined && guild !== undefined + ? new Member(gateway.client, d.member, user, guild) + : undefined + + gateway.client.emit( + 'typingStart', + user, + channel, + new Date(d.timestamp), + guild !== undefined && member !== undefined ? { guild, member } : undefined + ) +} diff --git a/src/gateway/handlers/userUpdate.ts b/src/gateway/handlers/userUpdate.ts index 48a83ce2..8004c63b 100644 --- a/src/gateway/handlers/userUpdate.ts +++ b/src/gateway/handlers/userUpdate.ts @@ -1,17 +1,17 @@ -import { User } from '../../structures/user.ts' -import { UserPayload } from '../../types/user.ts' -import { Gateway, GatewayEventHandler } from '../index.ts' - -export const userUpdate: GatewayEventHandler = async ( - gateway: Gateway, - d: UserPayload -) => { - const oldUser: User | undefined = await gateway.client.users.get(d.id) - await gateway.client.users.set(d.id, d) - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion - const newUser = (await gateway.client.users.get(d.id)) as User - - if (oldUser !== undefined) { - gateway.client.emit('userUpdate', oldUser, newUser) - } else gateway.client.emit('userUpdateUncached', newUser) -} +import { User } from '../../structures/user.ts' +import { UserPayload } from '../../types/user.ts' +import { Gateway, GatewayEventHandler } from '../index.ts' + +export const userUpdate: GatewayEventHandler = async ( + gateway: Gateway, + d: UserPayload +) => { + const oldUser: User | undefined = await gateway.client.users.get(d.id) + await gateway.client.users.set(d.id, d) + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + const newUser = (await gateway.client.users.get(d.id)) as User + + if (oldUser !== undefined) { + gateway.client.emit('userUpdate', oldUser, newUser) + } else gateway.client.emit('userUpdateUncached', newUser) +} diff --git a/src/gateway/handlers/voiceServerUpdate.ts b/src/gateway/handlers/voiceServerUpdate.ts index 5fc299d9..c8e7a4e8 100644 --- a/src/gateway/handlers/voiceServerUpdate.ts +++ b/src/gateway/handlers/voiceServerUpdate.ts @@ -1,14 +1,14 @@ -import { Guild } from '../../structures/guild.ts' -import { VoiceServerUpdatePayload } from '../../types/gateway.ts' -import { Gateway, GatewayEventHandler } from '../index.ts' - -export const voiceServerUpdate: GatewayEventHandler = async ( - gateway: Gateway, - d: VoiceServerUpdatePayload -) => { - gateway.client.emit('voiceServerUpdate', { - token: d.token, - endpoint: d.endpoint, - guild: ((await gateway.client.guilds.get(d.guild_id)) as unknown) as Guild, - }) -} +import { Guild } from '../../structures/guild.ts' +import { VoiceServerUpdatePayload } from '../../types/gateway.ts' +import { Gateway, GatewayEventHandler } from '../index.ts' + +export const voiceServerUpdate: GatewayEventHandler = async ( + gateway: Gateway, + d: VoiceServerUpdatePayload +) => { + gateway.client.emit('voiceServerUpdate', { + token: d.token, + endpoint: d.endpoint, + guild: ((await gateway.client.guilds.get(d.guild_id)) as unknown) as Guild + }) +} diff --git a/src/gateway/handlers/voiceStateUpdate.ts b/src/gateway/handlers/voiceStateUpdate.ts index 9ea79542..3e016d36 100644 --- a/src/gateway/handlers/voiceStateUpdate.ts +++ b/src/gateway/handlers/voiceStateUpdate.ts @@ -1,50 +1,50 @@ -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 ( - gateway: Gateway, - d: VoiceStatePayload -) => { - // 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 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 - ) - 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 - ) - } else { - gateway.client.emit( - 'voiceStateUpdate', - voiceState, - (newVoiceState as unknown) as VoiceState - ) - } -} +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 ( + gateway: Gateway, + d: VoiceStatePayload +) => { + // 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 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 + ) + 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 + ) + } else { + gateway.client.emit( + 'voiceStateUpdate', + voiceState, + (newVoiceState as unknown) as VoiceState + ) + } +} diff --git a/src/gateway/handlers/webhooksUpdate.ts b/src/gateway/handlers/webhooksUpdate.ts index 99aa8ed6..3b3ae6ef 100644 --- a/src/gateway/handlers/webhooksUpdate.ts +++ b/src/gateway/handlers/webhooksUpdate.ts @@ -1,19 +1,19 @@ -import { Gateway, GatewayEventHandler } from '../index.ts' -import { Guild } from '../../structures/guild.ts' -import { WebhooksUpdatePayload } from '../../types/gateway.ts' -import { GuildTextChannel } from '../../structures/textChannel.ts' - -export const webhooksUpdate: GatewayEventHandler = async ( - gateway: Gateway, - d: WebhooksUpdatePayload -) => { - 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) - else gateway.client.emit('webhooksUpdate', guild, channel) -} +import { Gateway, GatewayEventHandler } from '../index.ts' +import { Guild } from '../../structures/guild.ts' +import { WebhooksUpdatePayload } from '../../types/gateway.ts' +import { GuildTextChannel } from '../../structures/textChannel.ts' + +export const webhooksUpdate: GatewayEventHandler = async ( + gateway: Gateway, + d: WebhooksUpdatePayload +) => { + 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) + else gateway.client.emit('webhooksUpdate', guild, channel) +} diff --git a/src/gateway/index.ts b/src/gateway/index.ts index 4af39124..5763b408 100644 --- a/src/gateway/index.ts +++ b/src/gateway/index.ts @@ -2,7 +2,7 @@ import { unzlib } from 'https://deno.land/x/denoflate@1.1/mod.ts' import { Client } from '../models/client.ts' import { DISCORD_GATEWAY_URL, - DISCORD_API_VERSION, + DISCORD_API_VERSION } from '../consts/urlsAndVersions.ts' import { GatewayResponse } from '../types/gatewayResponse.ts' import { @@ -10,7 +10,7 @@ import { GatewayIntents, GatewayCloseCodes, IdentityPayload, - StatusUpdatePayload, + StatusUpdatePayload } from '../types/gateway.ts' import { gatewayHandlers } from './handlers/index.ts' import { GATEWAY_BOT } from '../types/endpoint.ts' @@ -230,7 +230,7 @@ class Gateway { properties: { $os: Deno.build.os, $browser: 'harmony', - $device: 'harmony', + $device: 'harmony' }, compress: true, shard: [0, 1], // TODO: Make sharding possible @@ -238,7 +238,7 @@ class Gateway { (previous, current) => previous | current, 0 ), - presence: this.client.presence.create(), + presence: this.client.presence.create() } if (this.client.bot === false) { @@ -250,13 +250,13 @@ class Gateway { $browser: 'Firefox', $device: '', $referrer: '', - $referring_domain: '', + $referring_domain: '' } } this.send({ op: GatewayOpcodes.IDENTIFY, - d: payload, + d: payload }) } @@ -272,8 +272,8 @@ class Gateway { d: { token: this.token, session_id: this.sessionID, - seq: this.sequenceID ?? null, - }, + seq: this.sequenceID ?? null + } } this.send(resumePayload) } @@ -292,8 +292,8 @@ class Gateway { limit: options.limit, presences: options.presences, user_ids: options.users, - nonce, - }, + nonce + } }) return nonce } @@ -334,7 +334,7 @@ class Gateway { op: data.op, d: data.d, s: typeof data.s === 'number' ? data.s : null, - t: data.t === undefined ? null : data.t, + t: data.t === undefined ? null : data.t }) ) return true @@ -343,14 +343,14 @@ class Gateway { sendPresence(data: StatusUpdatePayload): void { this.send({ op: GatewayOpcodes.PRESENCE_UPDATE, - d: data, + d: data }) } sendHeartbeat(): void { const payload = { op: GatewayOpcodes.HEARTBEAT, - d: this.sequenceID ?? null, + d: this.sequenceID ?? null } this.send(payload) diff --git a/src/managers/base.ts b/src/managers/base.ts index fd20c35e..ce956ac7 100644 --- a/src/managers/base.ts +++ b/src/managers/base.ts @@ -8,37 +8,37 @@ export class BaseManager { /** Which data type does this cache have */ DataType: any - constructor (client: Client, cacheName: string, DataType: any) { + constructor(client: Client, cacheName: string, DataType: any) { this.client = client this.cacheName = cacheName this.DataType = DataType } - async _get (key: string): Promise { + async _get(key: string): Promise { return this.client.cache.get(this.cacheName, key) } - async get (key: string): Promise { + async get(key: string): Promise { const raw = await this._get(key) if (raw === undefined) return return new this.DataType(this.client, raw) } - async set (key: string, value: T): Promise { + async set(key: string, value: T): Promise { return this.client.cache.set(this.cacheName, key, value) } - async delete (key: string): Promise { + async delete(key: string): Promise { return this.client.cache.delete(this.cacheName, key) } - async array (): Promise { + async array(): Promise { let arr = await (this.client.cache.array(this.cacheName) as T[]) if (arr === undefined) arr = [] - return arr.map(e => new this.DataType(this.client, e)) as any + return arr.map((e) => new this.DataType(this.client, e)) as any } - async collection (): Promise> { + async collection(): Promise> { const arr = await this.array() if (arr === undefined) return new Collection() const collection = new Collection() @@ -49,7 +49,7 @@ export class BaseManager { return collection } - flush (): any { + flush(): any { return this.client.cache.deleteCache(this.cacheName) } } diff --git a/src/managers/baseChild.ts b/src/managers/baseChild.ts index 1f43d429..a799fc8d 100644 --- a/src/managers/baseChild.ts +++ b/src/managers/baseChild.ts @@ -28,7 +28,7 @@ export class BaseChildManager { } async collection(): Promise> { - const arr = await this.array() as undefined | T2[] + const arr = (await this.array()) as undefined | T2[] if (arr === undefined) return new Collection() const collection = new Collection() for (const elem of arr) { @@ -37,4 +37,4 @@ export class BaseChildManager { } return collection } -} \ No newline at end of file +} diff --git a/src/managers/channels.ts b/src/managers/channels.ts index 49530202..a068eb37 100644 --- a/src/managers/channels.ts +++ b/src/managers/channels.ts @@ -6,12 +6,12 @@ import getChannelByType from '../utils/getChannelByType.ts' import { BaseManager } from './base.ts' export class ChannelsManager extends BaseManager { - constructor (client: Client) { + constructor(client: Client) { super(client, 'channels', Channel) } // Override get method as Generic - async get (key: string): Promise { + async get(key: string): Promise { const data = await this._get(key) if (data === undefined) return let guild @@ -25,7 +25,7 @@ export class ChannelsManager extends BaseManager { return res as any } - async array (): Promise { + async array(): Promise { const arr = await (this.client.cache.array( this.cacheName ) as ChannelPayload[]) @@ -43,19 +43,25 @@ export class ChannelsManager extends BaseManager { return result } - async fetch (id: string): Promise { + async fetch(id: string): Promise { return await new Promise((resolve, reject) => { this.client.rest .get(CHANNEL(id)) - .then(async data => { + .then(async (data) => { this.set(id, data as ChannelPayload) let guild if (data.guild_id !== undefined) { guild = await this.client.guilds.get(data.guild_id) } - resolve((getChannelByType(this.client, data as ChannelPayload, guild) as unknown) as T) + resolve( + (getChannelByType( + this.client, + data as ChannelPayload, + guild + ) as unknown) as T + ) }) - .catch(e => reject(e)) + .catch((e) => reject(e)) }) } } diff --git a/src/managers/emojis.ts b/src/managers/emojis.ts index baeda1ad..028e4e8b 100644 --- a/src/managers/emojis.ts +++ b/src/managers/emojis.ts @@ -5,12 +5,11 @@ import { GUILD_EMOJI } from '../types/endpoint.ts' import { BaseManager } from './base.ts' export class EmojisManager extends BaseManager { - - constructor (client: Client) { + constructor(client: Client) { super(client, `emojis`, Emoji) } - async get (key: string): Promise { + async get(key: string): Promise { const raw = await this._get(key) if (raw === undefined) return const emoji = new this.DataType(this.client, raw) @@ -21,15 +20,15 @@ export class EmojisManager extends BaseManager { return emoji } - async fetch (guildID: string, id: string): Promise { + async fetch(guildID: string, id: string): Promise { return await new Promise((resolve, reject) => { this.client.rest .get(GUILD_EMOJI(guildID, id)) - .then(async data => { + .then(async (data) => { await this.set(id, data as EmojiPayload) resolve(new Emoji(this.client, data as EmojiPayload)) }) - .catch(e => reject(e)) + .catch((e) => reject(e)) }) } } diff --git a/src/managers/gatewayCache.ts b/src/managers/gatewayCache.ts index 3c6fba21..4813d41b 100644 --- a/src/managers/gatewayCache.ts +++ b/src/managers/gatewayCache.ts @@ -4,22 +4,22 @@ export class GatewayCache { client: Client cacheName: string = 'discord_gateway_cache' - constructor (client: Client, cacheName?: string) { + constructor(client: Client, cacheName?: string) { this.client = client if (cacheName !== undefined) this.cacheName = cacheName } - async get (key: string): Promise { + async get(key: string): Promise { const result = await this.client.cache.get(this.cacheName, key) return result } - async set (key: string, value: any): Promise { + async set(key: string, value: any): Promise { const result = await this.client.cache.set(this.cacheName, key, value) return result } - async delete (key: string): Promise { + async delete(key: string): Promise { const result = await this.client.cache.delete(this.cacheName, key) return result } diff --git a/src/managers/guildChannels.ts b/src/managers/guildChannels.ts index da3e375d..cc7749ce 100644 --- a/src/managers/guildChannels.ts +++ b/src/managers/guildChannels.ts @@ -25,29 +25,29 @@ export class GuildChannelsManager extends BaseChildManager< > { guild: Guild - constructor (client: Client, parent: ChannelsManager, guild: Guild) { + constructor(client: Client, parent: ChannelsManager, guild: Guild) { super(client, parent as any) this.guild = guild } - async get (id: string): Promise { + async get(id: string): Promise { const res = await this.parent.get(id) if (res !== undefined && res.guild.id === this.guild.id) return res else return undefined } - + async delete(id: string): Promise { return this.client.rest.delete(CHANNEL(id)) } - async array (): Promise { + async array(): Promise { const arr = (await this.parent.array()) as Channel[] return arr.filter( (c: any) => c.guild !== undefined && c.guild.id === this.guild.id ) as any } - async flush (): Promise { + async flush(): Promise { const arr = await this.array() for (const elem of arr) { this.parent.delete(elem.id) diff --git a/src/managers/guildEmojis.ts b/src/managers/guildEmojis.ts index 768f4465..30c1d495 100644 --- a/src/managers/guildEmojis.ts +++ b/src/managers/guildEmojis.ts @@ -8,10 +8,7 @@ import { BaseChildManager } from './baseChild.ts' import { EmojisManager } from './emojis.ts' import { fetchAuto } from 'https://raw.githubusercontent.com/DjDeveloperr/fetch-base64/main/mod.ts' -export class GuildEmojisManager extends BaseChildManager< - EmojiPayload, - Emoji - > { +export class GuildEmojisManager extends BaseChildManager { guild: Guild constructor(client: Client, parent: EmojisManager, guild: Guild) { @@ -33,28 +30,34 @@ export class GuildEmojisManager extends BaseChildManager< return await new Promise((resolve, reject) => { this.client.rest .get(GUILD_EMOJI(this.guild.id, id)) - .then(async data => { + .then(async (data) => { const emoji = new Emoji(this.client, data as EmojiPayload) data.guild_id = this.guild.id await this.set(id, data as EmojiPayload) emoji.guild = this.guild resolve(emoji) }) - .catch(e => reject(e)) + .catch((e) => reject(e)) }) } - async create(name: string, url: string, roles?: Role[] | string[] | string): Promise { + async create( + name: string, + url: string, + roles?: Role[] | string[] | string + ): Promise { let data = url - if (!data.startsWith("data:")) { + if (!data.startsWith('data:')) { data = await fetchAuto(url) } return await new Promise((resolve, reject) => { let roleIDs: string[] = [] - if (roles !== undefined && typeof roles === "string") roleIDs = [roles] + if (roles !== undefined && typeof roles === 'string') roleIDs = [roles] else if (roles !== undefined) { - if (roles?.length === 0) reject(new Error("Empty Roles array was provided")) - if (roles[0] instanceof Role) roleIDs = (roles as any).map((r: Role) => r.id) + if (roles?.length === 0) + reject(new Error('Empty Roles array was provided')) + if (roles[0] instanceof Role) + roleIDs = (roles as any).map((r: Role) => r.id) else roleIDs = roles as string[] } else roles = [this.guild.id] this.client.rest @@ -63,14 +66,14 @@ export class GuildEmojisManager extends BaseChildManager< image: data, roles: roleIDs }) - .then(async data => { + .then(async (data) => { const emoji = new Emoji(this.client, data as EmojiPayload) data.guild_id = this.guild.id await this.set(data.id, data as EmojiPayload) emoji.guild = this.guild resolve(emoji) }) - .catch(e => reject(e)) + .catch((e) => reject(e)) }) } diff --git a/src/managers/guildVoiceStates.ts b/src/managers/guildVoiceStates.ts index 63d00c11..35796ba2 100644 --- a/src/managers/guildVoiceStates.ts +++ b/src/managers/guildVoiceStates.ts @@ -1,48 +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 { BaseManager } from './base.ts' - -export class GuildVoiceStatesManager extends BaseManager< - VoiceStatePayload, - VoiceState -> { - guild: Guild - - constructor(client: Client, guild: Guild) { - super(client, `vs:${guild.id}`, VoiceState) - this.guild = guild - } - - async get(key: string): Promise { - 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( - raw.channel_id - )) as unknown) as VoiceChannel), - guild, - member: - guild === undefined ? undefined : await guild.members.get(raw.user_id), - }) - } - - async fromPayload(d: VoiceStatePayload[]): Promise { - for (const data of d) { - await this.set(data.user_id, data) - } - } -} +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 { BaseManager } from './base.ts' + +export class GuildVoiceStatesManager extends BaseManager< + VoiceStatePayload, + VoiceState +> { + guild: Guild + + constructor(client: Client, guild: Guild) { + super(client, `vs:${guild.id}`, VoiceState) + this.guild = guild + } + + async get(key: string): Promise { + 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( + raw.channel_id + )) as unknown) as VoiceChannel), + guild, + member: + guild === undefined ? undefined : await guild.members.get(raw.user_id) + }) + } + + async fromPayload(d: VoiceStatePayload[]): Promise { + for (const data of d) { + await this.set(data.user_id, data) + } + } +} diff --git a/src/managers/guilds.ts b/src/managers/guilds.ts index 802ff9f7..b90f2475 100644 --- a/src/managers/guilds.ts +++ b/src/managers/guilds.ts @@ -6,11 +6,11 @@ import { BaseManager } from './base.ts' import { MembersManager } from './members.ts' export class GuildManager extends BaseManager { - constructor (client: Client) { + constructor(client: Client) { super(client, 'guilds', Guild) } - async fetch (id: string): Promise { + async fetch(id: string): Promise { return await new Promise((resolve, reject) => { this.client.rest .get(GUILD(id)) @@ -29,7 +29,7 @@ export class GuildManager extends BaseManager { resolve(guild) }) - .catch(e => reject(e)) + .catch((e) => reject(e)) }) } } diff --git a/src/managers/memberRoles.ts b/src/managers/memberRoles.ts index b1aabeca..bb715e06 100644 --- a/src/managers/memberRoles.ts +++ b/src/managers/memberRoles.ts @@ -1,81 +1,81 @@ -import { Client } from '../models/client.ts' -import { BaseChildManager } from './baseChild.ts' -import { RolePayload } from '../types/role.ts' -import { Role } from '../structures/role.ts' -import { Member } from '../structures/member.ts' -import { RolesManager } from './roles.ts' -import { MemberPayload } from '../types/guild.ts' -import { GUILD_MEMBER_ROLE } from '../types/endpoint.ts' - -export class MemberRolesManager extends BaseChildManager { - member: Member - - constructor(client: Client, parent: RolesManager, member: Member) { - super(client, parent as any) - this.member = member - } - - async get(id: string): Promise { - const res = await this.parent.get(id) - const mem = (await (this.parent as any).guild.members._get( - this.member.id - )) as MemberPayload - if ( - res !== undefined && - (mem.roles.includes(res.id) === true || res.id === this.member.guild.id) - ) - return res - else return undefined - } - - async array(): Promise { - const arr = (await this.parent.array()) as Role[] - const mem = (await (this.parent as any).guild.members._get( - this.member.id - )) as MemberPayload - return arr.filter( - (c: any) => - (mem.roles.includes(c.id) as boolean) || c.id === this.member.guild.id - ) as any - } - - async flush(): Promise { - const arr = await this.array() - for (const elem of arr) { - this.parent.delete(elem.id) - } - return true - } - - async add(role: string | Role): Promise { - const res = await this.client.rest.put( - GUILD_MEMBER_ROLE( - this.member.guild.id, - this.member.id, - typeof role === 'string' ? role : role.id - ), - undefined, - undefined, - undefined, - true - ) - - return res.status === 204 - } - - async remove(role: string | Role): Promise { - const res = await this.client.rest.delete( - GUILD_MEMBER_ROLE( - this.member.guild.id, - this.member.id, - typeof role === 'string' ? role : role.id - ), - undefined, - undefined, - undefined, - true - ) - - return res.status === 204 - } -} +import { Client } from '../models/client.ts' +import { BaseChildManager } from './baseChild.ts' +import { RolePayload } from '../types/role.ts' +import { Role } from '../structures/role.ts' +import { Member } from '../structures/member.ts' +import { RolesManager } from './roles.ts' +import { MemberPayload } from '../types/guild.ts' +import { GUILD_MEMBER_ROLE } from '../types/endpoint.ts' + +export class MemberRolesManager extends BaseChildManager { + member: Member + + constructor(client: Client, parent: RolesManager, member: Member) { + super(client, parent as any) + this.member = member + } + + async get(id: string): Promise { + const res = await this.parent.get(id) + const mem = (await (this.parent as any).guild.members._get( + this.member.id + )) as MemberPayload + if ( + res !== undefined && + (mem.roles.includes(res.id) === true || res.id === this.member.guild.id) + ) + return res + else return undefined + } + + async array(): Promise { + const arr = (await this.parent.array()) as Role[] + const mem = (await (this.parent as any).guild.members._get( + this.member.id + )) as MemberPayload + return arr.filter( + (c: any) => + (mem.roles.includes(c.id) as boolean) || c.id === this.member.guild.id + ) as any + } + + async flush(): Promise { + const arr = await this.array() + for (const elem of arr) { + this.parent.delete(elem.id) + } + return true + } + + async add(role: string | Role): Promise { + const res = await this.client.rest.put( + GUILD_MEMBER_ROLE( + this.member.guild.id, + this.member.id, + typeof role === 'string' ? role : role.id + ), + undefined, + undefined, + undefined, + true + ) + + return res.status === 204 + } + + async remove(role: string | Role): Promise { + const res = await this.client.rest.delete( + GUILD_MEMBER_ROLE( + this.member.guild.id, + this.member.id, + typeof role === 'string' ? role : role.id + ), + undefined, + undefined, + undefined, + true + ) + + return res.status === 204 + } +} diff --git a/src/managers/members.ts b/src/managers/members.ts index f3b6a9fe..3226765c 100644 --- a/src/managers/members.ts +++ b/src/managers/members.ts @@ -5,7 +5,7 @@ import { Member } from '../structures/member.ts' import { GUILD_MEMBER } from '../types/endpoint.ts' import { MemberPayload } from '../types/guild.ts' import { BaseManager } from './base.ts' -import { Permissions } from "../utils/permissions.ts" +import { Permissions } from '../utils/permissions.ts' export class MembersManager extends BaseManager { guild: Guild @@ -22,27 +22,47 @@ export class MembersManager extends BaseManager { const roles = await this.guild.roles.array() let permissions = new Permissions(Permissions.DEFAULT) if (roles !== undefined) { - const mRoles = roles.filter(r => raw.roles.includes(r.id) as boolean || r.id === this.guild.id) - permissions = new Permissions(mRoles.map(r => r.permissions)) + const mRoles = roles.filter( + (r) => (raw.roles.includes(r.id) as boolean) || r.id === this.guild.id + ) + permissions = new Permissions(mRoles.map((r) => r.permissions)) } - const res = new this.DataType(this.client, raw, user, this.guild, permissions) + const res = new this.DataType( + this.client, + raw, + user, + this.guild, + permissions + ) return res } async fetch(id: string): Promise { return await new Promise((resolve, reject) => { - this.client.rest.get(GUILD_MEMBER(this.guild.id, id)).then(async data => { - await this.set(id, data as MemberPayload) - const user: User = new User(this.client, data.user) - const roles = await this.guild.roles.array() - let permissions = new Permissions(Permissions.DEFAULT) - if (roles !== undefined) { - const mRoles = roles.filter(r => data.roles.includes(r.id) as boolean || r.id === this.guild.id) - permissions = new Permissions(mRoles.map(r => r.permissions)) - } - const res = new Member(this.client, data as MemberPayload, user, this.guild, permissions) - resolve(res) - }).catch(e => reject(e)) + this.client.rest + .get(GUILD_MEMBER(this.guild.id, id)) + .then(async (data) => { + await this.set(id, data as MemberPayload) + const user: User = new User(this.client, data.user) + const roles = await this.guild.roles.array() + let permissions = new Permissions(Permissions.DEFAULT) + if (roles !== undefined) { + const mRoles = roles.filter( + (r) => + (data.roles.includes(r.id) as boolean) || r.id === this.guild.id + ) + permissions = new Permissions(mRoles.map((r) => r.permissions)) + } + const res = new Member( + this.client, + data as MemberPayload, + user, + this.guild, + permissions + ) + resolve(res) + }) + .catch((e) => reject(e)) }) } @@ -51,4 +71,4 @@ export class MembersManager extends BaseManager { await this.set(member.user.id, member) } } -} \ No newline at end of file +} diff --git a/src/managers/messageReactions.ts b/src/managers/messageReactions.ts index 2c249c43..f2d3895f 100644 --- a/src/managers/messageReactions.ts +++ b/src/managers/messageReactions.ts @@ -1,44 +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 { - 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 { - return this.client.cache.set( - this.cacheName, - key, - value, - this.client.reactionCacheLifetime - ) - } - - async flush(): Promise { - await this.client.cache.deleteCache(`reaction_users:${this.message.id}`) - return this.client.cache.deleteCache(this.cacheName) - } -} +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 { + 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 { + return this.client.cache.set( + this.cacheName, + key, + value, + this.client.reactionCacheLifetime + ) + } + + async flush(): Promise { + await this.client.cache.deleteCache(`reaction_users:${this.message.id}`) + return this.client.cache.deleteCache(this.cacheName) + } +} diff --git a/src/managers/messages.ts b/src/managers/messages.ts index b1d6eeeb..a0395a80 100644 --- a/src/managers/messages.ts +++ b/src/managers/messages.ts @@ -1,80 +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 { - channel: TextChannel - - constructor(client: Client, channel: TextChannel) { - super(client, 'messages', Message) - this.channel = channel - } - - async get(key: string): Promise { - 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 { - return this.client.cache.set( - this.cacheName, - key, - value, - this.client.messageCacheLifetime - ) - } - - async fetch(id: string): Promise { - 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( - 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 { + channel: TextChannel + + constructor(client: Client, channel: TextChannel) { + super(client, 'messages', Message) + this.channel = channel + } + + async get(key: string): Promise { + 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 { + return this.client.cache.set( + this.cacheName, + key, + value, + this.client.messageCacheLifetime + ) + } + + async fetch(id: string): Promise { + 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( + 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)) + }) + } +} diff --git a/src/managers/presences.ts b/src/managers/presences.ts index 1dda7d2a..6a7a0fd4 100644 --- a/src/managers/presences.ts +++ b/src/managers/presences.ts @@ -1,39 +1,39 @@ -import { Client } from '../models/client.ts' -import { Guild } from '../structures/guild.ts' -import { Presence } from '../structures/presence.ts' -import { User } from '../structures/user.ts' -import { PresenceUpdatePayload } from '../types/gateway.ts' -import { BaseManager } from './base.ts' - -export class GuildPresencesManager extends BaseManager< - PresenceUpdatePayload, - Presence -> { - guild: Guild - - constructor(client: Client, guild: Guild) { - super(client, `presences:${guild.id}`, Presence) - this.guild = guild - } - - async get(id: string): Promise { - const raw = await this._get(id) - if (raw === undefined) return - let user = await this.client.users.get(raw.user.id) - if (user === undefined) user = new User(this.client, raw.user) - const guild = await this.client.guilds.get(raw.guild_id) - if (guild === undefined) return - const presence = new Presence(this.client, raw, user, guild) - return presence - } - - async fromPayload( - data: PresenceUpdatePayload[] - ): Promise { - await this.flush() - for (const pres of data) { - await this.set(pres.user.id, pres) - } - return this - } -} +import { Client } from '../models/client.ts' +import { Guild } from '../structures/guild.ts' +import { Presence } from '../structures/presence.ts' +import { User } from '../structures/user.ts' +import { PresenceUpdatePayload } from '../types/gateway.ts' +import { BaseManager } from './base.ts' + +export class GuildPresencesManager extends BaseManager< + PresenceUpdatePayload, + Presence +> { + guild: Guild + + constructor(client: Client, guild: Guild) { + super(client, `presences:${guild.id}`, Presence) + this.guild = guild + } + + async get(id: string): Promise { + const raw = await this._get(id) + if (raw === undefined) return + let user = await this.client.users.get(raw.user.id) + if (user === undefined) user = new User(this.client, raw.user) + const guild = await this.client.guilds.get(raw.guild_id) + if (guild === undefined) return + const presence = new Presence(this.client, raw, user, guild) + return presence + } + + async fromPayload( + data: PresenceUpdatePayload[] + ): Promise { + await this.flush() + for (const pres of data) { + await this.set(pres.user.id, pres) + } + return this + } +} diff --git a/src/managers/reactionUsers.ts b/src/managers/reactionUsers.ts index 76051944..332c66bd 100644 --- a/src/managers/reactionUsers.ts +++ b/src/managers/reactionUsers.ts @@ -1,13 +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 - } -} +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 + } +} diff --git a/src/managers/roles.ts b/src/managers/roles.ts index 9e88a9c2..437c6c08 100644 --- a/src/managers/roles.ts +++ b/src/managers/roles.ts @@ -8,20 +8,20 @@ import { BaseManager } from './base.ts' export class RolesManager extends BaseManager { guild: Guild - constructor (client: Client, guild: Guild) { + constructor(client: Client, guild: Guild) { super(client, `roles:${guild.id}`, Role) this.guild = guild } - async fetch (id: string): Promise { + async fetch(id: string): Promise { return await new Promise((resolve, reject) => { this.client.rest .get(GUILD_ROLE(this.guild.id, id)) - .then(data => { + .then((data) => { this.set(id, data as RolePayload) resolve(new Role(this.client, data as RolePayload)) }) - .catch(e => reject(e)) + .catch((e) => reject(e)) }) } diff --git a/src/managers/users.ts b/src/managers/users.ts index 8a428b1d..46b36e66 100644 --- a/src/managers/users.ts +++ b/src/managers/users.ts @@ -5,19 +5,19 @@ import { UserPayload } from '../types/user.ts' import { BaseManager } from './base.ts' export class UserManager extends BaseManager { - constructor (client: Client) { + constructor(client: Client) { super(client, 'users', User) } - async fetch (id: string): Promise { + async fetch(id: string): Promise { return await new Promise((resolve, reject) => { this.client.rest .get(USER(id)) - .then(data => { + .then((data) => { this.set(id, data as UserPayload) resolve(new User(this.client, data as UserPayload)) }) - .catch(e => reject(e)) + .catch((e) => reject(e)) }) } } diff --git a/src/models/cacheAdapter.ts b/src/models/cacheAdapter.ts index 9318aa45..3b6fc08b 100644 --- a/src/models/cacheAdapter.ts +++ b/src/models/cacheAdapter.ts @@ -7,7 +7,12 @@ import { export interface ICacheAdapter { get: (cacheName: string, key: string) => Promise | any - set: (cacheName: string, key: string, value: any, expire?: number) => Promise | any + set: ( + cacheName: string, + key: string, + value: any, + expire?: number + ) => Promise | any delete: (cacheName: string, key: string) => Promise | boolean array: (cacheName: string) => undefined | any[] | Promise deleteCache: (cacheName: string) => any @@ -24,16 +29,22 @@ export class DefaultCacheAdapter implements ICacheAdapter { return cache.get(key) } - async set(cacheName: string, key: string, value: any, expire?: number): Promise { + async set( + cacheName: string, + key: string, + value: any, + expire?: number + ): Promise { let cache = this.data[cacheName] if (cache === undefined) { this.data[cacheName] = new Collection() cache = this.data[cacheName] } cache.set(key, value) - if (expire !== undefined) setTimeout(() => { - cache.delete(key) - }, expire) + if (expire !== undefined) + setTimeout(() => { + cache.delete(key) + }, expire) } async delete(cacheName: string, key: string): Promise { @@ -64,7 +75,7 @@ export class RedisCacheAdapter implements ICacheAdapter { constructor(options: RedisConnectOptions) { this._redis = connect(options) this._redis.then( - redis => { + (redis) => { this.redis = redis this.ready = true this._startExpireInterval() @@ -79,11 +90,11 @@ export class RedisCacheAdapter implements ICacheAdapter { this._expireInterval = setInterval(() => { this.redis?.scan(0, { pattern: '*:expires' }).then(([_, names]) => { for (const name of names) { - this.redis?.hvals(name).then(vals => { + this.redis?.hvals(name).then((vals) => { for (const val of vals) { const expireVal: { - name: string, - key: string, + name: string + key: string at: number } = JSON.parse(val) const expired = new Date().getTime() > expireVal.at @@ -126,7 +137,11 @@ export class RedisCacheAdapter implements ICacheAdapter { await this.redis?.hset( `${cacheName}:expires`, key, - JSON.stringify({ name: cacheName, key, at: new Date().getTime() + expire }) + JSON.stringify({ + name: cacheName, + key, + at: new Date().getTime() + expire + }) ) } return result @@ -148,6 +163,6 @@ export class RedisCacheAdapter implements ICacheAdapter { async deleteCache(cacheName: string): Promise { await this._checkReady() - return await this.redis?.del(cacheName) !== 0 + return (await this.redis?.del(cacheName)) !== 0 } } diff --git a/src/models/client.ts b/src/models/client.ts index 3f335e8d..17b96a98 100644 --- a/src/models/client.ts +++ b/src/models/client.ts @@ -1,148 +1,147 @@ -import { User } from '../structures/user.ts' -import { GatewayIntents } from '../types/gateway.ts' -import { Gateway } from '../gateway/index.ts' -import { RESTManager } from './rest.ts' -import EventEmitter from 'https://deno.land/std@0.74.0/node/events.ts' -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 { EmojisManager } from '../managers/emojis.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 */ -export interface ClientOptions { - /** Token of the Bot/User */ - token?: string - /** Gateway Intents */ - intents?: GatewayIntents[] - /** Cache Adapter to use, defaults to Collections one */ - cache?: ICacheAdapter - /** Force New Session and don't use cached Session (by persistent caching) */ - forceNewSession?: boolean - /** Startup presence of client */ - presence?: ClientPresence | ClientActivity | ActivityGame - /** Whether it's a bot user or not? Use this if selfbot! */ - bot?: boolean - /** Force all requests to Canary API */ - 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: (event: U, listener: ClientEvents[U]) => this - - emit: ( - event: U, - ...args: Parameters - ) => boolean -} - -/** - * Discord Client. - */ -export class Client extends EventEmitter { - /** Gateway object */ - gateway?: Gateway - /** REST Manager - used to make all requests */ - rest: RESTManager = new RESTManager(this) - /** User which Client logs in to, undefined until logs in */ - user?: User - /** WebSocket ping of Client */ - ping = 0 - /** Token of the Bot/User */ - token?: string - /** Cache Adapter */ - cache: ICacheAdapter = new DefaultCacheAdapter() - /** Gateway Intents */ - intents?: GatewayIntents[] - /** Whether to force new session or not */ - 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 */ - canary: boolean = false - /** Client's presence. Startup one if set before connecting */ - presence: ClientPresence = new ClientPresence() - - constructor(options: ClientOptions = {}) { - super() - this.token = options.token - this.intents = options.intents - this.forceNewSession = options.forceNewSession - if (options.cache !== undefined) this.cache = options.cache - if (options.presence !== undefined) - this.presence = - options.presence instanceof ClientPresence - ? options.presence - : 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.reactionCacheLifetime !== undefined) - this.reactionCacheLifetime = options.reactionCacheLifetime - if (options.fetchUncachedReactions === true) - this.fetchUncachedReactions = true - } - - /** Set Cache Adapter */ - setAdapter(adapter: ICacheAdapter): Client { - this.cache = adapter - return this - } - - /** Change Presence of Client */ - setPresence(presence: ClientPresence | ClientActivity | ActivityGame): void { - if (presence instanceof ClientPresence) { - this.presence = presence - } else this.presence = new ClientPresence(presence) - this.gateway?.sendPresence(this.presence.create()) - } - - /** Emit debug event */ - debug(tag: string, msg: string): void { - this.emit('debug', `[${tag}] ${msg}`) - } - - // TODO(DjDeveloperr): Implement this - // fetchApplication(): Promise - - /** - * This function is used for connect to discord. - * @param token Your token. This is required. - * @param intents Gateway intents in array. This is required. - */ - 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 - } else throw new Error('No Token Provided') - if (intents === undefined && this.intents !== undefined) - intents = this.intents - else if (intents !== undefined && this.intents === undefined) { - this.intents = intents - } else throw new Error('No Gateway Intents were provided') - this.gateway = new Gateway(this, token, intents) - } -} +import { User } from '../structures/user.ts' +import { GatewayIntents } from '../types/gateway.ts' +import { Gateway } from '../gateway/index.ts' +import { RESTManager } from './rest.ts' +import EventEmitter from 'https://deno.land/std@0.74.0/node/events.ts' +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 { EmojisManager } from '../managers/emojis.ts' +import { ActivityGame, ClientActivity } from '../types/presence.ts' +import { ClientEvents } from '../gateway/handlers/index.ts' + +/** Some Client Options to modify behaviour */ +export interface ClientOptions { + /** Token of the Bot/User */ + token?: string + /** Gateway Intents */ + intents?: GatewayIntents[] + /** Cache Adapter to use, defaults to Collections one */ + cache?: ICacheAdapter + /** Force New Session and don't use cached Session (by persistent caching) */ + forceNewSession?: boolean + /** Startup presence of client */ + presence?: ClientPresence | ClientActivity | ActivityGame + /** Whether it's a bot user or not? Use this if selfbot! */ + bot?: boolean + /** Force all requests to Canary API */ + 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: (event: U, listener: ClientEvents[U]) => this + + emit: ( + event: U, + ...args: Parameters + ) => boolean +} + +/** + * Discord Client. + */ +export class Client extends EventEmitter { + /** Gateway object */ + gateway?: Gateway + /** REST Manager - used to make all requests */ + rest: RESTManager = new RESTManager(this) + /** User which Client logs in to, undefined until logs in */ + user?: User + /** WebSocket ping of Client */ + ping = 0 + /** Token of the Bot/User */ + token?: string + /** Cache Adapter */ + cache: ICacheAdapter = new DefaultCacheAdapter() + /** Gateway Intents */ + intents?: GatewayIntents[] + /** Whether to force new session or not */ + 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 */ + canary: boolean = false + /** Client's presence. Startup one if set before connecting */ + presence: ClientPresence = new ClientPresence() + + constructor(options: ClientOptions = {}) { + super() + this.token = options.token + this.intents = options.intents + this.forceNewSession = options.forceNewSession + if (options.cache !== undefined) this.cache = options.cache + if (options.presence !== undefined) + this.presence = + options.presence instanceof ClientPresence + ? options.presence + : 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.reactionCacheLifetime !== undefined) + this.reactionCacheLifetime = options.reactionCacheLifetime + if (options.fetchUncachedReactions === true) + this.fetchUncachedReactions = true + } + + /** Set Cache Adapter */ + setAdapter(adapter: ICacheAdapter): Client { + this.cache = adapter + return this + } + + /** Change Presence of Client */ + setPresence(presence: ClientPresence | ClientActivity | ActivityGame): void { + if (presence instanceof ClientPresence) { + this.presence = presence + } else this.presence = new ClientPresence(presence) + this.gateway?.sendPresence(this.presence.create()) + } + + /** Emit debug event */ + debug(tag: string, msg: string): void { + this.emit('debug', `[${tag}] ${msg}`) + } + + // TODO(DjDeveloperr): Implement this + // fetchApplication(): Promise + + /** + * This function is used for connect to discord. + * @param token Your token. This is required. + * @param intents Gateway intents in array. This is required. + */ + 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 + } else throw new Error('No Token Provided') + if (intents === undefined && this.intents !== undefined) + intents = this.intents + else if (intents !== undefined && this.intents === undefined) { + this.intents = intents + } else throw new Error('No Gateway Intents were provided') + this.gateway = new Gateway(this, token, intents) + } +} diff --git a/src/models/command.ts b/src/models/command.ts index 48b2a0a9..2df4e5e3 100644 --- a/src/models/command.ts +++ b/src/models/command.ts @@ -1,428 +1,428 @@ -import { Guild } from '../structures/guild.ts' -import { Message } from '../structures/message.ts' -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' - -export interface CommandContext { - /** The Client object */ - client: CommandClient - /** Message which was parsed for Command */ - message: Message - /** The Author of the Message */ - author: User - /** The Channel in which Command was used */ - channel: TextChannel - /** Prefix which was used */ - prefix: string - /** Oject of Command which was used */ - command: Command - /** Name of Command which was used */ - name: string - /** Array of Arguments used with Command */ - args: string[] - /** Complete Raw String of Arguments */ - argString: string - /** Guild which the command has called */ - guild?: Guild -} - -export class Command { - /** Name of the 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 */ - extension?: Extension - /** Usage of Command, only Argument Names */ - 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? 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 */ - roles?: string | string[] - /** Whitelisted Guilds. Only these Guild(s) can execute Command. (List or one of IDs) */ - whitelistedGuilds?: string | string[] - /** Whitelisted Channels. Command can be executed only in these channels. (List or one of IDs) */ - whitelistedChannels?: string | string[] - /** Whitelisted Users. Command can be executed only by these Users (List or one of IDs) */ - whitelistedUsers?: string | string[] - /** Whether the Command can only be used in Guild (if allowed in DMs) */ - guildOnly?: boolean - /** Whether the Command can only be used in Bot's DMs (if allowed) */ - dmOnly?: boolean - /** Whether the Command can only be used by Bot Owners */ - ownerOnly?: boolean - - /** Method executed before executing actual command. Returns bool value - whether to continue or not (optional) */ - beforeExecute(ctx: CommandContext): boolean | Promise { - return true - } - - /** Actual command code, which is executed when all checks have passed. */ - 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 {} - - toString(): string { - 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 - } -} - -export class CommandsManager { - client: CommandClient - list: Collection = new Collection() - disabled: Set = new Set() - - constructor(client: CommandClient) { - this.client = client - } - - /** Number of loaded Commands */ - get count(): number { - return this.list.size - } - - /** Find a Command by name/alias */ - find(search: string): Command | undefined { - if (this.client.caseSensitive === false) search = search.toLowerCase() - return this.list.find((cmd: Command): boolean => { - const name = - this.client.caseSensitive === true ? cmd.name : cmd.name.toLowerCase() - if (name === search) return true - else if (cmd.aliases !== undefined) { - let aliases: string[] - if (typeof cmd.aliases === 'string') aliases = [cmd.aliases] - else aliases = cmd.aliases - if (this.client.caseSensitive === false) - aliases = aliases.map((e) => e.toLowerCase()) - return aliases.includes(search) - } else return false - }) - } - - /** Fetch a Command including disable checks */ - fetch(name: string, bypassDisable?: boolean): Command | undefined { - const cmd = this.find(name) - if (cmd === undefined) return - if (this.isDisabled(cmd) && bypassDisable !== true) return - return cmd - } - - /** Check whether a Command exists or not */ - exists(search: Command | string): boolean { - let exists = false - if (typeof search === 'string') return this.find(search) !== undefined - else { - exists = this.find(search.name) !== undefined - if (search.aliases !== undefined) { - const aliases: string[] = - typeof search.aliases === 'string' ? [search.aliases] : search.aliases - exists = - aliases - .map((alias) => this.find(alias) !== undefined) - .find((e) => e) ?? false - } - return exists - } - } - - /** Add a Command */ - 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.` - ) - this.list.set(cmd.name, cmd) - return true - } - - /** Delete a Command */ - delete(cmd: string | Command): boolean { - const find = typeof cmd === 'string' ? this.find(cmd) : cmd - if (find === undefined) return false - else return this.list.delete(find.name) - } - - /** Check whether a Command is disabled or not */ - isDisabled(name: string | Command): boolean { - const cmd = typeof name === 'string' ? this.find(name) : name - if (cmd === undefined) return false - const exists = this.exists(name) - if (!exists) return false - return this.disabled.has(cmd.name) - } - - /** Disable a Command */ - disable(name: string | Command): boolean { - 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 { - return this.list.filter( - (cmd) => cmd.category !== undefined && cmd.category === category - ) - } -} - -export class CategoriesManager { - client: CommandClient - list: Collection = new Collection() - - constructor(client: CommandClient) { - this.client = client - } - - /** Get a Collection of Categories */ - all(): Collection { - 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 { - name: string - args: string[] - argString: string -} - -export const parseCommand = ( - client: CommandClient, - msg: Message, - prefix: string -): ParsedCommand => { - let content = msg.content.slice(prefix.length) - if (client.spacesAfterPrefix === true) content = content.trim() - const args = content.split(client.betterArgs === true ? /[\S\s]*/ : / +/) - const name = args.shift() as string - const argString = content.slice(name.length).trim() - - return { - name, - args, - argString, - } -} +import { Guild } from '../structures/guild.ts' +import { Message } from '../structures/message.ts' +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' + +export interface CommandContext { + /** The Client object */ + client: CommandClient + /** Message which was parsed for Command */ + message: Message + /** The Author of the Message */ + author: User + /** The Channel in which Command was used */ + channel: TextChannel + /** Prefix which was used */ + prefix: string + /** Oject of Command which was used */ + command: Command + /** Name of Command which was used */ + name: string + /** Array of Arguments used with Command */ + args: string[] + /** Complete Raw String of Arguments */ + argString: string + /** Guild which the command has called */ + guild?: Guild +} + +export class Command { + /** Name of the 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 */ + extension?: Extension + /** Usage of Command, only Argument Names */ + 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? 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 */ + roles?: string | string[] + /** Whitelisted Guilds. Only these Guild(s) can execute Command. (List or one of IDs) */ + whitelistedGuilds?: string | string[] + /** Whitelisted Channels. Command can be executed only in these channels. (List or one of IDs) */ + whitelistedChannels?: string | string[] + /** Whitelisted Users. Command can be executed only by these Users (List or one of IDs) */ + whitelistedUsers?: string | string[] + /** Whether the Command can only be used in Guild (if allowed in DMs) */ + guildOnly?: boolean + /** Whether the Command can only be used in Bot's DMs (if allowed) */ + dmOnly?: boolean + /** Whether the Command can only be used by Bot Owners */ + ownerOnly?: boolean + + /** Method executed before executing actual command. Returns bool value - whether to continue or not (optional) */ + beforeExecute(ctx: CommandContext): boolean | Promise { + return true + } + + /** Actual command code, which is executed when all checks have passed. */ + 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 {} + + toString(): string { + 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 + } +} + +export class CommandsManager { + client: CommandClient + list: Collection = new Collection() + disabled: Set = new Set() + + constructor(client: CommandClient) { + this.client = client + } + + /** Number of loaded Commands */ + get count(): number { + return this.list.size + } + + /** Find a Command by name/alias */ + find(search: string): Command | undefined { + if (this.client.caseSensitive === false) search = search.toLowerCase() + return this.list.find((cmd: Command): boolean => { + const name = + this.client.caseSensitive === true ? cmd.name : cmd.name.toLowerCase() + if (name === search) return true + else if (cmd.aliases !== undefined) { + let aliases: string[] + if (typeof cmd.aliases === 'string') aliases = [cmd.aliases] + else aliases = cmd.aliases + if (this.client.caseSensitive === false) + aliases = aliases.map((e) => e.toLowerCase()) + return aliases.includes(search) + } else return false + }) + } + + /** Fetch a Command including disable checks */ + fetch(name: string, bypassDisable?: boolean): Command | undefined { + const cmd = this.find(name) + if (cmd === undefined) return + if (this.isDisabled(cmd) && bypassDisable !== true) return + return cmd + } + + /** Check whether a Command exists or not */ + exists(search: Command | string): boolean { + let exists = false + if (typeof search === 'string') return this.find(search) !== undefined + else { + exists = this.find(search.name) !== undefined + if (search.aliases !== undefined) { + const aliases: string[] = + typeof search.aliases === 'string' ? [search.aliases] : search.aliases + exists = + aliases + .map((alias) => this.find(alias) !== undefined) + .find((e) => e) ?? false + } + return exists + } + } + + /** Add a Command */ + 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.` + ) + this.list.set(cmd.name, cmd) + return true + } + + /** Delete a Command */ + delete(cmd: string | Command): boolean { + const find = typeof cmd === 'string' ? this.find(cmd) : cmd + if (find === undefined) return false + else return this.list.delete(find.name) + } + + /** Check whether a Command is disabled or not */ + isDisabled(name: string | Command): boolean { + const cmd = typeof name === 'string' ? this.find(name) : name + if (cmd === undefined) return false + const exists = this.exists(name) + if (!exists) return false + return this.disabled.has(cmd.name) + } + + /** Disable a Command */ + disable(name: string | Command): boolean { + 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 { + return this.list.filter( + (cmd) => cmd.category !== undefined && cmd.category === category + ) + } +} + +export class CategoriesManager { + client: CommandClient + list: Collection = new Collection() + + constructor(client: CommandClient) { + this.client = client + } + + /** Get a Collection of Categories */ + all(): Collection { + 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 { + name: string + args: string[] + argString: string +} + +export const parseCommand = ( + client: CommandClient, + msg: Message, + prefix: string +): ParsedCommand => { + let content = msg.content.slice(prefix.length) + if (client.spacesAfterPrefix === true) content = content.trim() + const args = content.split(client.betterArgs === true ? /[\S\s]*/ : / +/) + const name = args.shift() as string + const argString = content.slice(name.length).trim() + + return { + name, + args, + argString + } +} diff --git a/src/models/commandClient.ts b/src/models/commandClient.ts index e3b3b668..69a84231 100644 --- a/src/models/commandClient.ts +++ b/src/models/commandClient.ts @@ -1,332 +1,332 @@ -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 - -export interface CommandClientOptions extends ClientOptions { - prefix: string | string[] - mentionPrefix?: boolean - getGuildPrefix?: (guildID: string) => PrefixReturnType - getUserPrefix?: (userID: string) => PrefixReturnType - isGuildBlacklisted?: (guildID: string) => boolean | Promise - isUserBlacklisted?: (guildID: string) => boolean | Promise - isChannelBlacklisted?: (guildID: string) => boolean | Promise - 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 - isUserBlacklisted: (guildID: string) => boolean | Promise - isChannelBlacklisted: (guildID: string) => boolean | Promise - 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 { - 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) - } - } -} +import { Message } from '../structures/message.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 + +export interface CommandClientOptions extends ClientOptions { + prefix: string | string[] + mentionPrefix?: boolean + getGuildPrefix?: (guildID: string) => PrefixReturnType + getUserPrefix?: (userID: string) => PrefixReturnType + isGuildBlacklisted?: (guildID: string) => boolean | Promise + isUserBlacklisted?: (guildID: string) => boolean | Promise + isChannelBlacklisted?: (guildID: string) => boolean | Promise + 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 + isUserBlacklisted: (guildID: string) => boolean | Promise + isChannelBlacklisted: (guildID: string) => boolean | Promise + 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 { + 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[] = await awaitSync( + this.getUserPrefix(msg.author.id) + ) + + if (msg.guild !== undefined) { + prefix = await awaitSync(this.getGuildPrefix(msg.guild.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) + } + } +} diff --git a/src/models/extensions.ts b/src/models/extensions.ts index 4dc27d1b..8af3aee5 100644 --- a/src/models/extensions.ts +++ b/src/models/extensions.ts @@ -1,6 +1,6 @@ -import { Collection } from "../utils/collection.ts"; -import { Command } from "./command.ts"; -import { CommandClient } from "./commandClient.ts"; +import { Collection } from '../utils/collection.ts' +import { Command } from './command.ts' +import { CommandClient } from './commandClient.ts' export type ExtensionEventCallback = (ext: Extension, ...args: any[]) => any @@ -12,7 +12,9 @@ export class ExtensionCommands { } get list(): Collection { - return this.extension.client.commands.list.filter(c => c.extension?.name === this.extension.name) + return this.extension.client.commands.list.filter( + (c) => c.extension?.name === this.extension.name + ) } get(cmd: string): Command | undefined { @@ -31,9 +33,15 @@ export class ExtensionCommands { } delete(cmd: Command | string): boolean { - const find = this.extension.client.commands.find(typeof cmd === 'string' ? cmd : cmd.name) + const find = this.extension.client.commands.find( + typeof cmd === 'string' ? cmd : cmd.name + ) if (find === undefined) return false - if (find.extension !== undefined && find.extension.name !== this.extension.name) return false + if ( + find.extension !== undefined && + find.extension.name !== this.extension.name + ) + return false else return this.extension.client.commands.delete(find) } @@ -61,7 +69,7 @@ export class Extension { const fn = (...args: any[]): any => { // eslint-disable-next-line standard/no-callback-literal cb(this, ...args) - }; + } this.client.on(event, fn) this.events[event] = fn return true @@ -91,7 +99,8 @@ export class ExtensionsManager { load(ext: Extension | typeof Extension): void { // eslint-disable-next-line new-cap if (!(ext instanceof Extension)) ext = new ext(this.client) - if (this.exists(ext.name)) throw new Error(`Extension with name '${ext.name}' already exists`) + if (this.exists(ext.name)) + throw new Error(`Extension with name '${ext.name}' already exists`) this.list.set(ext.name, ext) ext.load() } @@ -109,4 +118,4 @@ export class ExtensionsManager { extension.unload() return this.list.delete(name) } -} \ No newline at end of file +} diff --git a/src/models/rest.ts b/src/models/rest.ts index bc265c53..8bd889a7 100644 --- a/src/models/rest.ts +++ b/src/models/rest.ts @@ -22,7 +22,7 @@ export enum HttpResponseCode { NotFound = 404, MethodNotAllowed = 405, TooManyRequests = 429, - GatewayUnavailable = 502, + GatewayUnavailable = 502 } export interface RequestHeaders { @@ -109,7 +109,7 @@ export class RESTManager { if (result?.rateLimited !== undefined) { this.queue({ ...request, - bucket: result.bucket ?? request.bucket, + bucket: result.bucket ?? request.bucket }) } } @@ -121,7 +121,7 @@ export class RESTManager { if (result?.rateLimited !== undefined) { this.queue({ ...request, - bucket: result.bucket ?? request.bucket, + bucket: result.bucket ?? request.bucket }) } } @@ -141,7 +141,7 @@ export class RESTManager { prepare(body: any, method: RequestMethods): { [key: string]: any } { const headers: RequestHeaders = { - 'User-Agent': `DiscordBot (harmony, https://github.com/harmony-org/harmony)`, + 'User-Agent': `DiscordBot (harmony, https://github.com/harmony-org/harmony)` } if (this.client !== undefined) @@ -168,7 +168,7 @@ export class RESTManager { const data: { [name: string]: any } = { headers, body: body?.file ?? JSON.stringify(body), - method: method.toUpperCase(), + method: method.toUpperCase() } if (this.client?.bot === false) { @@ -222,14 +222,14 @@ export class RESTManager { this.rateLimits.set(url, { url, resetAt: Number(resetAt) * 1000, - bucket, + bucket }) if (bucket !== null) { this.rateLimits.set(bucket, { url, resetAt: Number(resetAt) * 1000, - bucket, + bucket }) } } @@ -242,14 +242,14 @@ export class RESTManager { this.rateLimits.set('global', { url: 'global', resetAt: reset, - bucket, + bucket }) if (bucket !== null) { this.rateLimits.set(bucket, { url: 'global', resetAt: reset, - bucket, + bucket }) } } @@ -286,7 +286,7 @@ export class RESTManager { url: response.url, status, method: data.method, - body: data.body, + body: data.body } if (body !== undefined) error = Object.assign(error, body) @@ -295,7 +295,7 @@ export class RESTManager { HttpResponseCode.BadRequest, HttpResponseCode.NotFound, HttpResponseCode.Forbidden, - HttpResponseCode.MethodNotAllowed, + HttpResponseCode.MethodNotAllowed ].includes(status) ) { throw new DiscordAPIError(Deno.inspect(error)) @@ -320,7 +320,7 @@ export class RESTManager { return { rateLimited: rateLimitResetIn, before: true, - bucket, + bucket } } @@ -367,7 +367,7 @@ export class RESTManager { return { rateLimited: json.retry_after, before: false, - bucket: bucketFromHeaders, + bucket: bucketFromHeaders } } return resolve(rawResponse === true ? { response, body: json } : json) @@ -379,7 +379,7 @@ export class RESTManager { this.queue({ onComplete, bucket, - url, + url }) if (!this.processing) { this.processing = true diff --git a/src/models/shard.ts b/src/models/shard.ts index 36fb07e9..a9eed476 100644 --- a/src/models/shard.ts +++ b/src/models/shard.ts @@ -1 +1 @@ -// TODO: write code \ No newline at end of file +// TODO: write code diff --git a/src/models/voice.ts b/src/models/voice.ts index 80b51ff9..8c9e4a44 100644 --- a/src/models/voice.ts +++ b/src/models/voice.ts @@ -1,26 +1,26 @@ -import { Guild } from "../structures/guild.ts" -import { VoiceChannel } from "../structures/guildVoiceChannel.ts" -import { Client } from './client.ts' - -export interface VoiceOptions { - guild: Guild, - channel: VoiceChannel -} - -export class VoiceClient { - client: Client - ws?: WebSocket - guild: Guild - channel: VoiceChannel - - constructor(client: Client, options: VoiceOptions) { - this.client = client - this.guild = options.guild - this.channel = options.channel - } - - async connect(): Promise { - // TODO(DjDeveloperr): Actually understand what the hell docs say - return this - } -} \ No newline at end of file +import { Guild } from '../structures/guild.ts' +import { VoiceChannel } from '../structures/guildVoiceChannel.ts' +import { Client } from './client.ts' + +export interface VoiceOptions { + guild: Guild + channel: VoiceChannel +} + +export class VoiceClient { + client: Client + ws?: WebSocket + guild: Guild + channel: VoiceChannel + + constructor(client: Client, options: VoiceOptions) { + this.client = client + this.guild = options.guild + this.channel = options.channel + } + + async connect(): Promise { + // TODO(DjDeveloperr): Actually understand what the hell docs say + return this + } +} diff --git a/src/structures/application.ts b/src/structures/application.ts index c4d5cf18..fdab9724 100644 --- a/src/structures/application.ts +++ b/src/structures/application.ts @@ -1,24 +1,24 @@ -import { Client } from "../models/client.ts"; -import { ApplicationPayload } from "../types/application.ts"; -import { Base } from "./base.ts"; -import { User } from "./user.ts"; - -export class Application extends Base { - id: string - name: string - icon: string - description: string - summary: string - bot?: User - - constructor(client: Client, data: ApplicationPayload) { - super(client, data) - - this.id = data.id - this.name = data.name - this.icon = data.icon - this.description = data.description - this.summary = data.summary - this.bot = data.bot !== undefined ? new User(client, data.bot) : undefined - } -} \ No newline at end of file +import { Client } from '../models/client.ts' +import { ApplicationPayload } from '../types/application.ts' +import { Base } from './base.ts' +import { User } from './user.ts' + +export class Application extends Base { + id: string + name: string + icon: string + description: string + summary: string + bot?: User + + constructor(client: Client, data: ApplicationPayload) { + super(client, data) + + this.id = data.id + this.name = data.name + this.icon = data.icon + this.description = data.description + this.summary = data.summary + this.bot = data.bot !== undefined ? new User(client, data.bot) : undefined + } +} diff --git a/src/structures/base.ts b/src/structures/base.ts index 155bb7d1..387de3f5 100644 --- a/src/structures/base.ts +++ b/src/structures/base.ts @@ -13,18 +13,21 @@ export class Base { static useCache?: boolean = true static restFunc?: (...restURLfuncArgs: string[]) => string - constructor (client: Client, _data?: any) { + constructor(client: Client, _data?: any) { this.client = client } - static async autoInit ( + static async autoInit( client: Client, { useCache, endpoint, restURLfuncArgs }: IInit ): Promise { this.useCache = useCache const cacheID = restURLfuncArgs.join(':') if (this.useCache !== undefined) { - const cached = await client.cache.get(this.cacheName ?? this.name, cacheID) + const cached = await client.cache.get( + this.cacheName ?? this.name, + cacheID + ) if (cached !== undefined) { return cached } @@ -35,7 +38,7 @@ export class Base { return new this(client, jsonParsed) } - async refreshFromAPI ( + async refreshFromAPI( client: Client, { endpoint, restURLfuncArgs }: IInit ): Promise { @@ -48,13 +51,13 @@ export class Base { return oldOne } - refreshFromData (data: { [k: string]: any }): this { + refreshFromData(data: { [k: string]: any }): this { const oldOne = Object.assign(Object.create(this), this) this.readFromData(data) return oldOne } - protected readFromData (data: { [k: string]: any }): void {} + protected readFromData(data: { [k: string]: any }): void {} // toJSON() {} } diff --git a/src/structures/channel.ts b/src/structures/channel.ts index ed8d97be..031183b1 100644 --- a/src/structures/channel.ts +++ b/src/structures/channel.ts @@ -6,11 +6,11 @@ export class Channel extends Base { type: ChannelTypes id: string static cacheName = 'channel' - get mention (): string { + get mention(): string { return `<#${this.id}>` } - constructor (client: Client, data: ChannelPayload) { + constructor(client: Client, data: ChannelPayload) { super(client, data) this.type = data.type this.id = data.id @@ -18,7 +18,7 @@ export class Channel extends Base { // this.client.channels.set(this.id, data) } - protected readFromData (data: ChannelPayload): void { + protected readFromData(data: ChannelPayload): void { super.readFromData(data) this.type = data.type ?? this.type this.id = data.id ?? this.id diff --git a/src/structures/dmChannel.ts b/src/structures/dmChannel.ts index 1513216c..64e1896b 100644 --- a/src/structures/dmChannel.ts +++ b/src/structures/dmChannel.ts @@ -6,12 +6,12 @@ import { TextChannel } from './textChannel.ts' export class DMChannel extends TextChannel { recipients: UserPayload[] - constructor (client: Client, data: DMChannelPayload) { + constructor(client: Client, data: DMChannelPayload) { super(client, data) this.recipients = data.recipients } - protected readFromData (data: DMChannelPayload): void { + protected readFromData(data: DMChannelPayload): void { super.readFromData(data) this.recipients = data.recipients ?? this.recipients } diff --git a/src/structures/embed.ts b/src/structures/embed.ts index 2ce70a15..6abcedf0 100644 --- a/src/structures/embed.ts +++ b/src/structures/embed.ts @@ -25,7 +25,7 @@ export class Embed { author?: EmbedAuthor fields?: EmbedField[] - constructor (data?: EmbedPayload) { + constructor(data?: EmbedPayload) { this.title = data?.title this.type = data?.type this.description = data?.description @@ -42,7 +42,7 @@ export class Embed { } // khk4912 - toJSON (): EmbedPayload { + toJSON(): EmbedPayload { return { title: this.title, type: this.type, @@ -60,72 +60,72 @@ export class Embed { } } - setTitle (title: string): Embed { + setTitle(title: string): Embed { this.title = title return this } - setDescription (description: string): Embed { + setDescription(description: string): Embed { this.description = description return this } - setType (type: EmbedTypes): Embed { + setType(type: EmbedTypes): Embed { this.type = type return this } - setURL (url: string): Embed { + setURL(url: string): Embed { this.url = url return this } - setTimestamp (timestamp: string): Embed { + setTimestamp(timestamp: string): Embed { this.timestamp = timestamp return this } - setColor (hex: number): Embed { + setColor(hex: number): Embed { this.color = hex return this } - setFooter (footer: EmbedFooter): Embed { + setFooter(footer: EmbedFooter): Embed { this.footer = footer return this } - setImage (image: EmbedImage): Embed { + setImage(image: EmbedImage): Embed { this.image = image return this } - setThumbnail (thumbnail: EmbedThumbnail): Embed { + setThumbnail(thumbnail: EmbedThumbnail): Embed { this.thumbnail = thumbnail return this } - setVideo (video: EmbedVideo): Embed { + setVideo(video: EmbedVideo): Embed { this.video = video return this } - setProvider (provider: EmbedProvider): Embed { + setProvider(provider: EmbedProvider): Embed { this.provider = provider return this } - setAuthor (author: EmbedAuthor): Embed { + setAuthor(author: EmbedAuthor): Embed { this.author = author return this } - setFields (fields: EmbedField[]): Embed { + setFields(fields: EmbedField[]): Embed { this.fields = fields return this } - addField (name: string, value: string, inline?: boolean): Embed { + addField(name: string, value: string, inline?: boolean): Embed { if (this.fields === undefined) { this.fields = [ { diff --git a/src/structures/emoji.ts b/src/structures/emoji.ts index b42e42ad..f4009010 100644 --- a/src/structures/emoji.ts +++ b/src/structures/emoji.ts @@ -16,7 +16,7 @@ export class Emoji extends Base { animated?: boolean available?: boolean - get getEmojiString (): string { + get getEmojiString(): string { if (this.animated === false) { return `<:${this.name}:${this.id}>` } else return `` @@ -26,7 +26,7 @@ export class Emoji extends Base { return this.getEmojiString } - constructor (client: Client, data: EmojiPayload) { + constructor(client: Client, data: EmojiPayload) { super(client, data) this.id = data.id this.name = data.name @@ -38,7 +38,7 @@ export class Emoji extends Base { this.available = data.available } - protected readFromData (data: EmojiPayload): void { + protected readFromData(data: EmojiPayload): void { super.readFromData(data) this.id = data.id ?? this.id this.name = data.name ?? this.name @@ -51,7 +51,7 @@ export class Emoji extends Base { User.autoInit(this.client, { endpoint: USER, restURLfuncArgs: [data.user.id] - }).then(user => (this.user = user)) + }).then((user) => (this.user = user)) } } } diff --git a/src/structures/groupChannel.ts b/src/structures/groupChannel.ts index 6baf3543..ee7e1e40 100644 --- a/src/structures/groupChannel.ts +++ b/src/structures/groupChannel.ts @@ -7,7 +7,7 @@ export class GroupDMChannel extends Channel { icon?: string ownerID: string - constructor (client: Client, data: GroupDMChannelPayload) { + constructor(client: Client, data: GroupDMChannelPayload) { super(client, data) this.name = data.name @@ -17,7 +17,7 @@ export class GroupDMChannel extends Channel { // cache.set('groupchannel', this.id, this) } - protected readFromData (data: GroupDMChannelPayload): void { + protected readFromData(data: GroupDMChannelPayload): void { super.readFromData(data) this.name = data.name ?? this.name this.icon = data.icon ?? this.icon diff --git a/src/structures/guild.ts b/src/structures/guild.ts index 29ecf077..cd3f574e 100644 --- a/src/structures/guild.ts +++ b/src/structures/guild.ts @@ -1,377 +1,377 @@ -import { Client } from '../models/client.ts' -import { - GuildBanPayload, - GuildFeatures, - GuildIntegrationPayload, - GuildPayload, - IntegrationAccountPayload, - IntegrationExpireBehavior, -} from '../types/guild.ts' -import { Base } from './base.ts' -import { RolesManager } from '../managers/roles.ts' -import { InviteManager } from '../managers/invites.ts' -import { GuildChannelsManager } from '../managers/guildChannels.ts' -import { MembersManager } from '../managers/members.ts' -import { Role } from './role.ts' -import { GuildEmojisManager } from '../managers/guildEmojis.ts' -import { Member } from './member.ts' -import { User } from './user.ts' -import { Application } from './application.ts' -import { GUILD_BAN, GUILD_BANS, GUILD_INTEGRATIONS } from '../types/endpoint.ts' -import { GuildVoiceStatesManager } from '../managers/guildVoiceStates.ts' -import { RequestMembersOptions } from '../gateway/index.ts' -import { GuildPresencesManager } from '../managers/presences.ts' - -export class GuildBan extends Base { - guild: Guild - reason?: string - user: User - - constructor(client: Client, data: GuildBanPayload, guild: Guild) { - super(client, data) - this.guild = guild - this.reason = data.reason === null ? undefined : data.reason - this.user = new User(client, data.user) - } -} - -export class GuildBans { - client: Client - guild: Guild - - constructor(client: Client, guild: Guild) { - this.client = client - this.guild = guild - } - - /** - * Get all bans in the Guild. - */ - async all(): Promise { - const res = await this.client.rest.get(GUILD_BANS(this.guild.id)) - if (typeof res !== 'object' || !Array.isArray(res)) - throw new Error('Failed to fetch Guild Bans') - - const bans = (res as GuildBanPayload[]).map( - (ban) => new GuildBan(this.client, ban, this.guild) - ) - return bans - } - - /** - * Get ban details of a User if any. - * @param user User to get ban of, ID or User object. - */ - async get(user: string | User): Promise { - const res = await this.client.rest.get( - GUILD_BAN(this.guild.id, typeof user === 'string' ? user : user.id) - ) - if (typeof res !== 'object') throw new Error('Failed to fetch Guild Ban') - return new GuildBan(this.client, res, this.guild) - } - - /** - * Ban a User. - * @param user User to ban, ID or User object. - * @param reason Reason for the Ban. - * @param deleteMessagesDays Delete Old Messages? If yes, how much days. - */ - async add( - user: string | User, - reason?: string, - deleteMessagesDays?: number - ): Promise { - const res = await this.client.rest.put( - GUILD_BAN(this.guild.id, typeof user === 'string' ? user : user.id), - { - reason, - delete_message_days: deleteMessagesDays, - }, - undefined, - null, - true - ) - - if (res.status !== 204) throw new Error('Failed to Add Guild Ban') - } - - /** - * Unban (remove ban from) a User. - * @param user User to unban, ID or User object. - */ - async remove(user: string | User): Promise { - const res = await this.client.rest.delete( - GUILD_BAN(this.guild.id, typeof user === 'string' ? user : user.id), - undefined, - undefined, - null, - true - ) - - if (res.status !== 204) return false - else return true - } -} - -export class Guild extends Base { - id: string - name?: string - icon?: string - iconHash?: string - splash?: string - discoverySplash?: string - owner?: boolean - ownerID?: string - permissions?: string - region?: string - afkChannelID?: string - afkTimeout?: number - widgetEnabled?: boolean - widgetChannelID?: string - verificationLevel?: string - defaultMessageNotifications?: string - explicitContentFilter?: string - roles: RolesManager - emojis: GuildEmojisManager - invites: InviteManager - features?: GuildFeatures[] - mfaLevel?: string - applicationID?: string - systemChannelID?: string - systemChannelFlags?: string - rulesChannelID?: string - joinedAt?: string - large?: boolean - unavailable: boolean - memberCount?: number - voiceStates: GuildVoiceStatesManager - members: MembersManager - channels: GuildChannelsManager - presences: GuildPresencesManager - maxPresences?: number - maxMembers?: number - vanityURLCode?: string - description?: string - banner?: string - premiumTier?: number - premiumSubscriptionCount?: number - preferredLocale?: string - publicUpdatesChannelID?: string - maxVideoChannelUsers?: number - approximateNumberCount?: number - approximatePresenceCount?: number - bans: GuildBans - - constructor(client: Client, data: GuildPayload) { - super(client, data) - this.id = data.id - this.bans = new GuildBans(client, this) - this.unavailable = data.unavailable - this.members = new MembersManager(this.client, this) - this.voiceStates = new GuildVoiceStatesManager(client, this) - this.presences = new GuildPresencesManager(client, this) - this.channels = new GuildChannelsManager( - this.client, - this.client.channels, - this - ) - this.roles = new RolesManager(this.client, this) - this.emojis = new GuildEmojisManager(this.client, this.client.emojis, this) - this.invites = new InviteManager(this.client, this) - - if (!this.unavailable) { - this.name = data.name - this.icon = data.icon - this.iconHash = data.icon_hash - this.splash = data.splash - this.discoverySplash = data.discovery_splash - this.owner = data.owner - this.ownerID = data.owner_id - this.permissions = data.permissions - this.region = data.region - this.afkTimeout = data.afk_timeout - this.afkChannelID = data.afk_channel_id - this.widgetEnabled = data.widget_enabled - this.widgetChannelID = data.widget_channel_id - this.verificationLevel = data.verification_level - this.defaultMessageNotifications = data.default_message_notifications - this.explicitContentFilter = data.explicit_content_filter - this.features = data.features - this.mfaLevel = data.mfa_level - this.systemChannelID = data.system_channel_id - this.systemChannelFlags = data.system_channel_flags - this.rulesChannelID = data.rules_channel_id - this.joinedAt = data.joined_at - this.large = data.large - this.memberCount = data.member_count - this.maxPresences = data.max_presences - this.maxMembers = data.max_members - this.vanityURLCode = data.vanity_url_code - this.description = data.description - this.banner = data.banner - this.premiumTier = data.premium_tier - this.premiumSubscriptionCount = data.premium_subscription_count - this.preferredLocale = data.preferred_locale - this.publicUpdatesChannelID = data.public_updates_channel_id - this.maxVideoChannelUsers = data.max_video_channel_users - this.approximateNumberCount = data.approximate_number_count - this.approximatePresenceCount = data.approximate_presence_count - } - } - - protected readFromData(data: GuildPayload): void { - super.readFromData(data) - this.id = data.id ?? this.id - this.unavailable = data.unavailable ?? this.unavailable - - if (!this.unavailable) { - this.name = data.name ?? this.name - this.icon = data.icon ?? this.icon - this.iconHash = data.icon_hash ?? this.iconHash - this.splash = data.splash ?? this.splash - this.discoverySplash = data.discovery_splash ?? this.discoverySplash - this.owner = data.owner ?? this.owner - this.ownerID = data.owner_id ?? this.ownerID - this.permissions = data.permissions ?? this.permissions - this.region = data.region ?? this.region - this.afkTimeout = data.afk_timeout ?? this.afkTimeout - this.afkChannelID = data.afk_channel_id ?? this.afkChannelID - this.widgetEnabled = data.widget_enabled ?? this.widgetEnabled - this.widgetChannelID = data.widget_channel_id ?? this.widgetChannelID - this.verificationLevel = data.verification_level ?? this.verificationLevel - this.defaultMessageNotifications = - data.default_message_notifications ?? this.defaultMessageNotifications - this.explicitContentFilter = - data.explicit_content_filter ?? this.explicitContentFilter - this.features = data.features ?? this.features - this.mfaLevel = data.mfa_level ?? this.mfaLevel - this.systemChannelID = data.system_channel_id ?? this.systemChannelID - this.systemChannelFlags = - data.system_channel_flags ?? this.systemChannelFlags - this.rulesChannelID = data.rules_channel_id ?? this.rulesChannelID - this.joinedAt = data.joined_at ?? this.joinedAt - this.large = data.large ?? this.large - this.memberCount = data.member_count ?? this.memberCount - this.maxPresences = data.max_presences ?? this.maxPresences - this.maxMembers = data.max_members ?? this.maxMembers - this.vanityURLCode = data.vanity_url_code ?? this.vanityURLCode - this.description = data.description ?? this.description - this.banner = data.banner ?? this.banner - this.premiumTier = data.premium_tier ?? this.premiumTier - this.premiumSubscriptionCount = - data.premium_subscription_count ?? this.premiumSubscriptionCount - this.preferredLocale = data.preferred_locale ?? this.preferredLocale - this.publicUpdatesChannelID = - data.public_updates_channel_id ?? this.publicUpdatesChannelID - this.maxVideoChannelUsers = - data.max_video_channel_users ?? this.maxVideoChannelUsers - this.approximateNumberCount = - data.approximate_number_count ?? this.approximateNumberCount - this.approximatePresenceCount = - data.approximate_presence_count ?? this.approximatePresenceCount - } - } - - /** - * Get Everyone role of the Guild - */ - async getEveryoneRole(): Promise { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion - return (await this.roles.get(this.id)) as Role - } - - /** - * Get current client's member in the Guild - */ - async me(): Promise { - const get = await this.members.get(this.client.user?.id as string) - if (get === undefined) throw new Error('Guild#me is not cached') - return get - } - - /** - * Fetch Guild's Integrations (Webhooks, Bots, etc.) - */ - async fetchIntegrations(): Promise { - const raw = (await this.client.rest.get( - GUILD_INTEGRATIONS(this.id) - )) as GuildIntegrationPayload[] - return raw.map((e) => new GuildIntegration(this.client, e)) - } - - /** - * Chunk the Guild Members, i.e. cache them. - * @param options Options regarding the Members Request - * @param wait Whether to wait for all Members to come before resolving Promise or not. - * @param timeout Configurable timeout to cancel the wait to safely remove listener. - */ - async chunk( - options: RequestMembersOptions, - wait: boolean = false, - timeout: number = 60000 - ): Promise { - return await new Promise((resolve, reject) => { - this.client.gateway?.requestMembers(this.id, options) - if (!wait) return resolve(this) - else { - let chunked = false - const listener = (guild: Guild): void => { - if (guild.id === this.id) { - chunked = true - this.client.removeListener('guildMembersChunked', listener) - resolve(this) - } - } - this.client.on('guildMembersChunked', listener) - setTimeout(() => { - if (!chunked) { - this.client.removeListener('guildMembersChunked', listener) - } - }, timeout) - } - resolve(this) - }) - } -} - -export class GuildIntegration extends Base { - id: string - name: string - type: string - enabled: boolean - syncing?: boolean - roleID?: string - enableEmoticons?: boolean - expireBehaviour?: IntegrationExpireBehavior - expireGracePeriod?: number - user?: User - account: IntegrationAccountPayload - syncedAt?: string // Actually a ISO Timestamp, but we parse in constructor' - subscriberCount?: number - revoked?: boolean - application?: Application - - constructor(client: Client, data: GuildIntegrationPayload) { - super(client, data) - - this.id = data.id - this.name = data.name - this.type = data.type - this.enabled = data.enabled - this.syncing = data.syncing - this.roleID = data.role_id - this.enableEmoticons = data.enable_emoticons - this.expireBehaviour = data.expire_behaviour - this.expireGracePeriod = data.expire_grace_period - this.user = - data.user !== undefined ? new User(client, data.user) : undefined - this.account = data.account - this.syncedAt = data.synced_at - this.subscriberCount = data.subscriber_count - this.revoked = data.revoked - this.application = - data.application !== undefined - ? new Application(client, data.application) - : undefined - } -} +import { Client } from '../models/client.ts' +import { + GuildBanPayload, + GuildFeatures, + GuildIntegrationPayload, + GuildPayload, + IntegrationAccountPayload, + IntegrationExpireBehavior +} from '../types/guild.ts' +import { Base } from './base.ts' +import { RolesManager } from '../managers/roles.ts' +import { InviteManager } from '../managers/invites.ts' +import { GuildChannelsManager } from '../managers/guildChannels.ts' +import { MembersManager } from '../managers/members.ts' +import { Role } from './role.ts' +import { GuildEmojisManager } from '../managers/guildEmojis.ts' +import { Member } from './member.ts' +import { User } from './user.ts' +import { Application } from './application.ts' +import { GUILD_BAN, GUILD_BANS, GUILD_INTEGRATIONS } from '../types/endpoint.ts' +import { GuildVoiceStatesManager } from '../managers/guildVoiceStates.ts' +import { RequestMembersOptions } from '../gateway/index.ts' +import { GuildPresencesManager } from '../managers/presences.ts' + +export class GuildBan extends Base { + guild: Guild + reason?: string + user: User + + constructor(client: Client, data: GuildBanPayload, guild: Guild) { + super(client, data) + this.guild = guild + this.reason = data.reason === null ? undefined : data.reason + this.user = new User(client, data.user) + } +} + +export class GuildBans { + client: Client + guild: Guild + + constructor(client: Client, guild: Guild) { + this.client = client + this.guild = guild + } + + /** + * Get all bans in the Guild. + */ + async all(): Promise { + const res = await this.client.rest.get(GUILD_BANS(this.guild.id)) + if (typeof res !== 'object' || !Array.isArray(res)) + throw new Error('Failed to fetch Guild Bans') + + const bans = (res as GuildBanPayload[]).map( + (ban) => new GuildBan(this.client, ban, this.guild) + ) + return bans + } + + /** + * Get ban details of a User if any. + * @param user User to get ban of, ID or User object. + */ + async get(user: string | User): Promise { + const res = await this.client.rest.get( + GUILD_BAN(this.guild.id, typeof user === 'string' ? user : user.id) + ) + if (typeof res !== 'object') throw new Error('Failed to fetch Guild Ban') + return new GuildBan(this.client, res, this.guild) + } + + /** + * Ban a User. + * @param user User to ban, ID or User object. + * @param reason Reason for the Ban. + * @param deleteMessagesDays Delete Old Messages? If yes, how much days. + */ + async add( + user: string | User, + reason?: string, + deleteMessagesDays?: number + ): Promise { + const res = await this.client.rest.put( + GUILD_BAN(this.guild.id, typeof user === 'string' ? user : user.id), + { + reason, + delete_message_days: deleteMessagesDays + }, + undefined, + null, + true + ) + + if (res.status !== 204) throw new Error('Failed to Add Guild Ban') + } + + /** + * Unban (remove ban from) a User. + * @param user User to unban, ID or User object. + */ + async remove(user: string | User): Promise { + const res = await this.client.rest.delete( + GUILD_BAN(this.guild.id, typeof user === 'string' ? user : user.id), + undefined, + undefined, + null, + true + ) + + if (res.status !== 204) return false + else return true + } +} + +export class Guild extends Base { + id: string + name?: string + icon?: string + iconHash?: string + splash?: string + discoverySplash?: string + owner?: boolean + ownerID?: string + permissions?: string + region?: string + afkChannelID?: string + afkTimeout?: number + widgetEnabled?: boolean + widgetChannelID?: string + verificationLevel?: string + defaultMessageNotifications?: string + explicitContentFilter?: string + roles: RolesManager + emojis: GuildEmojisManager + invites: InviteManager + features?: GuildFeatures[] + mfaLevel?: string + applicationID?: string + systemChannelID?: string + systemChannelFlags?: string + rulesChannelID?: string + joinedAt?: string + large?: boolean + unavailable: boolean + memberCount?: number + voiceStates: GuildVoiceStatesManager + members: MembersManager + channels: GuildChannelsManager + presences: GuildPresencesManager + maxPresences?: number + maxMembers?: number + vanityURLCode?: string + description?: string + banner?: string + premiumTier?: number + premiumSubscriptionCount?: number + preferredLocale?: string + publicUpdatesChannelID?: string + maxVideoChannelUsers?: number + approximateNumberCount?: number + approximatePresenceCount?: number + bans: GuildBans + + constructor(client: Client, data: GuildPayload) { + super(client, data) + this.id = data.id + this.bans = new GuildBans(client, this) + this.unavailable = data.unavailable + this.members = new MembersManager(this.client, this) + this.voiceStates = new GuildVoiceStatesManager(client, this) + this.presences = new GuildPresencesManager(client, this) + this.channels = new GuildChannelsManager( + this.client, + this.client.channels, + this + ) + this.roles = new RolesManager(this.client, this) + this.emojis = new GuildEmojisManager(this.client, this.client.emojis, this) + this.invites = new InviteManager(this.client, this) + + if (!this.unavailable) { + this.name = data.name + this.icon = data.icon + this.iconHash = data.icon_hash + this.splash = data.splash + this.discoverySplash = data.discovery_splash + this.owner = data.owner + this.ownerID = data.owner_id + this.permissions = data.permissions + this.region = data.region + this.afkTimeout = data.afk_timeout + this.afkChannelID = data.afk_channel_id + this.widgetEnabled = data.widget_enabled + this.widgetChannelID = data.widget_channel_id + this.verificationLevel = data.verification_level + this.defaultMessageNotifications = data.default_message_notifications + this.explicitContentFilter = data.explicit_content_filter + this.features = data.features + this.mfaLevel = data.mfa_level + this.systemChannelID = data.system_channel_id + this.systemChannelFlags = data.system_channel_flags + this.rulesChannelID = data.rules_channel_id + this.joinedAt = data.joined_at + this.large = data.large + this.memberCount = data.member_count + this.maxPresences = data.max_presences + this.maxMembers = data.max_members + this.vanityURLCode = data.vanity_url_code + this.description = data.description + this.banner = data.banner + this.premiumTier = data.premium_tier + this.premiumSubscriptionCount = data.premium_subscription_count + this.preferredLocale = data.preferred_locale + this.publicUpdatesChannelID = data.public_updates_channel_id + this.maxVideoChannelUsers = data.max_video_channel_users + this.approximateNumberCount = data.approximate_number_count + this.approximatePresenceCount = data.approximate_presence_count + } + } + + protected readFromData(data: GuildPayload): void { + super.readFromData(data) + this.id = data.id ?? this.id + this.unavailable = data.unavailable ?? this.unavailable + + if (!this.unavailable) { + this.name = data.name ?? this.name + this.icon = data.icon ?? this.icon + this.iconHash = data.icon_hash ?? this.iconHash + this.splash = data.splash ?? this.splash + this.discoverySplash = data.discovery_splash ?? this.discoverySplash + this.owner = data.owner ?? this.owner + this.ownerID = data.owner_id ?? this.ownerID + this.permissions = data.permissions ?? this.permissions + this.region = data.region ?? this.region + this.afkTimeout = data.afk_timeout ?? this.afkTimeout + this.afkChannelID = data.afk_channel_id ?? this.afkChannelID + this.widgetEnabled = data.widget_enabled ?? this.widgetEnabled + this.widgetChannelID = data.widget_channel_id ?? this.widgetChannelID + this.verificationLevel = data.verification_level ?? this.verificationLevel + this.defaultMessageNotifications = + data.default_message_notifications ?? this.defaultMessageNotifications + this.explicitContentFilter = + data.explicit_content_filter ?? this.explicitContentFilter + this.features = data.features ?? this.features + this.mfaLevel = data.mfa_level ?? this.mfaLevel + this.systemChannelID = data.system_channel_id ?? this.systemChannelID + this.systemChannelFlags = + data.system_channel_flags ?? this.systemChannelFlags + this.rulesChannelID = data.rules_channel_id ?? this.rulesChannelID + this.joinedAt = data.joined_at ?? this.joinedAt + this.large = data.large ?? this.large + this.memberCount = data.member_count ?? this.memberCount + this.maxPresences = data.max_presences ?? this.maxPresences + this.maxMembers = data.max_members ?? this.maxMembers + this.vanityURLCode = data.vanity_url_code ?? this.vanityURLCode + this.description = data.description ?? this.description + this.banner = data.banner ?? this.banner + this.premiumTier = data.premium_tier ?? this.premiumTier + this.premiumSubscriptionCount = + data.premium_subscription_count ?? this.premiumSubscriptionCount + this.preferredLocale = data.preferred_locale ?? this.preferredLocale + this.publicUpdatesChannelID = + data.public_updates_channel_id ?? this.publicUpdatesChannelID + this.maxVideoChannelUsers = + data.max_video_channel_users ?? this.maxVideoChannelUsers + this.approximateNumberCount = + data.approximate_number_count ?? this.approximateNumberCount + this.approximatePresenceCount = + data.approximate_presence_count ?? this.approximatePresenceCount + } + } + + /** + * Get Everyone role of the Guild + */ + async getEveryoneRole(): Promise { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + return (await this.roles.get(this.id)) as Role + } + + /** + * Get current client's member in the Guild + */ + async me(): Promise { + const get = await this.members.get(this.client.user?.id as string) + if (get === undefined) throw new Error('Guild#me is not cached') + return get + } + + /** + * Fetch Guild's Integrations (Webhooks, Bots, etc.) + */ + async fetchIntegrations(): Promise { + const raw = (await this.client.rest.get( + GUILD_INTEGRATIONS(this.id) + )) as GuildIntegrationPayload[] + return raw.map((e) => new GuildIntegration(this.client, e)) + } + + /** + * Chunk the Guild Members, i.e. cache them. + * @param options Options regarding the Members Request + * @param wait Whether to wait for all Members to come before resolving Promise or not. + * @param timeout Configurable timeout to cancel the wait to safely remove listener. + */ + async chunk( + options: RequestMembersOptions, + wait: boolean = false, + timeout: number = 60000 + ): Promise { + return await new Promise((resolve, reject) => { + this.client.gateway?.requestMembers(this.id, options) + if (!wait) return resolve(this) + else { + let chunked = false + const listener = (guild: Guild): void => { + if (guild.id === this.id) { + chunked = true + this.client.removeListener('guildMembersChunked', listener) + resolve(this) + } + } + this.client.on('guildMembersChunked', listener) + setTimeout(() => { + if (!chunked) { + this.client.removeListener('guildMembersChunked', listener) + } + }, timeout) + } + resolve(this) + }) + } +} + +export class GuildIntegration extends Base { + id: string + name: string + type: string + enabled: boolean + syncing?: boolean + roleID?: string + enableEmoticons?: boolean + expireBehaviour?: IntegrationExpireBehavior + expireGracePeriod?: number + user?: User + account: IntegrationAccountPayload + syncedAt?: string // Actually a ISO Timestamp, but we parse in constructor' + subscriberCount?: number + revoked?: boolean + application?: Application + + constructor(client: Client, data: GuildIntegrationPayload) { + super(client, data) + + this.id = data.id + this.name = data.name + this.type = data.type + this.enabled = data.enabled + this.syncing = data.syncing + this.roleID = data.role_id + this.enableEmoticons = data.enable_emoticons + this.expireBehaviour = data.expire_behaviour + this.expireGracePeriod = data.expire_grace_period + this.user = + data.user !== undefined ? new User(client, data.user) : undefined + this.account = data.account + this.syncedAt = data.synced_at + this.subscriberCount = data.subscriber_count + this.revoked = data.revoked + this.application = + data.application !== undefined + ? new Application(client, data.application) + : undefined + } +} diff --git a/src/structures/guildCategoryChannel.ts b/src/structures/guildCategoryChannel.ts index 1da8d674..186c2d26 100644 --- a/src/structures/guildCategoryChannel.ts +++ b/src/structures/guildCategoryChannel.ts @@ -1,9 +1,6 @@ import { Client } from '../models/client.ts' import { Channel } from './channel.ts' -import { - GuildChannelCategoryPayload, - Overwrite -} from '../types/channel.ts' +import { GuildChannelCategoryPayload, Overwrite } from '../types/channel.ts' import { Guild } from './guild.ts' export class CategoryChannel extends Channel { @@ -15,7 +12,7 @@ export class CategoryChannel extends Channel { guild: Guild parentID?: string - constructor (client: Client, data: GuildChannelCategoryPayload, guild: Guild) { + constructor(client: Client, data: GuildChannelCategoryPayload, guild: Guild) { super(client, data) this.guildID = data.guild_id this.name = data.name @@ -28,7 +25,7 @@ export class CategoryChannel extends Channel { // cache.set('guildcategorychannel', this.id, this) } - protected readFromData (data: GuildChannelCategoryPayload): void { + protected readFromData(data: GuildChannelCategoryPayload): void { super.readFromData(data) this.guildID = data.guild_id ?? this.guildID this.name = data.name ?? this.name diff --git a/src/structures/guildNewsChannel.ts b/src/structures/guildNewsChannel.ts index 0f05237a..b5e750f9 100644 --- a/src/structures/guildNewsChannel.ts +++ b/src/structures/guildNewsChannel.ts @@ -13,7 +13,7 @@ export class NewsChannel extends TextChannel { parentID?: string topic?: string - constructor (client: Client, data: GuildNewsChannelPayload, guild: Guild) { + constructor(client: Client, data: GuildNewsChannelPayload, guild: Guild) { super(client, data) this.guildID = data.guild_id this.name = data.name @@ -25,7 +25,7 @@ export class NewsChannel extends TextChannel { this.topic = data.topic } - protected readFromData (data: GuildNewsChannelPayload): void { + protected readFromData(data: GuildNewsChannelPayload): void { super.readFromData(data) this.guildID = data.guild_id ?? this.guildID this.name = data.name ?? this.name diff --git a/src/structures/guildVoiceChannel.ts b/src/structures/guildVoiceChannel.ts index 211c81c3..d64abf4d 100644 --- a/src/structures/guildVoiceChannel.ts +++ b/src/structures/guildVoiceChannel.ts @@ -14,7 +14,7 @@ export class VoiceChannel extends Channel { nsfw: boolean parentID?: string - constructor (client: Client, data: GuildVoiceChannelPayload, guild: Guild) { + constructor(client: Client, data: GuildVoiceChannelPayload, guild: Guild) { super(client, data) this.bitrate = data.bitrate this.userLimit = data.user_limit @@ -29,7 +29,7 @@ export class VoiceChannel extends Channel { // cache.set('guildvoicechannel', this.id, this) } - protected readFromData (data: GuildVoiceChannelPayload): void { + protected readFromData(data: GuildVoiceChannelPayload): void { super.readFromData(data) this.bitrate = data.bitrate ?? this.bitrate this.userLimit = data.user_limit ?? this.userLimit diff --git a/src/structures/invite.ts b/src/structures/invite.ts index 32bdce6f..d84ceb88 100644 --- a/src/structures/invite.ts +++ b/src/structures/invite.ts @@ -1,47 +1,47 @@ -import { Client } from '../models/client.ts' -import { ChannelPayload } from '../types/channel.ts' -import { GuildPayload } from '../types/guild.ts' -import { InvitePayload } from '../types/invite.ts' -import { UserPayload } from '../types/user.ts' -import { Base } from './base.ts' - -export class Invite extends Base { - code: string - guild?: GuildPayload - channel: ChannelPayload - inviter?: UserPayload - targetUser?: UserPayload - targetUserType?: number - approximatePresenceCount?: number - approximateMemberCount?: number - - get link(): string { - return `https://discord.gg/${this.code}` - } - - constructor(client: Client, data: InvitePayload) { - super(client) - this.code = data.code - this.guild = data.guild - this.channel = data.channel - this.inviter = data.inviter - this.targetUser = data.target_user - this.targetUserType = data.target_user_type - this.approximateMemberCount = data.approximate_member_count - this.approximatePresenceCount = data.approximate_presence_count - } - - protected readFromData(data: InvitePayload): void { - super.readFromData(data) - this.code = data.code ?? this.code - this.guild = data.guild ?? this.guild - this.channel = data.channel ?? this.channel - this.inviter = data.inviter ?? this.inviter - this.targetUser = data.target_user ?? this.targetUser - this.targetUserType = data.target_user_type ?? this.targetUserType - this.approximateMemberCount = - data.approximate_member_count ?? this.approximateMemberCount - this.approximatePresenceCount = - data.approximate_presence_count ?? this.approximatePresenceCount - } -} +import { Client } from '../models/client.ts' +import { ChannelPayload } from '../types/channel.ts' +import { GuildPayload } from '../types/guild.ts' +import { InvitePayload } from '../types/invite.ts' +import { UserPayload } from '../types/user.ts' +import { Base } from './base.ts' + +export class Invite extends Base { + code: string + guild?: GuildPayload + channel: ChannelPayload + inviter?: UserPayload + targetUser?: UserPayload + targetUserType?: number + approximatePresenceCount?: number + approximateMemberCount?: number + + get link(): string { + return `https://discord.gg/${this.code}` + } + + constructor(client: Client, data: InvitePayload) { + super(client) + this.code = data.code + this.guild = data.guild + this.channel = data.channel + this.inviter = data.inviter + this.targetUser = data.target_user + this.targetUserType = data.target_user_type + this.approximateMemberCount = data.approximate_member_count + this.approximatePresenceCount = data.approximate_presence_count + } + + protected readFromData(data: InvitePayload): void { + super.readFromData(data) + this.code = data.code ?? this.code + this.guild = data.guild ?? this.guild + this.channel = data.channel ?? this.channel + this.inviter = data.inviter ?? this.inviter + this.targetUser = data.target_user ?? this.targetUser + this.targetUserType = data.target_user_type ?? this.targetUserType + this.approximateMemberCount = + data.approximate_member_count ?? this.approximateMemberCount + this.approximatePresenceCount = + data.approximate_presence_count ?? this.approximatePresenceCount + } +} diff --git a/src/structures/member.ts b/src/structures/member.ts index f1a133f0..f74d3be4 100644 --- a/src/structures/member.ts +++ b/src/structures/member.ts @@ -1,173 +1,173 @@ -import { MemberRolesManager } from '../managers/memberRoles.ts' -import { Client } from '../models/client.ts' -import { GUILD_MEMBER } from '../types/endpoint.ts' -import { MemberPayload } from '../types/guild.ts' -import { Permissions } from '../utils/permissions.ts' -import { Base } from './base.ts' -import { Guild } from './guild.ts' -import { Role } from './role.ts' -import { User } from './user.ts' - -export interface MemberData { - nick?: string | null - roles?: Array - deaf?: boolean - mute?: boolean -} - -export class Member extends Base { - id: string - user: User - nick?: string - roles: MemberRolesManager - joinedAt: string - premiumSince?: string - deaf: boolean - mute: boolean - guild: Guild - permissions: Permissions - - constructor( - client: Client, - data: MemberPayload, - user: User, - guild: Guild, - perms?: Permissions - ) { - super(client) - this.id = data.user.id - this.user = user - this.nick = data.nick - this.guild = guild - this.roles = new MemberRolesManager(this.client, this.guild.roles, this) - this.joinedAt = data.joined_at - this.premiumSince = data.premium_since - this.deaf = data.deaf - this.mute = data.mute - if (perms !== undefined) this.permissions = perms - else this.permissions = new Permissions(Permissions.DEFAULT) - } - - get displayName(): string { - return this.nick !== undefined ? this.nick : this.user.username - } - - toString(): string { - return this.user.nickMention - } - - protected readFromData(data: MemberPayload): void { - super.readFromData(data.user) - this.nick = data.nick ?? this.nick - this.joinedAt = data.joined_at ?? this.joinedAt - this.premiumSince = data.premium_since ?? this.premiumSince - this.deaf = data.deaf ?? this.deaf - this.mute = data.mute ?? this.mute - } - - /** - * Update the Member data in cache (and this object). - */ - async fetch(): Promise { - const raw = await this.client.rest.get(this.id) - if (typeof raw !== 'object') throw new Error('Member not found') - await this.guild.members.set(this.id, raw) - this.readFromData(raw) - return this - } - - /** - * Edit the Member - * @param data Data to apply - */ - async edit(data: MemberData): Promise { - const payload = { - nick: data.nick, - roles: data.roles?.map((e) => (typeof e === 'string' ? e : e.id)), - deaf: data.deaf, - mute: data.mute, - } - const res = await this.client.rest.patch( - GUILD_MEMBER(this.guild.id, this.id), - payload, - undefined, - null, - true - ) - if (res.ok === true) { - if (data.nick !== undefined) - this.nick = data.nick === null ? undefined : data.nick - if (data.deaf !== undefined) this.deaf = data.deaf - if (data.mute !== undefined) this.mute = data.mute - } - return this - } - - /** - * New nickname to set. If empty, nick is reset - * @param nick New nickname - */ - async setNickname(nick?: string): Promise { - return await this.edit({ - nick: nick === undefined ? null : nick, - }) - } - - /** - * Reset nickname of the Member - */ - async resetNickname(): Promise { - return await this.setNickname() - } - - /** - * Set mute of a Member in VC - * @param mute Value to set - */ - async setMute(mute?: boolean): Promise { - return await this.edit({ - mute: mute === undefined ? false : mute, - }) - } - - /** - * Set deaf of a Member in VC - * @param deaf Value to set - */ - async setDeaf(deaf?: boolean): Promise { - return await this.edit({ - deaf: deaf === undefined ? false : deaf, - }) - } - - /** - * Unmute the Member from VC. - */ - async unmute(): Promise { - return await this.setMute(false) - } - - /** - * Kick the member. - */ - async kick(): Promise { - const resp = await this.client.rest.delete( - GUILD_MEMBER(this.guild.id, this.id), - undefined, - undefined, - null, - true - ) - if (resp.ok !== true) return false - else return true - } - - /** - * Ban the Member. - * @param reason Reason for the Ban. - * @param deleteMessagesDays Delete Old Messages? If yes, how much days. - */ - async ban(reason?: string, deleteOldMessages?: number): Promise { - return this.guild.bans.add(this.id, reason, deleteOldMessages) - } -} +import { MemberRolesManager } from '../managers/memberRoles.ts' +import { Client } from '../models/client.ts' +import { GUILD_MEMBER } from '../types/endpoint.ts' +import { MemberPayload } from '../types/guild.ts' +import { Permissions } from '../utils/permissions.ts' +import { Base } from './base.ts' +import { Guild } from './guild.ts' +import { Role } from './role.ts' +import { User } from './user.ts' + +export interface MemberData { + nick?: string | null + roles?: Array + deaf?: boolean + mute?: boolean +} + +export class Member extends Base { + id: string + user: User + nick?: string + roles: MemberRolesManager + joinedAt: string + premiumSince?: string + deaf: boolean + mute: boolean + guild: Guild + permissions: Permissions + + constructor( + client: Client, + data: MemberPayload, + user: User, + guild: Guild, + perms?: Permissions + ) { + super(client) + this.id = data.user.id + this.user = user + this.nick = data.nick + this.guild = guild + this.roles = new MemberRolesManager(this.client, this.guild.roles, this) + this.joinedAt = data.joined_at + this.premiumSince = data.premium_since + this.deaf = data.deaf + this.mute = data.mute + if (perms !== undefined) this.permissions = perms + else this.permissions = new Permissions(Permissions.DEFAULT) + } + + get displayName(): string { + return this.nick !== undefined ? this.nick : this.user.username + } + + toString(): string { + return this.user.nickMention + } + + protected readFromData(data: MemberPayload): void { + super.readFromData(data.user) + this.nick = data.nick ?? this.nick + this.joinedAt = data.joined_at ?? this.joinedAt + this.premiumSince = data.premium_since ?? this.premiumSince + this.deaf = data.deaf ?? this.deaf + this.mute = data.mute ?? this.mute + } + + /** + * Update the Member data in cache (and this object). + */ + async fetch(): Promise { + const raw = await this.client.rest.get(this.id) + if (typeof raw !== 'object') throw new Error('Member not found') + await this.guild.members.set(this.id, raw) + this.readFromData(raw) + return this + } + + /** + * Edit the Member + * @param data Data to apply + */ + async edit(data: MemberData): Promise { + const payload = { + nick: data.nick, + roles: data.roles?.map((e) => (typeof e === 'string' ? e : e.id)), + deaf: data.deaf, + mute: data.mute + } + const res = await this.client.rest.patch( + GUILD_MEMBER(this.guild.id, this.id), + payload, + undefined, + null, + true + ) + if (res.ok === true) { + if (data.nick !== undefined) + this.nick = data.nick === null ? undefined : data.nick + if (data.deaf !== undefined) this.deaf = data.deaf + if (data.mute !== undefined) this.mute = data.mute + } + return this + } + + /** + * New nickname to set. If empty, nick is reset + * @param nick New nickname + */ + async setNickname(nick?: string): Promise { + return await this.edit({ + nick: nick === undefined ? null : nick + }) + } + + /** + * Reset nickname of the Member + */ + async resetNickname(): Promise { + return await this.setNickname() + } + + /** + * Set mute of a Member in VC + * @param mute Value to set + */ + async setMute(mute?: boolean): Promise { + return await this.edit({ + mute: mute === undefined ? false : mute + }) + } + + /** + * Set deaf of a Member in VC + * @param deaf Value to set + */ + async setDeaf(deaf?: boolean): Promise { + return await this.edit({ + deaf: deaf === undefined ? false : deaf + }) + } + + /** + * Unmute the Member from VC. + */ + async unmute(): Promise { + return await this.setMute(false) + } + + /** + * Kick the member. + */ + async kick(): Promise { + const resp = await this.client.rest.delete( + GUILD_MEMBER(this.guild.id, this.id), + undefined, + undefined, + null, + true + ) + if (resp.ok !== true) return false + else return true + } + + /** + * Ban the Member. + * @param reason Reason for the Ban. + * @param deleteMessagesDays Delete Old Messages? If yes, how much days. + */ + async ban(reason?: string, deleteOldMessages?: number): Promise { + return this.guild.bans.add(this.id, reason, deleteOldMessages) + } +} diff --git a/src/structures/message.ts b/src/structures/message.ts index 4ede4866..1a57a744 100644 --- a/src/structures/message.ts +++ b/src/structures/message.ts @@ -1,129 +1,129 @@ -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 { - 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 { - return this.channel.send(text, option, this) - } - - /** Delete the Message. */ - async delete(): Promise { - 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 { + 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 { + return this.channel.send(text, option, this) + } + + /** Delete the Message. */ + async delete(): Promise { + return this.client.rest.delete(CHANNEL_MESSAGE(this.channelID, this.id)) + } +} diff --git a/src/structures/messageMentions.ts b/src/structures/messageMentions.ts index 56e11975..50e3c161 100644 --- a/src/structures/messageMentions.ts +++ b/src/structures/messageMentions.ts @@ -1,63 +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 = new Collection() - roles: Collection = new Collection() - channels: Collection = 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 { - 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( - 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( - 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 = new Collection() + roles: Collection = new Collection() + channels: Collection = 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 { + 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( + 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( + parsedID + ) + if (channel !== undefined) this.channels.set(channel.id, channel) + } + } + this.everyone = payload.mention_everyone + return this + } +} diff --git a/src/structures/messageReaction.ts b/src/structures/messageReaction.ts index b20baf16..285c52a6 100644 --- a/src/structures/messageReaction.ts +++ b/src/structures/messageReaction.ts @@ -1,28 +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 - } -} +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 + } +} diff --git a/src/structures/presence.ts b/src/structures/presence.ts index 65b84bea..2ab724d6 100644 --- a/src/structures/presence.ts +++ b/src/structures/presence.ts @@ -3,7 +3,7 @@ import { ActivityPayload, ClientActivity, ClientStatus, - StatusType, + StatusType } from '../types/presence.ts' import { PresenceUpdatePayload, StatusUpdatePayload } from '../types/gateway.ts' import { Base } from './base.ts' @@ -17,7 +17,7 @@ enum ActivityTypes { LISTENING = 2, WATCHING = 3, CUSTOM_STATUS = 4, - COMPETING = 5, + COMPETING = 5 } export class Presence extends Base { @@ -88,7 +88,7 @@ export class ClientPresence { afk: this.afk === undefined ? false : this.afk, activities: this.createActivity(), since: this.since === undefined ? null : this.since, - status: this.status === undefined ? 'online' : this.status, + status: this.status === undefined ? 'online' : this.status } } diff --git a/src/structures/role.ts b/src/structures/role.ts index 903fc384..f670cfaa 100644 --- a/src/structures/role.ts +++ b/src/structures/role.ts @@ -1,7 +1,7 @@ import { Client } from '../models/client.ts' import { Base } from './base.ts' import { RolePayload } from '../types/role.ts' -import { Permissions } from "../utils/permissions.ts" +import { Permissions } from '../utils/permissions.ts' export class Role extends Base { id: string @@ -13,13 +13,15 @@ export class Role extends Base { managed: boolean mentionable: boolean - get mention (): string { + get mention(): string { return `<@&${this.id}>` } - toString(): string { return this.mention } + toString(): string { + return this.mention + } - constructor (client: Client, data: RolePayload) { + constructor(client: Client, data: RolePayload) { super(client, data) this.id = data.id this.name = data.name @@ -31,13 +33,16 @@ export class Role extends Base { this.mentionable = data.mentionable } - protected readFromData (data: RolePayload): void { + protected readFromData(data: RolePayload): void { super.readFromData(data) this.name = data.name ?? this.name this.color = data.color ?? this.color this.hoist = data.hoist ?? this.hoist this.position = data.position ?? this.position - this.permissions = new Permissions(data.permissions) ?? this.permissions + this.permissions = + data.permissions !== undefined + ? new Permissions(data.permissions) + : this.permissions this.managed = data.managed ?? this.managed this.mentionable = data.mentionable ?? this.mentionable } diff --git a/src/structures/snowflake.ts b/src/structures/snowflake.ts index f0788a7c..a88d5f8d 100644 --- a/src/structures/snowflake.ts +++ b/src/structures/snowflake.ts @@ -1,22 +1,22 @@ export class Snowflake { snowflake: bigint - constructor (id: string) { + constructor(id: string) { this.snowflake = BigInt.asUintN(64, BigInt(id)) } - get timestamp (): string { + get timestamp(): string { return ((this.snowflake >> 22n) + 1420070400000n).toString() } - get workerID (): string { + get workerID(): string { return ((this.snowflake & 0x3e0000n) >> 17n).toString() } - get processID (): string { + get processID(): string { return ((this.snowflake & 0x1f00n) >> 12n).toString() } - get increment (): string { + get increment(): string { return (this.snowflake & 0xfffn).toString() } } diff --git a/src/structures/textChannel.ts b/src/structures/textChannel.ts index cc85b110..db0ffec7 100644 --- a/src/structures/textChannel.ts +++ b/src/structures/textChannel.ts @@ -1,156 +1,167 @@ -import { MessagesManager } from "../../mod.ts" -import { Client } from '../models/client.ts' -import { GuildTextChannelPayload, MessageOption, MessageReference, Overwrite, TextChannelPayload } from '../types/channel.ts' -import { CHANNEL_MESSAGE, CHANNEL_MESSAGES } from '../types/endpoint.ts' -import { Channel } from './channel.ts' -import { Embed } from './embed.ts' -import { Guild } from "./guild.ts" -import { Message } from './message.ts' - -export type AllMessageOptions = MessageOption | Embed - -export class TextChannel extends Channel { - lastMessageID?: string - lastPinTimestamp?: string - messages: MessagesManager - - constructor(client: Client, data: TextChannelPayload) { - super(client, data) - this.messages = new MessagesManager(this.client, this) - this.lastMessageID = data.last_message_id - this.lastPinTimestamp = data.last_pin_timestamp - } - - protected readFromData(data: TextChannelPayload): void { - super.readFromData(data) - this.lastMessageID = data.last_message_id ?? this.lastMessageID - this.lastPinTimestamp = data.last_pin_timestamp ?? this.lastPinTimestamp - } - - /** - * - * @param text Text content of the Message to send. - * @param option Various other Message options. - * @param reply Reference to a Message object to reply-to. - */ - async send(text?: string | AllMessageOptions, option?: AllMessageOptions, reply?: Message): Promise { - if (typeof text === "object") { - option = text - text = undefined - } - if (text === undefined && option === undefined) { - throw new Error('Either text or option is necessary.') - } - if (option instanceof Embed) option = { - embed: option - } - - const payload: any = { - content: text, - embed: option?.embed, - file: option?.file, - tts: option?.tts, - allowed_mentions: option?.allowedMentions - } - - if (reply !== undefined) { - const reference: MessageReference = { - message_id: reply.id, - channel_id: reply.channel.id, - guild_id: reply.guild?.id, - } - payload.message_reference = reference - } - - const resp = await this.client.rest.post(CHANNEL_MESSAGES(this.id), payload) - - const res = new Message(this.client, resp, this, this.client.user as any) - await res.mentions.fromPayload(resp) - return res - } - - /** - * - * @param message Message to edit. ID or the Message object itself. - * @param text New text contents of the Message. - * @param option Other options to edit the message. - */ - async editMessage( - message: Message | string, - text?: string, - option?: MessageOption - ): Promise { - if (text === undefined && option === undefined) { - throw new Error('Either text or option is necessary.') - } - - if (this.client.user === undefined) { - throw new Error('Client user has not initialized.') - } - - const newMsg = await this.client.rest.patch( - CHANNEL_MESSAGE( - this.id, - typeof message === 'string' ? message : message.id - ), - { - content: text, - embed: option?.embed !== undefined ? option.embed.toJSON() : undefined, - // Cannot upload new files with Message - // file: option?.file, - tts: option?.tts, - allowed_mentions: option?.allowedMentions - } - ) - - const res = new Message(this.client, newMsg, this, this.client.user) - await res.mentions.fromPayload(newMsg) - return res - } -} - -export class GuildTextChannel extends TextChannel { - guildID: string - name: string - position: number - permissionOverwrites: Overwrite[] - nsfw: boolean - parentID?: string - rateLimit: number - topic?: string - guild: Guild - - get mention(): string { - return `<#${this.id}>` - } - - toString(): string { - return this.mention - } - - constructor(client: Client, data: GuildTextChannelPayload, guild: Guild) { - super(client, data) - this.guildID = data.guild_id - this.name = data.name - this.guild = guild - this.position = data.position - this.permissionOverwrites = data.permission_overwrites - this.nsfw = data.nsfw - this.parentID = data.parent_id - this.topic = data.topic - this.rateLimit = data.rate_limit_per_user - } - - protected readFromData(data: GuildTextChannelPayload): void { - super.readFromData(data) - this.guildID = data.guild_id ?? this.guildID - this.name = data.name ?? this.name - this.position = data.position ?? this.position - this.permissionOverwrites = - data.permission_overwrites ?? this.permissionOverwrites - this.nsfw = data.nsfw ?? this.nsfw - this.parentID = data.parent_id ?? this.parentID - this.topic = data.topic ?? this.topic - this.rateLimit = data.rate_limit_per_user ?? this.rateLimit - } -} +import { MessagesManager } from '../managers/messages.ts' +import { Client } from '../models/client.ts' +import { + GuildTextChannelPayload, + MessageOption, + MessageReference, + Overwrite, + TextChannelPayload +} from '../types/channel.ts' +import { CHANNEL_MESSAGE, CHANNEL_MESSAGES } from '../types/endpoint.ts' +import { Channel } from './channel.ts' +import { Embed } from './embed.ts' +import { Guild } from './guild.ts' +import { Message } from './message.ts' + +export type AllMessageOptions = MessageOption | Embed + +export class TextChannel extends Channel { + lastMessageID?: string + lastPinTimestamp?: string + messages: MessagesManager + + constructor(client: Client, data: TextChannelPayload) { + super(client, data) + this.messages = new MessagesManager(this.client, this) + this.lastMessageID = data.last_message_id + this.lastPinTimestamp = data.last_pin_timestamp + } + + protected readFromData(data: TextChannelPayload): void { + super.readFromData(data) + this.lastMessageID = data.last_message_id ?? this.lastMessageID + this.lastPinTimestamp = data.last_pin_timestamp ?? this.lastPinTimestamp + } + + /** + * + * @param text Text content of the Message to send. + * @param option Various other Message options. + * @param reply Reference to a Message object to reply-to. + */ + async send( + text?: string | AllMessageOptions, + option?: AllMessageOptions, + reply?: Message + ): Promise { + if (typeof text === 'object') { + option = text + text = undefined + } + if (text === undefined && option === undefined) { + throw new Error('Either text or option is necessary.') + } + if (option instanceof Embed) + option = { + embed: option + } + + const payload: any = { + content: text, + embed: option?.embed, + file: option?.file, + tts: option?.tts, + allowed_mentions: option?.allowedMentions + } + + if (reply !== undefined) { + const reference: MessageReference = { + message_id: reply.id, + channel_id: reply.channel.id, + guild_id: reply.guild?.id + } + payload.message_reference = reference + } + + const resp = await this.client.rest.post(CHANNEL_MESSAGES(this.id), payload) + + const res = new Message(this.client, resp, this, this.client.user as any) + await res.mentions.fromPayload(resp) + return res + } + + /** + * + * @param message Message to edit. ID or the Message object itself. + * @param text New text contents of the Message. + * @param option Other options to edit the message. + */ + async editMessage( + message: Message | string, + text?: string, + option?: MessageOption + ): Promise { + if (text === undefined && option === undefined) { + throw new Error('Either text or option is necessary.') + } + + if (this.client.user === undefined) { + throw new Error('Client user has not initialized.') + } + + const newMsg = await this.client.rest.patch( + CHANNEL_MESSAGE( + this.id, + typeof message === 'string' ? message : message.id + ), + { + content: text, + embed: option?.embed !== undefined ? option.embed.toJSON() : undefined, + // Cannot upload new files with Message + // file: option?.file, + tts: option?.tts, + allowed_mentions: option?.allowedMentions + } + ) + + const res = new Message(this.client, newMsg, this, this.client.user) + await res.mentions.fromPayload(newMsg) + return res + } +} + +export class GuildTextChannel extends TextChannel { + guildID: string + name: string + position: number + permissionOverwrites: Overwrite[] + nsfw: boolean + parentID?: string + rateLimit: number + topic?: string + guild: Guild + + get mention(): string { + return `<#${this.id}>` + } + + toString(): string { + return this.mention + } + + constructor(client: Client, data: GuildTextChannelPayload, guild: Guild) { + super(client, data) + this.guildID = data.guild_id + this.name = data.name + this.guild = guild + this.position = data.position + this.permissionOverwrites = data.permission_overwrites + this.nsfw = data.nsfw + this.parentID = data.parent_id + this.topic = data.topic + this.rateLimit = data.rate_limit_per_user + } + + protected readFromData(data: GuildTextChannelPayload): void { + super.readFromData(data) + this.guildID = data.guild_id ?? this.guildID + this.name = data.name ?? this.name + this.position = data.position ?? this.position + this.permissionOverwrites = + data.permission_overwrites ?? this.permissionOverwrites + this.nsfw = data.nsfw ?? this.nsfw + this.parentID = data.parent_id ?? this.parentID + this.topic = data.topic ?? this.topic + this.rateLimit = data.rate_limit_per_user ?? this.rateLimit + } +} diff --git a/src/structures/user.ts b/src/structures/user.ts index 56a5339b..c0b002bc 100644 --- a/src/structures/user.ts +++ b/src/structures/user.ts @@ -1,76 +1,80 @@ -import { Client } from '../models/client.ts' -import { UserPayload } from '../types/user.ts' -import { UserFlagsManager } from "../utils/userFlags.ts" -import { Base } from './base.ts' - -export class User extends Base { - id: string - username: string - discriminator: string - avatar?: string - bot?: boolean - system?: boolean - mfaEnabled?: boolean - locale?: string - verified?: boolean - email?: string - flags?: UserFlagsManager - /** - * Nitro type of the User. - * - * 0 = No Nitro - * 1 = Classic Nitro - * 2 = Regular Nitro - */ - premiumType?: 0 | 1 | 2 - publicFlags?: UserFlagsManager - - get tag (): string { - return `${this.username}#${this.discriminator}` - } - - get nickMention (): string { - return `<@!${this.id}>` - } - - get mention (): string { - return `<@${this.id}>` - } - - constructor (client: Client, data: UserPayload) { - super(client, data) - this.id = data.id - this.username = data.username - this.discriminator = data.discriminator - this.avatar = data.avatar - this.bot = data.bot - this.system = data.system - this.mfaEnabled = data.mfa_enabled - this.locale = data.locale - this.verified = data.verified - this.email = data.email - this.flags = new UserFlagsManager(data.flags) - this.premiumType = data.premium_type - this.publicFlags = new UserFlagsManager(data.public_flags) - } - - protected readFromData (data: UserPayload): void { - super.readFromData(data) - this.username = data.username ?? this.username - this.discriminator = data.discriminator ?? this.discriminator - this.avatar = data.avatar ?? this.avatar - this.bot = data.bot ?? this.bot - this.system = data.system ?? this.system - this.mfaEnabled = data.mfa_enabled ?? this.mfaEnabled - this.locale = data.locale ?? this.locale - this.verified = data.verified ?? this.verified - this.email = data.email ?? this.email - this.flags = new UserFlagsManager(data.flags) ?? this.flags - this.premiumType = data.premium_type ?? this.premiumType - this.publicFlags = new UserFlagsManager(data.public_flags) ?? this.publicFlags - } - - toString (): string { - return this.mention - } -} +import { Client } from '../models/client.ts' +import { UserPayload } from '../types/user.ts' +import { UserFlagsManager } from '../utils/userFlags.ts' +import { Base } from './base.ts' + +export class User extends Base { + id: string + username: string + discriminator: string + avatar?: string + bot?: boolean + system?: boolean + mfaEnabled?: boolean + locale?: string + verified?: boolean + email?: string + flags: UserFlagsManager + /** + * Nitro type of the User. + * + * 0 = No Nitro + * 1 = Classic Nitro + * 2 = Regular Nitro + */ + premiumType?: 0 | 1 | 2 + publicFlags: UserFlagsManager + + get tag(): string { + return `${this.username}#${this.discriminator}` + } + + get nickMention(): string { + return `<@!${this.id}>` + } + + get mention(): string { + return `<@${this.id}>` + } + + constructor(client: Client, data: UserPayload) { + super(client, data) + this.id = data.id + this.username = data.username + this.discriminator = data.discriminator + this.avatar = data.avatar + this.bot = data.bot + this.system = data.system + this.mfaEnabled = data.mfa_enabled + this.locale = data.locale + this.verified = data.verified + this.email = data.email + this.flags = new UserFlagsManager(data.flags) + this.premiumType = data.premium_type + this.publicFlags = new UserFlagsManager(data.public_flags) + } + + protected readFromData(data: UserPayload): void { + super.readFromData(data) + this.username = data.username ?? this.username + this.discriminator = data.discriminator ?? this.discriminator + this.avatar = data.avatar ?? this.avatar + this.bot = data.bot ?? this.bot + this.system = data.system ?? this.system + this.mfaEnabled = data.mfa_enabled ?? this.mfaEnabled + this.locale = data.locale ?? this.locale + this.verified = data.verified ?? this.verified + this.email = data.email ?? this.email + this.flags = + data.flags !== undefined ? new UserFlagsManager(data.flags) : this.flags + this.premiumType = data.premium_type ?? this.premiumType + this.publicFlags = + data.public_flags !== undefined + ? new UserFlagsManager(data.public_flags) + : this.publicFlags + } + + toString(): string { + return this.mention + } +} diff --git a/src/structures/voiceState.ts b/src/structures/voiceState.ts index 026d5dda..ece11286 100644 --- a/src/structures/voiceState.ts +++ b/src/structures/voiceState.ts @@ -1,53 +1,57 @@ -import { Client } from '../models/client.ts' -import { VoiceStatePayload } from '../types/voice.ts' -import { Base } from './base.ts' -import { Guild } from "./guild.ts" -import { VoiceChannel } from "./guildVoiceChannel.ts" -import { Member } from "./member.ts" -import { User } from "./user.ts" - -export class VoiceState extends Base { - guild?: Guild - channel: VoiceChannel | null - user: User - member?: Member - sessionID: string - deaf: boolean - mute: boolean - stream?: boolean - video: boolean - suppress: boolean - - constructor (client: Client, data: VoiceStatePayload, _data: { - user: User, - channel: VoiceChannel | null, - member?: Member, - guild?: Guild - }) { - super(client, data) - this.channel = _data.channel - this.sessionID = data.session_id - this.user = _data.user - this.member = _data.member - this.guild = _data.guild - this.deaf = data.deaf - this.mute = data.mute - this.deaf = data.self_deaf - this.mute = data.self_mute - this.stream = data.self_stream - this.video = data.self_video - this.suppress = data.suppress - } - - protected readFromData (data: VoiceStatePayload): void { - super.readFromData(data) - this.sessionID = data.session_id ?? this.sessionID - this.deaf = data.deaf ?? this.deaf - this.mute = data.mute ?? this.mute - this.deaf = data.self_deaf ?? this.deaf - this.mute = data.self_mute ?? this.mute - this.stream = data.self_stream ?? this.stream - this.video = data.self_video ?? this.video - this.suppress = data.suppress ?? this.suppress - } -} +import { Client } from '../models/client.ts' +import { VoiceStatePayload } from '../types/voice.ts' +import { Base } from './base.ts' +import { Guild } from './guild.ts' +import { VoiceChannel } from './guildVoiceChannel.ts' +import { Member } from './member.ts' +import { User } from './user.ts' + +export class VoiceState extends Base { + guild?: Guild + channel: VoiceChannel | null + user: User + member?: Member + sessionID: string + deaf: boolean + mute: boolean + stream?: boolean + video: boolean + suppress: boolean + + constructor( + client: Client, + data: VoiceStatePayload, + _data: { + user: User + channel: VoiceChannel | null + member?: Member + guild?: Guild + } + ) { + super(client, data) + this.channel = _data.channel + this.sessionID = data.session_id + this.user = _data.user + this.member = _data.member + this.guild = _data.guild + this.deaf = data.deaf + this.mute = data.mute + this.deaf = data.self_deaf + this.mute = data.self_mute + this.stream = data.self_stream + this.video = data.self_video + this.suppress = data.suppress + } + + protected readFromData(data: VoiceStatePayload): void { + super.readFromData(data) + this.sessionID = data.session_id ?? this.sessionID + this.deaf = data.deaf ?? this.deaf + this.mute = data.mute ?? this.mute + this.deaf = data.self_deaf ?? this.deaf + this.mute = data.self_mute ?? this.mute + this.stream = data.self_stream ?? this.stream + this.video = data.self_video ?? this.video + this.suppress = data.suppress ?? this.suppress + } +} diff --git a/src/structures/webhook.ts b/src/structures/webhook.ts index 2384abee..8adca66b 100644 --- a/src/structures/webhook.ts +++ b/src/structures/webhook.ts @@ -1,194 +1,194 @@ -import { - DISCORD_API_URL, - DISCORD_API_VERSION -} from '../consts/urlsAndVersions.ts' -import { Client } from '../models/client.ts' -import { RESTManager } from '../models/rest.ts' -import { MessageOption } from '../types/channel.ts' -import { UserPayload } from '../types/user.ts' -import { WebhookPayload } from '../types/webhook.ts' -import { Embed } from './embed.ts' -import { Message } from './message.ts' -import { TextChannel } from './textChannel.ts' -import { User } from './user.ts' -import { fetchAuto } from 'https://raw.githubusercontent.com/DjDeveloperr/fetch-base64/main/mod.ts' - -export interface WebhookMessageOptions extends MessageOption { - embeds?: Embed[] - name?: string - avatar?: string -} - -export type AllWebhookMessageOptions = string | WebhookMessageOptions - -export interface WebhookEditOptions { - /** New name to set for Webhook. */ - name?: string - /** New avatar to set for Webhook. URL of image or base64 encoded data. */ - avatar?: string - /** New channel for Webhook. Requires authentication. */ - channelID?: string -} - -/** Webhook follows different way of instantiation */ -export class Webhook { - client?: Client - id: string - type: 1 | 2 - guildID?: string - channelID: string - user?: User - userRaw?: UserPayload - name?: string - avatar?: string - token?: string - applicationID?: string - rest: RESTManager - - get url (): string { - return `${DISCORD_API_URL}/v${DISCORD_API_VERSION}/webhooks/${this.id}/${this.token}` - } - - constructor (data: WebhookPayload, client?: Client, rest?: RESTManager) { - this.id = data.id - this.type = data.type - this.channelID = data.channel_id - this.guildID = data.guild_id - this.user = - data.user === undefined || client === undefined - ? undefined - : new User(client, data.user) - if (data.user !== undefined && client === undefined) - this.userRaw = data.user - this.name = data.name - this.avatar = data.avatar - this.token = data.token - this.applicationID = data.application_id - - if (rest !== undefined) this.rest = rest - else if (client !== undefined) this.rest = client.rest - else this.rest = new RESTManager() - } - - private fromPayload (data: WebhookPayload): Webhook { - this.id = data.id - this.type = data.type - this.channelID = data.channel_id - this.guildID = data.guild_id - this.user = - data.user === undefined || this.client === undefined - ? undefined - : new User(this.client, data.user) - if (data.user !== undefined && this.client === undefined) - this.userRaw = data.user - this.name = data.name - this.avatar = data.avatar - this.token = data.token - this.applicationID = data.application_id - - return this - } - - /** Send a Message through Webhook. */ - async send ( - text?: string | AllWebhookMessageOptions, - option?: AllWebhookMessageOptions - ): Promise { - if (typeof text === 'object') { - option = text - text = undefined - } - - if (text === undefined && option === undefined) { - throw new Error('Either text or option is necessary.') - } - - if (option instanceof Embed) - option = { - embeds: [option] - } - - const payload: any = { - content: text, - embeds: - (option as WebhookMessageOptions)?.embed !== undefined - ? [(option as WebhookMessageOptions).embed] - : (option as WebhookMessageOptions)?.embeds !== undefined - ? (option as WebhookMessageOptions).embeds - : undefined, - file: (option as WebhookMessageOptions)?.file, - tts: (option as WebhookMessageOptions)?.tts, - allowed_mentions: (option as WebhookMessageOptions)?.allowedMentions - } - - if ((option as WebhookMessageOptions)?.name !== undefined) { - payload.username = (option as WebhookMessageOptions)?.name - } - - if ((option as WebhookMessageOptions)?.avatar !== undefined) { - payload.avatar = (option as WebhookMessageOptions)?.avatar - } - - if ( - payload.embeds !== undefined && - payload.embeds instanceof Array && - payload.embeds.length > 10 - ) - throw new Error(`Cannot send more than 10 embeds through Webhook`) - - const resp = await this.rest.post(this.url + '?wait=true', payload) - - const res = new Message( - this.client as Client, - resp, - (this as unknown) as TextChannel, - (this as unknown) as User - ) - await res.mentions.fromPayload(resp) - return res - } - - /** - * Create a Webhook object from URL - * @param url URL of the Webhook - * @param client Client (bot) object, if any. - */ - static async fromURL (url: string | URL, client?: Client): Promise { - const rest = client !== undefined ? client.rest : new RESTManager() - - const raw = await rest.get(typeof url === 'string' ? url : url.toString()) - if (typeof raw !== 'object') - throw new Error(`Failed to load Webhook from URL: ${url}`) - - const webhook = new Webhook(raw, client, rest) - return webhook - } - - /** - * Edit the Webhook name, avatar, or channel (requires authentication). - * @param options Options to edit the Webhook. - */ - async edit (options: WebhookEditOptions): Promise { - if (options.channelID !== undefined && this.rest.client === undefined) - throw new Error('Authentication is required for editing Webhook Channel') - if ( - options.avatar !== undefined && - (options.avatar.startsWith('http:') || - options.avatar.startsWith('https:')) - ) { - options.avatar = await fetchAuto(options.avatar) - } - - const data = await this.rest.patch(this.url, options) - this.fromPayload(data) - - return this - } - - /** Delete the Webhook. */ - async delete (): Promise { - const resp = await this.rest.delete(this.url, undefined, 0, undefined, true) - if (resp.response.status !== 204) return false - else return true - } -} +import { + DISCORD_API_URL, + DISCORD_API_VERSION +} from '../consts/urlsAndVersions.ts' +import { Client } from '../models/client.ts' +import { RESTManager } from '../models/rest.ts' +import { MessageOption } from '../types/channel.ts' +import { UserPayload } from '../types/user.ts' +import { WebhookPayload } from '../types/webhook.ts' +import { Embed } from './embed.ts' +import { Message } from './message.ts' +import { TextChannel } from './textChannel.ts' +import { User } from './user.ts' +import { fetchAuto } from 'https://raw.githubusercontent.com/DjDeveloperr/fetch-base64/main/mod.ts' + +export interface WebhookMessageOptions extends MessageOption { + embeds?: Embed[] + name?: string + avatar?: string +} + +export type AllWebhookMessageOptions = string | WebhookMessageOptions + +export interface WebhookEditOptions { + /** New name to set for Webhook. */ + name?: string + /** New avatar to set for Webhook. URL of image or base64 encoded data. */ + avatar?: string + /** New channel for Webhook. Requires authentication. */ + channelID?: string +} + +/** Webhook follows different way of instantiation */ +export class Webhook { + client?: Client + id: string + type: 1 | 2 + guildID?: string + channelID: string + user?: User + userRaw?: UserPayload + name?: string + avatar?: string + token?: string + applicationID?: string + rest: RESTManager + + get url(): string { + return `${DISCORD_API_URL}/v${DISCORD_API_VERSION}/webhooks/${this.id}/${this.token}` + } + + constructor(data: WebhookPayload, client?: Client, rest?: RESTManager) { + this.id = data.id + this.type = data.type + this.channelID = data.channel_id + this.guildID = data.guild_id + this.user = + data.user === undefined || client === undefined + ? undefined + : new User(client, data.user) + if (data.user !== undefined && client === undefined) + this.userRaw = data.user + this.name = data.name + this.avatar = data.avatar + this.token = data.token + this.applicationID = data.application_id + + if (rest !== undefined) this.rest = rest + else if (client !== undefined) this.rest = client.rest + else this.rest = new RESTManager() + } + + private fromPayload(data: WebhookPayload): Webhook { + this.id = data.id + this.type = data.type + this.channelID = data.channel_id + this.guildID = data.guild_id + this.user = + data.user === undefined || this.client === undefined + ? undefined + : new User(this.client, data.user) + if (data.user !== undefined && this.client === undefined) + this.userRaw = data.user + this.name = data.name + this.avatar = data.avatar + this.token = data.token + this.applicationID = data.application_id + + return this + } + + /** Send a Message through Webhook. */ + async send( + text?: string | AllWebhookMessageOptions, + option?: AllWebhookMessageOptions + ): Promise { + if (typeof text === 'object') { + option = text + text = undefined + } + + if (text === undefined && option === undefined) { + throw new Error('Either text or option is necessary.') + } + + if (option instanceof Embed) + option = { + embeds: [option] + } + + const payload: any = { + content: text, + embeds: + (option as WebhookMessageOptions)?.embed !== undefined + ? [(option as WebhookMessageOptions).embed] + : (option as WebhookMessageOptions)?.embeds !== undefined + ? (option as WebhookMessageOptions).embeds + : undefined, + file: (option as WebhookMessageOptions)?.file, + tts: (option as WebhookMessageOptions)?.tts, + allowed_mentions: (option as WebhookMessageOptions)?.allowedMentions + } + + if ((option as WebhookMessageOptions)?.name !== undefined) { + payload.username = (option as WebhookMessageOptions)?.name + } + + if ((option as WebhookMessageOptions)?.avatar !== undefined) { + payload.avatar = (option as WebhookMessageOptions)?.avatar + } + + if ( + payload.embeds !== undefined && + payload.embeds instanceof Array && + payload.embeds.length > 10 + ) + throw new Error(`Cannot send more than 10 embeds through Webhook`) + + const resp = await this.rest.post(this.url + '?wait=true', payload) + + const res = new Message( + this.client as Client, + resp, + (this as unknown) as TextChannel, + (this as unknown) as User + ) + await res.mentions.fromPayload(resp) + return res + } + + /** + * Create a Webhook object from URL + * @param url URL of the Webhook + * @param client Client (bot) object, if any. + */ + static async fromURL(url: string | URL, client?: Client): Promise { + const rest = client !== undefined ? client.rest : new RESTManager() + + const raw = await rest.get(typeof url === 'string' ? url : url.toString()) + if (typeof raw !== 'object') + throw new Error(`Failed to load Webhook from URL: ${url}`) + + const webhook = new Webhook(raw, client, rest) + return webhook + } + + /** + * Edit the Webhook name, avatar, or channel (requires authentication). + * @param options Options to edit the Webhook. + */ + async edit(options: WebhookEditOptions): Promise { + if (options.channelID !== undefined && this.rest.client === undefined) + throw new Error('Authentication is required for editing Webhook Channel') + if ( + options.avatar !== undefined && + (options.avatar.startsWith('http:') || + options.avatar.startsWith('https:')) + ) { + options.avatar = await fetchAuto(options.avatar) + } + + const data = await this.rest.patch(this.url, options) + this.fromPayload(data) + + return this + } + + /** Delete the Webhook. */ + async delete(): Promise { + const resp = await this.rest.delete(this.url, undefined, 0, undefined, true) + if (resp.response.status !== 204) return false + else return true + } +} diff --git a/src/test/cmd.ts b/src/test/cmd.ts index 44772bb1..2530c837 100644 --- a/src/test/cmd.ts +++ b/src/test/cmd.ts @@ -1,165 +1,165 @@ -import { - Command, - CommandClient, - Intents, - GuildChannel, - CommandContext, - Extension, -} from '../../mod.ts' -import { Invite } from '../structures/invite.ts' -import { TOKEN } from './config.ts' - -const client = new CommandClient({ - prefix: ['pls', '!'], - spacesAfterPrefix: true, - mentionPrefix: true, -}) - -client.on('debug', console.log) - -client.on('ready', () => { - console.log(`[Login] Logged in as ${client.user?.tag}!`) -}) - -client.on('messageDelete', (msg) => { - console.log(`Message Deleted: ${msg.id}, ${msg.author.tag}, ${msg.content}`) -}) - -client.on('messageUpdate', (before, after) => { - console.log('Message Update') - console.log(`Before: ${before.author.tag}: ${before.content}`) - console.log(`After: ${after.author.tag}: ${after.content}`) -}) - -client.on('messageUpdateUncached', (msg) => { - console.log(`Message: ${msg.author.tag}: ${msg.content}`) -}) - -client.on('guildMemberAdd', (member) => { - console.log(`Member Join: ${member.user.tag}`) -}) - -client.on('guildMemberRemove', (member) => { - console.log(`Member Leave: ${member.user.tag}`) -}) - -client.on('guildRoleCreate', (role) => { - console.log(`Role Create: ${role.name}`) -}) - -client.on('guildRoleDelete', (role) => { - console.log(`Role Delete: ${role.name}`) -}) - -client.on('guildRoleUpdate', (role, after) => { - console.log(`Role Update: ${role.name}, ${after.name}`) -}) - -client.on('guildIntegrationsUpdate', (guild) => { - console.log(`Guild Integrations Update: ${guild.name}`) -}) - -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}`) -}) - -client.on('inviteDelete', (invite: Invite) => { - console.log(`Invite Delete: ${invite.code}`) -}) - -client.on('inviteDeleteUncached', (invite: Invite) => { - console.log(invite) -}) - -client.on('commandError', console.error) - -class ChannelLog extends Extension { - onChannelCreate(ext: Extension, channel: GuildChannel): void { - console.log(`Channel Created: ${channel.name}`) - } - - load(): void { - this.listen('channelCreate', this.onChannelCreate) - - class Pong extends Command { - name = 'Pong' - - execute(ctx: CommandContext): any { - ctx.message.reply('Ping!') - } - } - - this.commands.add(Pong) - } -} - -client.extensions.load(ChannelLog) - -client.on('messageDeleteBulk', (channel, messages, uncached) => { - console.log( - `=== Message Delete Bulk ===\nMessages: ${messages - .map((m) => m.id) - .join(', ')}\nUncached: ${[...uncached.values()].join(', ')}` - ) -}) - -client.on('channelUpdate', (before, after) => { - console.log( - `Channel Update: ${(before as GuildChannel).name}, ${ - (after as GuildChannel).name - }` - ) -}) - -client.on('typingStart', (user, channel, at, guildData) => { - console.log( - `${user.tag} started typing in ${channel.id} at ${at}${ - guildData !== undefined ? `\nGuild: ${guildData.guild.name}` : '' - }` - ) -}) - -client.on('voiceStateAdd', (state) => { - console.log('VC Join', state) -}) - -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') - -for (const file of files) { - const module = await import(`./cmds/${file.name}`) - // eslint-disable-next-line new-cap - const cmd = new module.default() - client.commands.add(cmd) - console.log(`Loaded command ${cmd.name}!`) -} - -console.log(`Loaded ${client.commands.count} commands!`) - -client.connect(TOKEN, Intents.create(['GUILD_MEMBERS', 'GUILD_PRESENCES'])) +import { + Command, + CommandClient, + Intents, + GuildChannel, + CommandContext, + Extension +} from '../../mod.ts' +import { Invite } from '../structures/invite.ts' +import { TOKEN } from './config.ts' + +const client = new CommandClient({ + prefix: ['pls', '!'], + spacesAfterPrefix: true, + mentionPrefix: true +}) + +client.on('debug', console.log) + +client.on('ready', () => { + console.log(`[Login] Logged in as ${client.user?.tag}!`) +}) + +client.on('messageDelete', (msg) => { + console.log(`Message Deleted: ${msg.id}, ${msg.author.tag}, ${msg.content}`) +}) + +client.on('messageUpdate', (before, after) => { + console.log('Message Update') + console.log(`Before: ${before.author.tag}: ${before.content}`) + console.log(`After: ${after.author.tag}: ${after.content}`) +}) + +client.on('messageUpdateUncached', (msg) => { + console.log(`Message: ${msg.author.tag}: ${msg.content}`) +}) + +client.on('guildMemberAdd', (member) => { + console.log(`Member Join: ${member.user.tag}`) +}) + +client.on('guildMemberRemove', (member) => { + console.log(`Member Leave: ${member.user.tag}`) +}) + +client.on('guildRoleCreate', (role) => { + console.log(`Role Create: ${role.name}`) +}) + +client.on('guildRoleDelete', (role) => { + console.log(`Role Delete: ${role.name}`) +}) + +client.on('guildRoleUpdate', (role, after) => { + console.log(`Role Update: ${role.name}, ${after.name}`) +}) + +client.on('guildIntegrationsUpdate', (guild) => { + console.log(`Guild Integrations Update: ${guild.name}`) +}) + +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}`) +}) + +client.on('inviteDelete', (invite: Invite) => { + console.log(`Invite Delete: ${invite.code}`) +}) + +client.on('inviteDeleteUncached', (invite: Invite) => { + console.log(invite) +}) + +client.on('commandError', console.error) + +class ChannelLog extends Extension { + onChannelCreate(ext: Extension, channel: GuildChannel): void { + console.log(`Channel Created: ${channel.name}`) + } + + load(): void { + this.listen('channelCreate', this.onChannelCreate) + + class Pong extends Command { + name = 'Pong' + + execute(ctx: CommandContext): any { + ctx.message.reply('Ping!') + } + } + + this.commands.add(Pong) + } +} + +client.extensions.load(ChannelLog) + +client.on('messageDeleteBulk', (channel, messages, uncached) => { + console.log( + `=== Message Delete Bulk ===\nMessages: ${messages + .map((m) => m.id) + .join(', ')}\nUncached: ${[...uncached.values()].join(', ')}` + ) +}) + +client.on('channelUpdate', (before, after) => { + console.log( + `Channel Update: ${(before as GuildChannel).name}, ${ + (after as GuildChannel).name + }` + ) +}) + +client.on('typingStart', (user, channel, at, guildData) => { + console.log( + `${user.tag} started typing in ${channel.id} at ${at}${ + guildData !== undefined ? `\nGuild: ${guildData.guild.name}` : '' + }` + ) +}) + +client.on('voiceStateAdd', (state) => { + console.log('VC Join', state) +}) + +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') + +for (const file of files) { + const module = await import(`./cmds/${file.name}`) + // eslint-disable-next-line new-cap + const cmd = new module.default() + client.commands.add(cmd) + console.log(`Loaded command ${cmd.name}!`) +} + +console.log(`Loaded ${client.commands.count} commands!`) + +client.connect(TOKEN, Intents.create(['GUILD_MEMBERS', 'GUILD_PRESENCES'])) diff --git a/src/test/cmds/addemoji.ts b/src/test/cmds/addemoji.ts index e3f5a7b7..9508f355 100644 --- a/src/test/cmds/addemoji.ts +++ b/src/test/cmds/addemoji.ts @@ -3,7 +3,7 @@ import { CommandContext } from '../../models/command.ts' export default class AddEmojiCommand extends Command { name = 'addemoji' - aliases = [ 'ae', 'emojiadd' ] + aliases = ['ae', 'emojiadd'] args = 2 guildOnly = true @@ -12,11 +12,16 @@ export default class AddEmojiCommand extends Command { if (name === undefined) return ctx.message.reply('No name was given!') const url = ctx.argString.slice(name.length).trim() if (url === '') return ctx.message.reply('No URL was given!') - ctx.message.guild?.emojis.create(name, url).then(emoji => { + ctx.message.guild?.emojis + .create(name, url) + .then((emoji) => { if (emoji === undefined) throw new Error('Unknown') - ctx.message.reply(`Successfuly added emoji ${emoji.toString()} ${emoji.name}!`) - }).catch(e => { + ctx.message.reply( + `Successfuly added emoji ${emoji.toString()} ${emoji.name}!` + ) + }) + .catch((e) => { ctx.message.reply(`Failed to add emoji. Reason: ${e.message}`) - }) + }) } -} \ No newline at end of file +} diff --git a/src/test/cmds/mentions.ts b/src/test/cmds/mentions.ts index 63984d50..ce33ee2e 100644 --- a/src/test/cmds/mentions.ts +++ b/src/test/cmds/mentions.ts @@ -2,17 +2,35 @@ import { Command, Embed } from '../../../mod.ts' import { CommandContext } from '../../models/command.ts' export default class PingCommand extends Command { - name = "mentions" - aliases = ["m"] + name = 'mentions' + aliases = ['m'] execute(ctx: CommandContext): void { const embed = new Embed() .setTitle('Mentions') - .addField('Users', `${ctx.message.mentions.users.size === 0 ? `None` : ''}${ctx.message.mentions.users.map(u => u.toString()).join(", ")}`) - .addField('Channels', `${ctx.message.mentions.channels.size === 0 ? `None` : ''}${ctx.message.mentions.channels.map(u => u.toString()).join(", ")}`) - .addField('Roles', `${ctx.message.mentions.roles.size === 0 ? `None` : ''}${ctx.message.mentions.roles.map(u => u.toString()).join(", ")}`) - .addField('Everyone?', ctx.message.mentions.everyone === true ? 'Yes' : 'No') + .addField( + 'Users', + `${ + ctx.message.mentions.users.size === 0 ? `None` : '' + }${ctx.message.mentions.users.map((u) => u.toString()).join(', ')}` + ) + .addField( + 'Channels', + `${ + ctx.message.mentions.channels.size === 0 ? `None` : '' + }${ctx.message.mentions.channels.map((u) => u.toString()).join(', ')}` + ) + .addField( + 'Roles', + `${ + ctx.message.mentions.roles.size === 0 ? `None` : '' + }${ctx.message.mentions.roles.map((u) => u.toString()).join(', ')}` + ) + .addField( + 'Everyone?', + ctx.message.mentions.everyone === true ? 'Yes' : 'No' + ) .setColor(0xff0000) ctx.message.channel.send(embed) } -} \ No newline at end of file +} diff --git a/src/test/cmds/ping.ts b/src/test/cmds/ping.ts index 30b3f675..61981aed 100644 --- a/src/test/cmds/ping.ts +++ b/src/test/cmds/ping.ts @@ -2,9 +2,9 @@ import { Command } from '../../../mod.ts' import { CommandContext } from '../../models/command.ts' export default class PingCommand extends Command { - name = "ping" + name = 'ping' execute(ctx: CommandContext): void { ctx.message.reply(`Pong! Latency: ${ctx.client.ping}ms`) } -} \ No newline at end of file +} diff --git a/src/test/cmds/userinfo.ts b/src/test/cmds/userinfo.ts index 04f6066a..1f1ad60d 100644 --- a/src/test/cmds/userinfo.ts +++ b/src/test/cmds/userinfo.ts @@ -1,20 +1,23 @@ import { Command, Member, CommandContext, Embed } from '../../../mod.ts' export default class UserinfoCommand extends Command { - name = "userinfo" - guildOnly = true - aliases = [ 'u', 'user' ] + name = 'userinfo' + guildOnly = true + aliases = ['u', 'user'] - async execute(ctx: CommandContext): Promise { - const member: Member = ctx.message.member as any - const roles = await member.roles.array() - const embed = new Embed() - .setTitle(`User Info`) - .setAuthor({ name: member.user.tag }) - .addField("ID", member.id) - .addField("Roles", roles.map(r => r.name).join(", ")) - .addField('Permissions', JSON.stringify(member.permissions.has('ADMINISTRATOR'))) - .setColor(0xff00ff) - ctx.channel.send(embed) - } -} \ No newline at end of file + async execute(ctx: CommandContext): Promise { + const member: Member = ctx.message.member as any + const roles = await member.roles.array() + const embed = new Embed() + .setTitle(`User Info`) + .setAuthor({ name: member.user.tag }) + .addField('ID', member.id) + .addField('Roles', roles.map((r) => r.name).join(', ')) + .addField( + 'Permissions', + JSON.stringify(member.permissions.has('ADMINISTRATOR')) + ) + .setColor(0xff00ff) + ctx.channel.send(embed) + } +} diff --git a/src/test/hook.ts b/src/test/hook.ts index 150eb28e..6de3ba57 100644 --- a/src/test/hook.ts +++ b/src/test/hook.ts @@ -1,9 +1,11 @@ -import { Webhook } from '../../mod.ts' -import { WEBHOOK } from "./config.ts" - -const webhook = await Webhook.fromURL(WEBHOOK) -console.log('Fetched webhook!') - -webhook.send('Hello World', { - name: 'OwO' -}).then(() => 'Sent message!') \ No newline at end of file +import { Webhook } from '../../mod.ts' +import { WEBHOOK } from './config.ts' + +const webhook = await Webhook.fromURL(WEBHOOK) +console.log('Fetched webhook!') + +webhook + .send('Hello World', { + name: 'OwO' + }) + .then(() => 'Sent message!') diff --git a/src/test/index.ts b/src/test/index.ts index 7b07a8b2..65c4b959 100644 --- a/src/test/index.ts +++ b/src/test/index.ts @@ -1,11 +1,24 @@ -import { Client, Intents, GuildTextChannel, Message, ClientPresence, Member, Role, GuildChannel, Embed, Guild } from '../../mod.ts' +import { + Client, + Intents, + Message, + ClientPresence, + Member, + Role, + GuildChannel, + Embed, + Guild, + EveryChannelTypes, + ChannelTypes, + GuildTextChannel +} from '../../mod.ts' import { TOKEN } from './config.ts' const client = new Client({ presence: new ClientPresence({ - name: 'Pokémon Sword', - type: 'COMPETING' - }), + name: 'Pokémon Sword', + type: 'COMPETING' + }) // bot: false, // cache: new RedisCacheAdapter({ // hostname: '127.0.0.1', @@ -19,13 +32,19 @@ client.on('ready', () => { client.on('debug', console.log) -client.on('channelUpdate', (before: GuildTextChannel, after: GuildTextChannel) => { - console.log(before.send('', { - embed: new Embed({ - title: 'Channel Update', - description: `Name Before: ${before.name}\nName After: ${after.name}` - }) - })) +client.on('channelUpdate', (b: EveryChannelTypes, a: EveryChannelTypes) => { + if (b.type === ChannelTypes.GUILD_TEXT) { + const before = (b as unknown) as GuildTextChannel + const after = (a as unknown) as GuildTextChannel + console.log( + before.send('', { + embed: new Embed({ + title: 'Channel Update', + description: `Name Before: ${before.name}\nName After: ${after.name}` + }) + }) + ) + } }) client.on('messageCreate', async (msg: Message) => { @@ -35,26 +54,40 @@ client.on('messageCreate', async (msg: Message) => { msg.reply(`Pong! Ping: ${client.ping}ms`) } else if (msg.content === '!members') { const col = await msg.guild?.members.collection() - const data = col?.array().map((c: Member, i: number) => { - return `${i + 1}. ${c.user.tag}` - }).join("\n") as string - msg.channel.send("Member List:\n" + data) + const data = col + ?.array() + .map((c: Member, i: number) => { + return `${i + 1}. ${c.user.tag}` + }) + .join('\n') as string + msg.channel.send('Member List:\n' + data) } else if (msg.content === '!guilds') { const guilds = await msg.client.guilds.collection() - msg.channel.send('Guild List:\n' + (guilds.array().map((c: Guild, i: number) => { - return `${i + 1}. ${c.name} - ${c.memberCount} members` - }).join("\n") as string)) + msg.channel.send( + 'Guild List:\n' + + (guilds + .array() + .map((c: Guild, i: number) => { + return `${i + 1}. ${c.name} - ${c.memberCount} members` + }) + .join('\n') as string) + ) } else if (msg.content === '!roles') { const col = await msg.guild?.roles.collection() - const data = col?.array().map((c: Role, i: number) => { - return `${i + 1}. ${c.name}` - }).join("\n") as string - msg.channel.send("Roles List:\n" + data) + const data = col + ?.array() + .map((c: Role, i: number) => { + return `${i + 1}. ${c.name}` + }) + .join('\n') as string + msg.channel.send('Roles List:\n' + data) } else if (msg.content === '!channels') { const col = await msg.guild?.channels.array() - const data = col?.map((c: GuildChannel, i: number) => { - return `${i + 1}. ${c.name}` - }).join("\n") as string + const data = col + ?.map((c: GuildChannel, i: number) => { + return `${i + 1}. ${c.name}` + }) + .join('\n') as string msg.channel.send('Channels List:\n' + data) } }) diff --git a/src/types/application.ts b/src/types/application.ts index 888de73d..ce3782c7 100644 --- a/src/types/application.ts +++ b/src/types/application.ts @@ -1,10 +1,10 @@ -import { UserPayload } from "./user.ts"; - -export interface ApplicationPayload { - id: string - name: string - icon: string - description: string - summary: string - bot?: UserPayload -} \ No newline at end of file +import { UserPayload } from './user.ts' + +export interface ApplicationPayload { + id: string + name: string + icon: string + description: string + summary: string + bot?: UserPayload +} diff --git a/src/types/cdn.ts b/src/types/cdn.ts index 56e2be2d..4fbfc130 100644 --- a/src/types/cdn.ts +++ b/src/types/cdn.ts @@ -1,2 +1,2 @@ export type ImageSize = 16 | 32 | 64 | 128 | 256 | 512 | 1024 | 2048 -export type ImageFormats = "jpg" | "jpeg" | "png" | "webp" | "gif" \ No newline at end of file +export type ImageFormats = 'jpg' | 'jpeg' | 'png' | 'webp' | 'gif' diff --git a/src/types/gateway.ts b/src/types/gateway.ts index 73854c74..010f1119 100644 --- a/src/types/gateway.ts +++ b/src/types/gateway.ts @@ -8,7 +8,7 @@ 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 { diff --git a/src/types/gatewayBot.ts b/src/types/gatewayBot.ts index f76da8c2..3a030ef3 100644 --- a/src/types/gatewayBot.ts +++ b/src/types/gatewayBot.ts @@ -8,4 +8,4 @@ export interface GatewayBotPayload { url: string shards: number session_start_limit: ISessionStartLimit -} \ No newline at end of file +} diff --git a/src/types/guild.ts b/src/types/guild.ts index 3e7d7a1b..f7fcc016 100644 --- a/src/types/guild.ts +++ b/src/types/guild.ts @@ -1,148 +1,148 @@ -import { ApplicationPayload } from './application.ts' -import { ChannelPayload } from './channel.ts' -import { EmojiPayload } from './emoji.ts' -import { PresenceUpdatePayload } from './gateway.ts' -import { RolePayload } from './role.ts' -import { UserPayload } from './user.ts' -import { VoiceStatePayload } from './voice.ts' - -export interface GuildPayload { - id: string - name: string - icon?: string - icon_hash?: string - splash?: string - discovery_splash?: string - owner?: boolean - owner_id: string - permissions?: string - region: string - afk_channel_id?: string - afk_timeout: number - widget_enabled?: boolean - widget_channel_id?: string - verification_level: string - default_message_notifications: string - explicit_content_filter: string - roles: RolePayload[] - emojis: EmojiPayload[] - features: GuildFeatures[] - mfa_level: string - application_id?: string - system_channel_id?: string - system_channel_flags: string - rules_channel_id?: string - joined_at?: string - large?: boolean - unavailable: boolean - member_count?: number - voice_states?: VoiceStatePayload[] - members?: MemberPayload[] - channels?: ChannelPayload[] - presences?: PresenceUpdatePayload[] - max_presences?: number - max_members?: number - vanity_url_code?: string - description?: string - banner?: string - premium_tier: number - premium_subscription_count?: number - preferred_locale: string - public_updates_channel_id?: string - max_video_channel_users?: number - approximate_number_count?: number - approximate_presence_count?: number -} - -export interface MemberPayload { - user: UserPayload - nick?: string - roles: string[] - joined_at: string - premium_since?: string - deaf: boolean - mute: boolean -} - -export enum MessageNotification { - ALL_MESSAGES = 0, - ONLY_MENTIONS = 1, -} - -export enum ContentFilter { - DISABLED = 0, - MEMBERS_WITHOUT_ROLES = 1, - ALL_MEMBERS = 3, -} - -export enum MFA { - NONE = 0, - ELEVATED = 1, -} - -export enum Verification { - NONE = 0, - LOW = 1, - MEDIUM = 2, - HIGH = 3, - VERY_HIGH = 4, -} - -export enum PremiumTier { - NONE = 0, - TIER_1 = 1, - TIER_2 = 2, - TIER_3 = 3, -} - -export enum SystemChannelFlags { - SUPPRESS_JOIN_NOTIFICATIONS = 1 << 0, - SUPPRESS_PREMIUM_SUBSCRIPTIONS = 1 << 1, -} - -export type GuildFeatures = - | 'INVITE_SPLASH' - | 'VIP_REGIONS' - | 'VANITY_URL' - | 'VERIFIED' - | 'PARTNERED' - | 'PUBLIC' - | 'COMMERCE' - | 'NEWS' - | 'DISCOVERABLE' - | 'FEATURABLE' - | 'ANIMATED_ICON' - | 'BANNER' - -export enum IntegrationExpireBehavior { - REMOVE_ROLE = 0, - KICK = 1, -} - -export interface IntegrationAccountPayload { - id: string - name: string -} - -export interface GuildIntegrationPayload { - id: string - name: string - type: string - enabled: boolean - syncing?: boolean - role_id?: string - enable_emoticons?: boolean - expire_behaviour?: IntegrationExpireBehavior - expire_grace_period?: number - user?: UserPayload - account: IntegrationAccountPayload - synced_at?: string // Actually a ISO Timestamp, but we parse in constructor' - subscriber_count?: number - revoked?: boolean - application?: ApplicationPayload -} - -export interface GuildBanPayload { - reason: string | null - user: UserPayload -} +import { ApplicationPayload } from './application.ts' +import { ChannelPayload } from './channel.ts' +import { EmojiPayload } from './emoji.ts' +import { PresenceUpdatePayload } from './gateway.ts' +import { RolePayload } from './role.ts' +import { UserPayload } from './user.ts' +import { VoiceStatePayload } from './voice.ts' + +export interface GuildPayload { + id: string + name: string + icon?: string + icon_hash?: string + splash?: string + discovery_splash?: string + owner?: boolean + owner_id: string + permissions?: string + region: string + afk_channel_id?: string + afk_timeout: number + widget_enabled?: boolean + widget_channel_id?: string + verification_level: string + default_message_notifications: string + explicit_content_filter: string + roles: RolePayload[] + emojis: EmojiPayload[] + features: GuildFeatures[] + mfa_level: string + application_id?: string + system_channel_id?: string + system_channel_flags: string + rules_channel_id?: string + joined_at?: string + large?: boolean + unavailable: boolean + member_count?: number + voice_states?: VoiceStatePayload[] + members?: MemberPayload[] + channels?: ChannelPayload[] + presences?: PresenceUpdatePayload[] + max_presences?: number + max_members?: number + vanity_url_code?: string + description?: string + banner?: string + premium_tier: number + premium_subscription_count?: number + preferred_locale: string + public_updates_channel_id?: string + max_video_channel_users?: number + approximate_number_count?: number + approximate_presence_count?: number +} + +export interface MemberPayload { + user: UserPayload + nick?: string + roles: string[] + joined_at: string + premium_since?: string + deaf: boolean + mute: boolean +} + +export enum MessageNotification { + ALL_MESSAGES = 0, + ONLY_MENTIONS = 1 +} + +export enum ContentFilter { + DISABLED = 0, + MEMBERS_WITHOUT_ROLES = 1, + ALL_MEMBERS = 3 +} + +export enum MFA { + NONE = 0, + ELEVATED = 1 +} + +export enum Verification { + NONE = 0, + LOW = 1, + MEDIUM = 2, + HIGH = 3, + VERY_HIGH = 4 +} + +export enum PremiumTier { + NONE = 0, + TIER_1 = 1, + TIER_2 = 2, + TIER_3 = 3 +} + +export enum SystemChannelFlags { + SUPPRESS_JOIN_NOTIFICATIONS = 1 << 0, + SUPPRESS_PREMIUM_SUBSCRIPTIONS = 1 << 1 +} + +export type GuildFeatures = + | 'INVITE_SPLASH' + | 'VIP_REGIONS' + | 'VANITY_URL' + | 'VERIFIED' + | 'PARTNERED' + | 'PUBLIC' + | 'COMMERCE' + | 'NEWS' + | 'DISCOVERABLE' + | 'FEATURABLE' + | 'ANIMATED_ICON' + | 'BANNER' + +export enum IntegrationExpireBehavior { + REMOVE_ROLE = 0, + KICK = 1 +} + +export interface IntegrationAccountPayload { + id: string + name: string +} + +export interface GuildIntegrationPayload { + id: string + name: string + type: string + enabled: boolean + syncing?: boolean + role_id?: string + enable_emoticons?: boolean + expire_behaviour?: IntegrationExpireBehavior + expire_grace_period?: number + user?: UserPayload + account: IntegrationAccountPayload + synced_at?: string // Actually a ISO Timestamp, but we parse in constructor' + subscriber_count?: number + revoked?: boolean + application?: ApplicationPayload +} + +export interface GuildBanPayload { + reason: string | null + user: UserPayload +} diff --git a/src/types/permissionFlags.ts b/src/types/permissionFlags.ts index 88b7b036..9cb30409 100644 --- a/src/types/permissionFlags.ts +++ b/src/types/permissionFlags.ts @@ -31,5 +31,5 @@ export const PermissionFlags: { [key: string]: number } = { MANAGE_NICKNAMES: 1 << 27, MANAGE_ROLES: 1 << 28, MANAGE_WEBHOOKS: 1 << 29, - MANAGE_EMOJIS: 1 << 30, -} \ No newline at end of file + MANAGE_EMOJIS: 1 << 30 +} diff --git a/src/types/presence.ts b/src/types/presence.ts index fd81317e..08974888 100644 --- a/src/types/presence.ts +++ b/src/types/presence.ts @@ -56,7 +56,7 @@ export enum ActivityFlags { SPECTATE = 1 << 2, JOIN_REQUEST = 1 << 3, SYNC = 1 << 4, - PLAY = 1 << 5, + PLAY = 1 << 5 } export type ActivityType = diff --git a/src/types/userFlags.ts b/src/types/userFlags.ts index 5858104d..a76dbe86 100644 --- a/src/types/userFlags.ts +++ b/src/types/userFlags.ts @@ -13,4 +13,4 @@ export const UserFlags = { BUGHUNTER_LEVEL_2: 1 << 14, VERIFIED_BOT: 1 << 16, EARLY_VERIFIED_DEVELOPER: 1 << 17 -} \ No newline at end of file +} diff --git a/src/types/voice.ts b/src/types/voice.ts index c796d1cc..455af9e7 100644 --- a/src/types/voice.ts +++ b/src/types/voice.ts @@ -1,45 +1,45 @@ -// https://discord.com/developers/docs/topics/opcodes-and-status-codes#voice -import { MemberPayload } from './guild.ts' - -export enum VoiceOpcodes { // VoiceOpcodes 추가 - UnderC - - IDENTIFY = 0, - SELECT_PROTOCOL = 1, - READY = 2, - HEARTBEAT = 3, - SESSION_DESCRIPTION = 4, - SPEAKING = 6, - HEARTBEAT_ACK = 6, - RESUME = 7, - HELLO = 8, - RESUMED = 9, - CLIENT_DISCONNECT = 13 -} - -export enum VoiceCloseCodes { - UNKNOWN_OPCODE = 4001, - NOT_AUTHENTICATED = 4003, - AUTHENTICATION_FAILED = 4004, - ALREADY_AUTHENTICATED = 4005, - SESSION_NO_LONGER_VALID = 4006, - SESSION_TIMEOUT = 4009, - SERVER_NOT_FOUNT = 4011, - UNKNOWN_PROTOCOL = 4012, - DISCONNECTED = 4014, - VOICE_SERVER_CRASHED = 4015, - UNKNOWN_ENCRYPTION_MODE = 4016 -} - -export interface VoiceStatePayload { - guild_id?: string - channel_id: string | null - user_id: string - member?: MemberPayload - session_id: string - deaf: boolean - mute: boolean - self_deaf: boolean - self_mute: boolean - self_stream?: boolean - self_video: boolean - suppress: boolean -} +// https://discord.com/developers/docs/topics/opcodes-and-status-codes#voice +import { MemberPayload } from './guild.ts' + +export enum VoiceOpcodes { // VoiceOpcodes 추가 - UnderC - + IDENTIFY = 0, + SELECT_PROTOCOL = 1, + READY = 2, + HEARTBEAT = 3, + SESSION_DESCRIPTION = 4, + SPEAKING = 6, + HEARTBEAT_ACK = 6, + RESUME = 7, + HELLO = 8, + RESUMED = 9, + CLIENT_DISCONNECT = 13 +} + +export enum VoiceCloseCodes { + UNKNOWN_OPCODE = 4001, + NOT_AUTHENTICATED = 4003, + AUTHENTICATION_FAILED = 4004, + ALREADY_AUTHENTICATED = 4005, + SESSION_NO_LONGER_VALID = 4006, + SESSION_TIMEOUT = 4009, + SERVER_NOT_FOUNT = 4011, + UNKNOWN_PROTOCOL = 4012, + DISCONNECTED = 4014, + VOICE_SERVER_CRASHED = 4015, + UNKNOWN_ENCRYPTION_MODE = 4016 +} + +export interface VoiceStatePayload { + guild_id?: string + channel_id: string | null + user_id: string + member?: MemberPayload + session_id: string + deaf: boolean + mute: boolean + self_deaf: boolean + self_mute: boolean + self_stream?: boolean + self_video: boolean + suppress: boolean +} diff --git a/src/utils/bitfield.ts b/src/utils/bitfield.ts index 6330d64d..379d53d7 100644 --- a/src/utils/bitfield.ts +++ b/src/utils/bitfield.ts @@ -19,12 +19,13 @@ export class BitField { } has(bit: BitFieldResolvable, ...args: any[]): boolean { - if (Array.isArray(bit)) return bit.every(p => this.has(p)) + if (Array.isArray(bit)) return bit.every((p) => this.has(p)) return (this.bitfield & BitField.resolve(this.flags, bit)) === bit } missing(bits: any, ...hasParams: any[]): string[] { - if (!Array.isArray(bits)) bits = new BitField(this.flags, bits).toArray(false) + if (!Array.isArray(bits)) + bits = new BitField(this.flags, bits).toArray(false) return bits.filter((p: any) => !this.has(p, ...hasParams)) } @@ -37,7 +38,8 @@ export class BitField { for (const bit of bits) { total |= BitField.resolve(this.flags, bit) } - if (Object.isFrozen(this)) return new BitField(this.flags, this.bitfield | total) + if (Object.isFrozen(this)) + return new BitField(this.flags, this.bitfield | total) this.bitfield |= total return this } @@ -47,19 +49,26 @@ export class BitField { for (const bit of bits) { total |= BitField.resolve(this.flags, bit) } - if (Object.isFrozen(this)) return new BitField(this.flags, this.bitfield & ~total) + if (Object.isFrozen(this)) + return new BitField(this.flags, this.bitfield & ~total) this.bitfield &= ~total return this } serialize(...hasParams: any[]): { [key: string]: any } { const serialized: { [key: string]: any } = {} - for (const [flag, bit] of Object.entries(this.flags)) serialized[flag] = this.has(BitField.resolve(this.flags, bit), ...hasParams) + for (const [flag, bit] of Object.entries(this.flags)) + serialized[flag] = this.has( + BitField.resolve(this.flags, bit), + ...hasParams + ) return serialized } toArray(...hasParams: any[]): string[] { - return Object.keys(this.flags).filter(bit => this.has(BitField.resolve(this.flags, bit), ...hasParams)) + return Object.keys(this.flags).filter((bit) => + this.has(BitField.resolve(this.flags, bit), ...hasParams) + ) } toJSON(): number { @@ -78,9 +87,13 @@ export class BitField { if (typeof bit === 'string' && !isNaN(parseInt(bit))) return parseInt(bit) if (typeof bit === 'number' && bit >= 0) return bit if (bit instanceof BitField) return this.resolve(flags, bit.bitfield) - if (Array.isArray(bit)) return bit.map(p => this.resolve(flags, p)).reduce((prev, p) => prev | p, 0) - if (typeof bit === 'string' && typeof flags[bit] !== 'undefined') return flags[bit] + if (Array.isArray(bit)) + return bit + .map((p) => this.resolve(flags, p)) + .reduce((prev, p) => prev | p, 0) + if (typeof bit === 'string' && typeof flags[bit] !== 'undefined') + return flags[bit] const error = new RangeError('BITFIELD_INVALID') throw error } -} \ No newline at end of file +} diff --git a/src/utils/collection.ts b/src/utils/collection.ts index 67bc83e1..2af42f98 100644 --- a/src/utils/collection.ts +++ b/src/utils/collection.ts @@ -63,7 +63,7 @@ export class Collection extends Map { reduce( callback: (accumulator: T, value: V, key: K) => T, - initialValue?: T, + initialValue?: T ): T { let accumulator: T = initialValue as T @@ -82,4 +82,4 @@ export class Collection extends Map { toObject(): { [name: string]: V } { return Object.fromEntries(this) } -} \ No newline at end of file +} diff --git a/src/utils/delay.ts b/src/utils/delay.ts index 6fcb1ec3..98acaeec 100644 --- a/src/utils/delay.ts +++ b/src/utils/delay.ts @@ -1,3 +1,4 @@ -export const delay = async (ms: number): Promise => await new Promise((resolve, reject) => { - setTimeout(() => resolve(true), ms); -}); \ No newline at end of file +export const delay = async (ms: number): Promise => + await new Promise((resolve, reject) => { + setTimeout(() => resolve(true), ms) + }) diff --git a/src/utils/getChannelByType.ts b/src/utils/getChannelByType.ts index 5dbb82b1..1c320eaf 100644 --- a/src/utils/getChannelByType.ts +++ b/src/utils/getChannelByType.ts @@ -7,7 +7,8 @@ import { GuildChannelCategoryPayload, GuildNewsChannelPayload, GuildTextChannelPayload, - GuildVoiceChannelPayload + GuildVoiceChannelPayload, + TextChannelPayload } from '../types/channel.ts' import { DMChannel } from '../structures/dmChannel.ts' import { GroupDMChannel } from '../structures/groupChannel.ts' @@ -15,39 +16,64 @@ import { CategoryChannel } from '../structures/guildCategoryChannel.ts' import { NewsChannel } from '../structures/guildNewsChannel.ts' import { VoiceChannel } from '../structures/guildVoiceChannel.ts' import { Guild } from '../structures/guild.ts' -import { TextChannel, GuildTextChannel } from '../structures/textChannel.ts' +import { GuildTextChannel, TextChannel } from '../structures/textChannel.ts' +import { Channel } from '../structures/channel.ts' -const getChannelByType = ( - client: Client, - data: - | GuildChannelCategoryPayload - | GuildNewsChannelPayload - | GuildTextChannelPayload - | GuildVoiceChannelPayload - | DMChannelPayload - | GroupDMChannelPayload - | ChannelPayload, - guild?: Guild -): - | CategoryChannel - | NewsChannel +export type EveryTextChannelTypes = | TextChannel - | VoiceChannel + | NewsChannel + | GuildTextChannel | DMChannel | GroupDMChannel - | undefined => { + +export type EveryTextChannelPayloadTypes = + | TextChannelPayload + | GuildNewsChannelPayload + | GuildTextChannelPayload + | DMChannelPayload + | GroupDMChannelPayload + +export type EveryChannelTypes = + | Channel + | CategoryChannel + | VoiceChannel + | EveryTextChannelTypes + +export type EveryChannelPayloadTypes = + | ChannelPayload + | GuildChannelCategoryPayload + | GuildVoiceChannelPayload + | EveryTextChannelPayloadTypes + +const getChannelByType = ( + client: Client, + data: EveryChannelPayloadTypes, + guild?: Guild +): EveryChannelTypes | undefined => { switch (data.type) { case ChannelTypes.GUILD_CATEGORY: - if (guild === undefined) throw new Error("No Guild was provided to construct Channel") - return new CategoryChannel(client, data as GuildChannelCategoryPayload, guild) + if (guild === undefined) + throw new Error('No Guild was provided to construct Channel') + return new CategoryChannel( + client, + data as GuildChannelCategoryPayload, + guild + ) case ChannelTypes.GUILD_NEWS: - if (guild === undefined) throw new Error("No Guild was provided to construct Channel") + if (guild === undefined) + throw new Error('No Guild was provided to construct Channel') return new NewsChannel(client, data as GuildNewsChannelPayload, guild) case ChannelTypes.GUILD_TEXT: - if (guild === undefined) throw new Error("No Guild was provided to construct Channel") - return new GuildTextChannel(client, data as GuildTextChannelPayload, guild) + if (guild === undefined) + throw new Error('No Guild was provided to construct Channel') + return new GuildTextChannel( + client, + data as GuildTextChannelPayload, + guild + ) case ChannelTypes.GUILD_VOICE: - if (guild === undefined) throw new Error("No Guild was provided to construct Channel") + if (guild === undefined) + throw new Error('No Guild was provided to construct Channel') return new VoiceChannel(client, data as GuildVoiceChannelPayload, guild) case ChannelTypes.DM: return new DMChannel(client, data as DMChannelPayload) diff --git a/src/utils/index.ts b/src/utils/index.ts index 5d3be21d..0b1c56dd 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,3 +1,3 @@ export { default as getChannelByType } from './getChannelByType.ts' -export type AnyFunction = (...args:any[]) => ReturnType; -export { delay } from './delay.ts' \ No newline at end of file +export type AnyFunction = (...args: any[]) => ReturnType +export { delay } from './delay.ts' diff --git a/src/utils/intents.ts b/src/utils/intents.ts index ad4b0510..6106fdba 100644 --- a/src/utils/intents.ts +++ b/src/utils/intents.ts @@ -1,59 +1,60 @@ -import { GatewayIntents } from '../types/gateway.ts' - -export type PriviligedIntents = 'GUILD_MEMBERS' | 'GUILD_PRESENCES' - -// eslint-disable-next-line @typescript-eslint/no-extraneous-class -export class Intents { - static NonPriviliged: number[] = [ - GatewayIntents.GUILD_MESSAGES, - GatewayIntents.DIRECT_MESSAGES, - GatewayIntents.DIRECT_MESSAGE_REACTIONS, - GatewayIntents.DIRECT_MESSAGE_TYPING, - GatewayIntents.GUILDS, - GatewayIntents.GUILD_BANS, - GatewayIntents.GUILD_EMOJIS, - GatewayIntents.GUILD_INTEGRATIONS, - GatewayIntents.GUILD_INVITES, - GatewayIntents.GUILD_MESSAGE_REACTIONS, - GatewayIntents.GUILD_MESSAGE_TYPING, - GatewayIntents.GUILD_VOICE_STATES, - GatewayIntents.GUILD_WEBHOOKS - ] - - static All: number[] = [ - GatewayIntents.GUILD_MEMBERS, - GatewayIntents.GUILD_PRESENCES, - ...Intents.NonPriviliged - ] - - static Presence: number[] = [ - GatewayIntents.GUILD_PRESENCES, - ...Intents.NonPriviliged - ] - - static GuildMembers: number[] = [ - GatewayIntents.GUILD_MEMBERS, - ...Intents.NonPriviliged - ] - - static None: number[] = [ - ...Intents.NonPriviliged - ] - - static create(priviliged?: PriviligedIntents[], disable?: number[]): number[] { - let intents: number[] = [ - ...Intents.NonPriviliged - ] - - if (priviliged !== undefined && priviliged.length !== 0) { - if (priviliged.includes('GUILD_MEMBERS')) intents.push(GatewayIntents.GUILD_MEMBERS) - if (priviliged.includes('GUILD_PRESENCES')) intents.push(GatewayIntents.GUILD_PRESENCES) - } - - if (disable !== undefined) { - intents = intents.filter(intent => !disable.includes(intent)) - } - - return intents - } -} +import { GatewayIntents } from '../types/gateway.ts' + +export type PriviligedIntents = 'GUILD_MEMBERS' | 'GUILD_PRESENCES' + +// eslint-disable-next-line @typescript-eslint/no-extraneous-class +export class Intents { + static NonPriviliged: number[] = [ + GatewayIntents.GUILD_MESSAGES, + GatewayIntents.DIRECT_MESSAGES, + GatewayIntents.DIRECT_MESSAGE_REACTIONS, + GatewayIntents.DIRECT_MESSAGE_TYPING, + GatewayIntents.GUILDS, + GatewayIntents.GUILD_BANS, + GatewayIntents.GUILD_EMOJIS, + GatewayIntents.GUILD_INTEGRATIONS, + GatewayIntents.GUILD_INVITES, + GatewayIntents.GUILD_MESSAGE_REACTIONS, + GatewayIntents.GUILD_MESSAGE_TYPING, + GatewayIntents.GUILD_VOICE_STATES, + GatewayIntents.GUILD_WEBHOOKS + ] + + static All: number[] = [ + GatewayIntents.GUILD_MEMBERS, + GatewayIntents.GUILD_PRESENCES, + ...Intents.NonPriviliged + ] + + static Presence: number[] = [ + GatewayIntents.GUILD_PRESENCES, + ...Intents.NonPriviliged + ] + + static GuildMembers: number[] = [ + GatewayIntents.GUILD_MEMBERS, + ...Intents.NonPriviliged + ] + + static None: number[] = [...Intents.NonPriviliged] + + static create( + priviliged?: PriviligedIntents[], + disable?: number[] + ): number[] { + let intents: number[] = [...Intents.NonPriviliged] + + if (priviliged !== undefined && priviliged.length !== 0) { + if (priviliged.includes('GUILD_MEMBERS')) + intents.push(GatewayIntents.GUILD_MEMBERS) + if (priviliged.includes('GUILD_PRESENCES')) + intents.push(GatewayIntents.GUILD_PRESENCES) + } + + if (disable !== undefined) { + intents = intents.filter((intent) => !disable.includes(intent)) + } + + return intents + } +} diff --git a/src/utils/mixedPromise.ts b/src/utils/mixedPromise.ts index 749937fb..4f1b297c 100644 --- a/src/utils/mixedPromise.ts +++ b/src/utils/mixedPromise.ts @@ -1,3 +1,3 @@ -export const awaitSync = async(val: any | Promise): Promise => { - return val instanceof Promise ? await val : val -} \ No newline at end of file +export const awaitSync = async (val: any | Promise): Promise => { + return val instanceof Promise ? await val : val +} diff --git a/src/utils/permissions.ts b/src/utils/permissions.ts index 060a0c00..88ea5d10 100644 --- a/src/utils/permissions.ts +++ b/src/utils/permissions.ts @@ -1,8 +1,12 @@ // Ported from https://github.com/discordjs/discord.js/blob/master/src/util/Permissions.js -import { PermissionFlags } from "../types/permissionFlags.ts" -import { BitField } from "./bitfield.ts" +import { PermissionFlags } from '../types/permissionFlags.ts' +import { BitField } from './bitfield.ts' -export type PermissionResolvable = string | number | Permissions | PermissionResolvable[] +export type PermissionResolvable = + | string + | number + | Permissions + | PermissionResolvable[] export class Permissions extends BitField { static DEFAULT = 104324673 @@ -13,10 +17,16 @@ export class Permissions extends BitField { } any(permission: PermissionResolvable, checkAdmin = true): boolean { - return (checkAdmin && super.has(this.flags.ADMINISTRATOR)) || super.any(permission as any) + return ( + (checkAdmin && super.has(this.flags.ADMINISTRATOR)) || + super.any(permission as any) + ) } has(permission: PermissionResolvable, checkAdmin = true): boolean { - return (checkAdmin && super.has(this.flags.ADMINISTRATOR)) || super.has(permission as any) + return ( + (checkAdmin && super.has(this.flags.ADMINISTRATOR)) || + super.has(permission as any) + ) } -} \ No newline at end of file +} diff --git a/src/utils/userFlags.ts b/src/utils/userFlags.ts index 7be42f44..cba0a3f2 100644 --- a/src/utils/userFlags.ts +++ b/src/utils/userFlags.ts @@ -1,8 +1,8 @@ -import { UserFlags } from "../types/userFlags.ts"; -import { BitField } from "./bitfield.ts"; +import { UserFlags } from '../types/userFlags.ts' +import { BitField } from './bitfield.ts' export class UserFlagsManager extends BitField { - constructor(bits: any) { - super(UserFlags, bits) - } -} \ No newline at end of file + constructor(bits: any) { + super(UserFlags, bits) + } +} diff --git a/tsconfig.json b/tsconfig.json index a4477bbb..de2b8886 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,70 +1,70 @@ -{ - "compilerOptions": { - /* Visit https://aka.ms/tsconfig.json to read more about this file */ - /* Basic Options */ - // "incremental": true, /* Enable incremental compilation */ - "target": "ESNext", - /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ - "module": "ESNext", - /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ - "lib": [ - "esnext" - ] /* Specify library files to be included in the compilation. */, - // "allowJs": true, /* Allow javascript files to be compiled. */ - // "checkJs": true, /* Report errors in .js files. */ - // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ - // "declaration": true, /* Generates corresponding '.d.ts' file. */ - // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ - // "sourceMap": true, /* Generates corresponding '.map' file. */ - // "outFile": "./", /* Concatenate and emit output to single file. */ - // "outDir": "./", /* Redirect output structure to the directory. */ - // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ - // "composite": true, /* Enable project compilation */ - // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ - // "removeComments": true, /* Do not emit comments to output. */ - // "noEmit": true, /* Do not emit outputs. */ - // "importHelpers": true, /* Import emit helpers from 'tslib'. */ - // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ - "isolatedModules": true /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */, - /* Strict Type-Checking Options */ - "strict": true, - /* Enable all strict type-checking options. */ - // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* Enable strict null checks. */ - // "strictFunctionTypes": true, /* Enable strict checking of function types. */ - // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ - // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ - // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ - // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ - /* Additional Checks */ - // "noUnusedLocals": true, /* Report errors on unused locals. */ - // "noUnusedParameters": true, /* Report errors on unused parameters. */ - // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ - // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - /* Module Resolution Options */ - "moduleResolution": "node", - /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ - // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ - // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ - // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ - // "typeRoots": [], /* List of folders to include type definitions from. */ - // "types": [], /* Type declaration files to be included in compilation. */ - // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ - "esModuleInterop": true, - /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ - // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - /* Source Map Options */ - // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ - // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ - /* Experimental Options */ - "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ - "emitDecoratorMetadata": false /* Enables experimental support for emitting type metadata for decorators. */, - /* Advanced Options */ - "skipLibCheck": true, - /* Skip type checking of declaration files. */ - "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ - } -} +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "ESNext", + /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ + "module": "ESNext", + /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ + "lib": [ + "esnext" + ] /* Specify library files to be included in the compilation. */, + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + // "outDir": "./", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + "isolatedModules": true /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */, + /* Strict Type-Checking Options */ + "strict": true, + /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + /* Module Resolution Options */ + "moduleResolution": "node", + /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true, + /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + /* Experimental Options */ + "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */, + "emitDecoratorMetadata": false /* Enables experimental support for emitting type metadata for decorators. */, + /* Advanced Options */ + "skipLibCheck": true, + /* Skip type checking of declaration files. */ + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + } +}