Merge pull request #19 from DjDeveloperr/main
feature: Roles & Members Caching and Child Managers
This commit is contained in:
		
						commit
						536f070366
					
				
					 43 changed files with 751 additions and 327 deletions
				
			
		
							
								
								
									
										10
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								README.md
									
										
									
									
									
								
							|  | @ -4,13 +4,13 @@ | ||||||
| 
 | 
 | ||||||
| [](https://github.com/RichardLitt/standard-readme) | [](https://github.com/RichardLitt/standard-readme) | ||||||
| 
 | 
 | ||||||
| Discord Deno API that is easy to use | **An easy to use Discord API Library for Deno** | ||||||
| 
 | 
 | ||||||
| ## Table of Contents | ## Table of Contents | ||||||
| 
 | 
 | ||||||
| - [Usage](#usage) | - [Usage](#usage) | ||||||
| - [Docs](#docs) | - [Docs](#docs) | ||||||
| - [Maintainers](#maintainers) | - [Maintainer](#maintainer) | ||||||
| - [Contributing](#contributing) | - [Contributing](#contributing) | ||||||
| - [License](#license) | - [License](#license) | ||||||
| 
 | 
 | ||||||
|  | @ -35,7 +35,7 @@ bot.connect(TOKEN, [GatewayIntents.GUILD_MESSAGES]) | ||||||
| 
 | 
 | ||||||
| Not made yet | Not made yet | ||||||
| 
 | 
 | ||||||
| ## Maintainers | ## Maintainer | ||||||
| 
 | 
 | ||||||
| [@Helloyunho](https://github.com/Helloyunho) | [@Helloyunho](https://github.com/Helloyunho) | ||||||
| 
 | 
 | ||||||
|  | @ -43,10 +43,10 @@ Not made yet | ||||||
| 
 | 
 | ||||||
| See [the contributing file](CONTRIBUTING.md)! | See [the contributing file](CONTRIBUTING.md)! | ||||||
| 
 | 
 | ||||||
| PRs accepted. | PRs are accepted. | ||||||
| 
 | 
 | ||||||
| Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. | Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. | ||||||
| 
 | 
 | ||||||
| ## License | ## License | ||||||
| 
 | 
 | ||||||
| MIT © 2020 Helloyunho | [MIT © 2020 Helloyunho](LICENSE) | ||||||
|  |  | ||||||
							
								
								
									
										55
									
								
								mod.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								mod.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,55 @@ | ||||||
|  | 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/managers/BaseManager.ts' | ||||||
|  | export * from './src/managers/BaseChildManager.ts' | ||||||
|  | export * from './src/managers/ChannelsManager.ts' | ||||||
|  | export * from './src/managers/EmojisManager.ts' | ||||||
|  | export * from './src/managers/GatewayCache.ts' | ||||||
|  | export * from './src/managers/GuildChannelsManager.ts' | ||||||
|  | export * from './src/managers/GuildsManager.ts' | ||||||
|  | export * from './src/managers/MembersManager.ts' | ||||||
|  | export * from './src/managers/MessagesManager.ts' | ||||||
|  | export * from './src/managers/RolesManager.ts' | ||||||
|  | export * from './src/managers/UsersManager.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/guildTextChannel.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/user.ts' | ||||||
|  | export * from './src/structures/webhook.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' | ||||||
|  | @ -1,12 +1,11 @@ | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| import { Channel } from '../../structures/channel.ts' |  | ||||||
| import { ChannelPayload } from '../../types/channel.ts' | import { ChannelPayload } from '../../types/channel.ts' | ||||||
| 
 | 
 | ||||||
| export const channelDelete: GatewayEventHandler = async ( | export const channelDelete: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|   d: ChannelPayload |   d: ChannelPayload | ||||||
| ) => { | ) => { | ||||||
|   const channel: Channel = await gateway.client.channels.get(d.id) |   const channel = await gateway.client.channels.get(d.id) | ||||||
|   if (channel !== undefined) { |   if (channel !== undefined) { | ||||||
|     await gateway.client.channels.delete(d.id) |     await gateway.client.channels.delete(d.id) | ||||||
|     gateway.client.emit('channelDelete', channel) |     gateway.client.emit('channelDelete', channel) | ||||||
|  |  | ||||||
|  | @ -6,7 +6,7 @@ export const channelPinsUpdate: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|   d: ChannelPinsUpdatePayload |   d: ChannelPinsUpdatePayload | ||||||
| ) => { | ) => { | ||||||
|   const after: TextChannel = await gateway.client.channels.get(d.channel_id) |   const after: TextChannel | void = await gateway.client.channels.get<TextChannel>(d.channel_id) | ||||||
|   if (after !== undefined) { |   if (after !== undefined) { | ||||||
|     const before = after.refreshFromData({ |     const before = after.refreshFromData({ | ||||||
|       last_pin_timestamp: d.last_pin_timestamp |       last_pin_timestamp: d.last_pin_timestamp | ||||||
|  |  | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| import { Channel } from '../../structures/channel.ts' | import { Channel } from '../../structures/channel.ts' | ||||||
|  | import { Guild } from "../../structures/guild.ts" | ||||||
| import { ChannelPayload } from '../../types/channel.ts' | import { ChannelPayload } from '../../types/channel.ts' | ||||||
| import getChannelByType from '../../utils/getChannelByType.ts' | import getChannelByType from '../../utils/getChannelByType.ts' | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
|  | @ -7,12 +8,16 @@ export const channelUpdate: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|   d: ChannelPayload |   d: ChannelPayload | ||||||
| ) => { | ) => { | ||||||
|   const oldChannel: Channel = await gateway.client.channels.get(d.id) |   const oldChannel: Channel | undefined = await gateway.client.channels.get(d.id) | ||||||
| 
 | 
 | ||||||
|   if (oldChannel !== undefined) { |   if (oldChannel !== undefined) { | ||||||
|     await gateway.client.channels.set(d.id, d) |     await gateway.client.channels.set(d.id, d) | ||||||
|  |     let guild: undefined | Guild; | ||||||
|  |     if((d as any).guild_id !== undefined) { | ||||||
|  |       guild = await gateway.client.guilds.get((d as any).guild_id) as Guild | undefined | ||||||
|  |     } | ||||||
|     if (oldChannel.type !== d.type) { |     if (oldChannel.type !== d.type) { | ||||||
|       const channel: Channel = getChannelByType(gateway.client, d) ?? oldChannel |       const channel: Channel = getChannelByType(gateway.client, d, guild) ?? oldChannel | ||||||
|       gateway.client.emit('channelUpdate', oldChannel, channel) |       gateway.client.emit('channelUpdate', oldChannel, channel) | ||||||
|     } else { |     } else { | ||||||
|       const before = oldChannel.refreshFromData(d) |       const before = oldChannel.refreshFromData(d) | ||||||
|  |  | ||||||
|  | @ -13,7 +13,7 @@ export const guildBanAdd: GatewayEventHandler = async ( | ||||||
|     new User(gateway.client, d.user) |     new User(gateway.client, d.user) | ||||||
| 
 | 
 | ||||||
|   if (guild !== undefined) { |   if (guild !== undefined) { | ||||||
|     guild.members = guild.members?.filter(member => member.id !== d.user.id) |     await guild.members.delete(user.id) | ||||||
|     gateway.client.emit('guildBanAdd', guild, user) |     gateway.client.emit('guildBanAdd', guild, user) | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,19 +1,54 @@ | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| import { Guild } from '../../structures/guild.ts' | import { Guild } from '../../structures/guild.ts' | ||||||
| import { GuildPayload } from '../../types/guild.ts' | import { GuildPayload, MemberPayload } from "../../types/guild.ts" | ||||||
|  | import { MembersManager } from "../../managers/MembersManager.ts" | ||||||
|  | import { ChannelPayload } from "../../types/channel.ts" | ||||||
|  | import { RolePayload } from "../../types/role.ts" | ||||||
|  | import { RolesManager } from "../../managers/RolesManager.ts" | ||||||
| 
 | 
 | ||||||
| export const guildCreate: GatewayEventHandler = async ( | export const guildCreate: GatewayEventHandler = async(gateway: Gateway, d: GuildPayload) => { | ||||||
|   gateway: Gateway, |  | ||||||
|   d: GuildPayload |  | ||||||
| ) => { |  | ||||||
|   let guild: Guild | undefined = await gateway.client.guilds.get(d.id) |   let guild: Guild | undefined = await gateway.client.guilds.get(d.id) | ||||||
|   if (guild !== undefined) { |   if (guild !== undefined) { | ||||||
|     // It was just lazy load, so we don't fire the event as its gonna fire for every guild bot is in
 |     // It was just lazy load, so we don't fire the event as its gonna fire for every guild bot is in
 | ||||||
|     await gateway.client.guilds.set(d.id, d) |     await gateway.client.guilds.set(d.id, d) | ||||||
|  |     if ((d as any).members !== undefined) { | ||||||
|  |       const members = new MembersManager(gateway.client, guild) | ||||||
|  |       await members.fromPayload((d as any).members as MemberPayload[]) | ||||||
|  |       guild.members = members | ||||||
|  |     } | ||||||
|  |     if ((d as any).channels !== undefined) { | ||||||
|  |       for (const ch of (d as any).channels as ChannelPayload[]) { | ||||||
|  |         (ch as any).guild_id = d.id | ||||||
|  |         await gateway.client.channels.set(ch.id, ch) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     if ((d as any).roles !== undefined) { | ||||||
|  |       const roles = new RolesManager(gateway.client, guild) | ||||||
|  |       await roles.fromPayload((d as any).roles as RolePayload[]) | ||||||
|  |       guild.roles = roles | ||||||
|  |     } | ||||||
|     guild.refreshFromData(d) |     guild.refreshFromData(d) | ||||||
|   } else { |   } else { | ||||||
|     await gateway.client.guilds.set(d.id, d) |     await gateway.client.guilds.set(d.id, d) | ||||||
|     guild = new Guild(gateway.client, d) |     guild = new Guild(gateway.client, d) | ||||||
|  |     if ((d as any).members !== undefined) { | ||||||
|  |       const members = new MembersManager(gateway.client, guild) | ||||||
|  |       await members.fromPayload((d as any).members as MemberPayload[]) | ||||||
|  |       guild.members = members | ||||||
|  |     } | ||||||
|  |     if ((d as any).channels !== undefined) { | ||||||
|  |       for (const ch of (d as any).channels as ChannelPayload[]) { | ||||||
|  |         (ch as any).guild_id = d.id | ||||||
|  |         await gateway.client.channels.set(ch.id, ch) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     if ((d as any).roles !== undefined) { | ||||||
|  |       const roles = new RolesManager(gateway.client, guild) | ||||||
|  |       await roles.fromPayload((d as any).roles as RolePayload[]) | ||||||
|  |       guild.roles = roles | ||||||
|  |     } | ||||||
|  |     await guild.roles.fromPayload(d.roles) | ||||||
|  |     guild = new Guild(gateway.client, d) | ||||||
|     gateway.client.emit('guildCreate', guild) |     gateway.client.emit('guildCreate', guild) | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -10,6 +10,9 @@ export const guildDelte: GatewayEventHandler = async ( | ||||||
| 
 | 
 | ||||||
|   if (guild !== undefined) { |   if (guild !== undefined) { | ||||||
|     guild.refreshFromData(d) |     guild.refreshFromData(d) | ||||||
|  |     await guild.members.flush() | ||||||
|  |     await guild.channels.flush() | ||||||
|  |     await guild.roles.flush() | ||||||
|     await gateway.client.guilds.delete(d.id) |     await gateway.client.guilds.delete(d.id) | ||||||
|     gateway.client.emit('guildDelete', guild) |     gateway.client.emit('guildDelete', guild) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | @ -1,14 +1,14 @@ | ||||||
| import cache from '../../models/cache.ts' | import cache from '../../models/cache.ts' | ||||||
| import { Guild } from '../../structures/guild.ts' | import { Guild } from '../../structures/guild.ts' | ||||||
| import { GuildEmojiUpdatePayload } from '../../types/gatewayTypes.ts' | import { GuildEmojiUpdatePayload } from '../../types/gateway.ts' | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| 
 | 
 | ||||||
| const guildEmojiUpdate: GatewayEventHandler = ( | export const guildEmojiUpdate: GatewayEventHandler = ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|   d: GuildEmojiUpdatePayload |   d: GuildEmojiUpdatePayload | ||||||
| ) => { | ) => { | ||||||
|   const guild: Guild = cache.get('guild', d.guild_id) |   const guild: Guild = cache.get('guild', d.guild_id) | ||||||
|   if (guild !== undefined) { |   if (guild !== undefined) { | ||||||
|     const emojis = guild.emojis |     // const emojis = guild.emojis
 | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -12,12 +12,13 @@ import { ready } from './ready.ts' | ||||||
| import { guildBanRemove } from './guildBanRemove.ts' | import { guildBanRemove } from './guildBanRemove.ts' | ||||||
| import { messageCreate } from "./messageCreate.ts" | import { messageCreate } from "./messageCreate.ts" | ||||||
| import { resume } from "./resume.ts" | import { resume } from "./resume.ts" | ||||||
|  | import { reconnect } from './reconnect.ts' | ||||||
| 
 | 
 | ||||||
| export const gatewayHandlers: { | export const gatewayHandlers: { | ||||||
|   [eventCode in GatewayEvents]: GatewayEventHandler | undefined |   [eventCode in GatewayEvents]: GatewayEventHandler | undefined | ||||||
| } = { | } = { | ||||||
|   READY: ready, |   READY: ready, | ||||||
|   RECONNECT: undefined, |   RECONNECT: reconnect, | ||||||
|   RESUMED: resume, |   RESUMED: resume, | ||||||
|   CHANNEL_CREATE: channelCreate, |   CHANNEL_CREATE: channelCreate, | ||||||
|   CHANNEL_DELETE: channelDelete, |   CHANNEL_DELETE: channelDelete, | ||||||
|  |  | ||||||
|  | @ -1,4 +1,3 @@ | ||||||
| import { Channel } from '../../structures/channel.ts' |  | ||||||
| import { Message } from '../../structures/message.ts' | import { Message } from '../../structures/message.ts' | ||||||
| import { MessageMentions } from '../../structures/MessageMentions.ts' | import { MessageMentions } from '../../structures/MessageMentions.ts' | ||||||
| import { TextChannel } from '../../structures/textChannel.ts' | import { TextChannel } from '../../structures/textChannel.ts' | ||||||
|  | @ -10,13 +9,18 @@ export const messageCreate: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|   d: MessagePayload |   d: MessagePayload | ||||||
| ) => { | ) => { | ||||||
|   let channel = (await gateway.client.channels.get(d.channel_id)) as TextChannel |   let channel = await gateway.client.channels.get<TextChannel>(d.channel_id) | ||||||
|   // Fetch the channel if not cached
 |   // Fetch the channel if not cached
 | ||||||
|   if (channel === undefined) |   if (channel === undefined) | ||||||
|     channel = (await gateway.client.channels.fetch(d.channel_id)) as TextChannel |     channel = (await gateway.client.channels.fetch(d.channel_id)) as any | ||||||
|   const user = new User(gateway.client, d.author) |   const user = new User(gateway.client, d.author) | ||||||
|   await gateway.client.users.set(d.author.id, d.author) |   await gateway.client.users.set(d.author.id, d.author) | ||||||
|  |   let guild | ||||||
|  |   if(d.guild_id !== undefined) { | ||||||
|  |     guild = await gateway.client.guilds.get(d.guild_id) | ||||||
|  |   } | ||||||
|   const mentions = new MessageMentions() |   const mentions = new MessageMentions() | ||||||
|   const message = new Message(gateway.client, d, channel, user, mentions) |   const message = new Message(gateway.client, d, channel as any, user, mentions) | ||||||
|  |   if (guild !== undefined) message.guild = guild | ||||||
|   gateway.client.emit('messageCreate', message) |   gateway.client.emit('messageCreate', message) | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										6
									
								
								src/gateway/handlers/reconnect.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/gateway/handlers/reconnect.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | ||||||
|  | import { Gateway } from "../index.ts" | ||||||
|  | import { GatewayEventHandler } from "../index.ts" | ||||||
|  | 
 | ||||||
|  | export const reconnect: GatewayEventHandler = async (gateway: Gateway, d: any) => { | ||||||
|  |     gateway.reconnect() | ||||||
|  | } | ||||||
|  | @ -1,7 +1,10 @@ | ||||||
|  | import { User } from "../../structures/user.ts" | ||||||
|  | import { CLIENT_USER } from "../../types/endpoint.ts" | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| 
 | 
 | ||||||
| export const resume: GatewayEventHandler = (gateway: Gateway, d: any) => { | export const resume: GatewayEventHandler = async (gateway: Gateway, d: any) => { | ||||||
|   gateway.debug(`Session Resumed!`) |   gateway.debug(`Session Resumed!`) | ||||||
|   gateway.client.emit('resume') |   gateway.client.emit('resume') | ||||||
|  |   if (gateway.client.user === undefined) gateway.client.user = new User(gateway.client, await gateway.client.rest.get(CLIENT_USER()) as any) | ||||||
|   gateway.client.emit('ready') |   gateway.client.emit('ready') | ||||||
| } | } | ||||||
|  | @ -12,7 +12,8 @@ import { | ||||||
| } from '../types/gateway.ts' | } from '../types/gateway.ts' | ||||||
| import { gatewayHandlers } from './handlers/index.ts' | import { gatewayHandlers } from './handlers/index.ts' | ||||||
| import { GATEWAY_BOT } from '../types/endpoint.ts' | import { GATEWAY_BOT } from '../types/endpoint.ts' | ||||||
| import { GatewayCache } from '../managers/GatewayCache.ts' | import { GatewayCache } from "../managers/GatewayCache.ts" | ||||||
|  | import { ClientActivityPayload } from "../structures/presence.ts" | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Handles Discord gateway connection. |  * Handles Discord gateway connection. | ||||||
|  | @ -35,7 +36,7 @@ class Gateway { | ||||||
|   client: Client |   client: Client | ||||||
|   cache: GatewayCache |   cache: GatewayCache | ||||||
| 
 | 
 | ||||||
|   constructor (client: Client, token: string, intents: GatewayIntents[]) { |   constructor(client: Client, token: string, intents: GatewayIntents[]) { | ||||||
|     this.token = token |     this.token = token | ||||||
|     this.intents = intents |     this.intents = intents | ||||||
|     this.client = client |     this.client = client | ||||||
|  | @ -52,12 +53,12 @@ class Gateway { | ||||||
|     this.websocket.onerror = this.onerror.bind(this) |     this.websocket.onerror = this.onerror.bind(this) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private onopen (): void { |   private onopen(): void { | ||||||
|     this.connected = true |     this.connected = true | ||||||
|     this.debug('Connected to Gateway!') |     this.debug('Connected to Gateway!') | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private async onmessage (event: MessageEvent): Promise<void> { |   private async onmessage(event: MessageEvent): Promise<void> { | ||||||
|     let data = event.data |     let data = event.data | ||||||
|     if (data instanceof ArrayBuffer) { |     if (data instanceof ArrayBuffer) { | ||||||
|       data = new Uint8Array(data) |       data = new Uint8Array(data) | ||||||
|  | @ -85,21 +86,17 @@ class Gateway { | ||||||
|             return |             return | ||||||
|           } |           } | ||||||
| 
 | 
 | ||||||
|           this.websocket.send( |           this.send({ | ||||||
|             JSON.stringify({ |             op: GatewayOpcodes.HEARTBEAT, | ||||||
|               op: GatewayOpcodes.HEARTBEAT, |             d: this.sequenceID ?? null | ||||||
|               d: this.sequenceID ?? null |           }) | ||||||
|             }) |  | ||||||
|           ) |  | ||||||
|           this.lastPingTimestamp = Date.now() |           this.lastPingTimestamp = Date.now() | ||||||
|         }, this.heartbeatInterval) |         }, this.heartbeatInterval) | ||||||
| 
 | 
 | ||||||
|         if (!this.initialized) { |         if (!this.initialized) { | ||||||
|           // eslint-disable-next-line @typescript-eslint/no-floating-promises
 |  | ||||||
|           this.sendIdentify() |  | ||||||
|           this.initialized = true |           this.initialized = true | ||||||
|  |           await this.sendIdentify(this.client.forceNewSession) | ||||||
|         } else { |         } else { | ||||||
|           console.log('Calling Resume') |  | ||||||
|           // eslint-disable-next-line @typescript-eslint/no-floating-promises
 |           // eslint-disable-next-line @typescript-eslint/no-floating-promises
 | ||||||
|           this.sendResume() |           this.sendResume() | ||||||
|         } |         } | ||||||
|  | @ -198,7 +195,7 @@ class Gateway { | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private onerror (event: Event | ErrorEvent): void { |   private onerror(event: Event | ErrorEvent): void { | ||||||
|     const eventError = event as ErrorEvent |     const eventError = event as ErrorEvent | ||||||
|     console.log(eventError) |     console.log(eventError) | ||||||
|   } |   } | ||||||
|  | @ -224,34 +221,27 @@ class Gateway { | ||||||
|         return await this.sendResume() |         return await this.sendResume() | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     this.websocket.send( |     this.send({ | ||||||
|       JSON.stringify({ |       op: GatewayOpcodes.IDENTIFY, | ||||||
|         op: GatewayOpcodes.IDENTIFY, |       d: { | ||||||
|         d: { |         token: this.token, | ||||||
|           token: this.token, |         properties: { | ||||||
|           properties: { |           $os: Deno.build.os, | ||||||
|             $os: Deno.build.os, |           $browser: 'discord.deno', //TODO: Change lib name
 | ||||||
|             $browser: 'discord.deno', |           $device: 'discord.deno' | ||||||
|             $device: 'discord.deno' |         }, | ||||||
|           }, |         compress: true, | ||||||
|           compress: true, |         shard: [0, 1], // TODO: Make sharding possible
 | ||||||
|           shard: [0, 1], // TODO: Make sharding possible
 |         intents: this.intents.reduce( | ||||||
|           intents: this.intents.reduce( |           (previous, current) => previous | current, | ||||||
|             (previous, current) => previous | current, |           0 | ||||||
|             0 |         ), | ||||||
|           ), |         presence: this.client.presence.create() | ||||||
|           presence: { |       } | ||||||
|             // TODO: User should can customize this
 |     }) | ||||||
|             status: 'online', |  | ||||||
|             since: null, |  | ||||||
|             afk: false |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     ) |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private async sendResume (): Promise<void> { |   private async sendResume(): Promise<void> { | ||||||
|     this.debug(`Preparing to resume with Session: ${this.sessionID}`) |     this.debug(`Preparing to resume with Session: ${this.sessionID}`) | ||||||
|     if (this.sequenceID === undefined) { |     if (this.sequenceID === undefined) { | ||||||
|       const cached = await this.cache.get('seq') |       const cached = await this.cache.get('seq') | ||||||
|  | @ -266,7 +256,7 @@ class Gateway { | ||||||
|         seq: this.sequenceID ?? null |         seq: this.sequenceID ?? null | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     this.websocket.send(JSON.stringify(resumePayload)) |     this.send(resumePayload) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   debug (msg: string): void { |   debug (msg: string): void { | ||||||
|  | @ -281,7 +271,7 @@ class Gateway { | ||||||
|     this.initWebsocket() |     this.initWebsocket() | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   initWebsocket (): void { |   initWebsocket(): void { | ||||||
|     this.websocket = new WebSocket( |     this.websocket = new WebSocket( | ||||||
|       // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
 |       // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
 | ||||||
|       `${DISCORD_GATEWAY_URL}/?v=${DISCORD_API_VERSION}&encoding=json`, |       `${DISCORD_GATEWAY_URL}/?v=${DISCORD_API_VERSION}&encoding=json`, | ||||||
|  | @ -294,9 +284,27 @@ class Gateway { | ||||||
|     this.websocket.onerror = this.onerror.bind(this) |     this.websocket.onerror = this.onerror.bind(this) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   close (): void { |   close(): void { | ||||||
|     this.websocket.close(1000) |     this.websocket.close(1000) | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   send(data: GatewayResponse): boolean { | ||||||
|  |     if (this.websocket.readyState !== this.websocket.OPEN) return false | ||||||
|  |     this.websocket.send(JSON.stringify({ | ||||||
|  |       op: data.op, | ||||||
|  |       d: data.d, | ||||||
|  |       s: typeof data.s === "number" ? data.s : null, | ||||||
|  |       t: data.t === undefined ? null : data.t, | ||||||
|  |     })) | ||||||
|  |     return true | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   sendPresence(data: ClientActivityPayload): void { | ||||||
|  |     this.send({ | ||||||
|  |       op: GatewayOpcodes.PRESENCE_UPDATE, | ||||||
|  |       d: data | ||||||
|  |     }) | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export type GatewayEventHandler = (gateway: Gateway, d: any) => void | export type GatewayEventHandler = (gateway: Gateway, d: any) => void | ||||||
|  |  | ||||||
							
								
								
									
										40
									
								
								src/managers/BaseChildManager.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/managers/BaseChildManager.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,40 @@ | ||||||
|  | import { Client } from "../models/client.ts"; | ||||||
|  | import { Collection } from "../utils/collection.ts"; | ||||||
|  | import { BaseManager } from "./BaseManager.ts"; | ||||||
|  | 
 | ||||||
|  | export class BaseChildManager<T, T2> { | ||||||
|  |   client: Client | ||||||
|  |   parent: BaseManager<T, T2> | ||||||
|  | 
 | ||||||
|  |   constructor(client: Client, parent: BaseManager<T, T2>) { | ||||||
|  |     this.client = client | ||||||
|  |     this.parent = parent | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async get(key: string): Promise<T2 | undefined> { | ||||||
|  |     return this.parent.get(key) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async set(key: string, value: T): Promise<void> { | ||||||
|  |     return this.parent.set(key, value) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async delete(key: string): Promise<any> { | ||||||
|  |     return false | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async array(): Promise<any> { | ||||||
|  |     return this.parent.array() | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async collection(): Promise<Collection<string, T2>> { | ||||||
|  |     const arr = await this.array() as undefined | T2[] | ||||||
|  |     if (arr === undefined) return new Collection() | ||||||
|  |     const collection = new Collection() | ||||||
|  |     for (const elem of arr) { | ||||||
|  |       // @ts-expect-error
 | ||||||
|  |       collection.set(elem.id, elem) | ||||||
|  |     } | ||||||
|  |     return collection | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| import { Client } from '../models/client.ts' | import { Client } from "../models/client.ts"; | ||||||
|  | import { Collection } from "../utils/collection.ts"; | ||||||
| 
 | 
 | ||||||
| export class BaseManager<T, T2> { | export class BaseManager<T, T2> { | ||||||
|   client: Client |   client: Client | ||||||
|  | @ -28,4 +29,24 @@ export class BaseManager<T, T2> { | ||||||
|   async delete (key: string): Promise<boolean> { |   async delete (key: string): Promise<boolean> { | ||||||
|     return this.client.cache.delete(this.cacheName, key) |     return this.client.cache.delete(this.cacheName, key) | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   async array (): Promise<undefined | T2[]> { | ||||||
|  |     const arr = await (this.client.cache.array(this.cacheName) as T[]) | ||||||
|  |     return arr.map(e => new this.DataType(this.client, e)) as any | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async collection (): Promise<Collection<string, T2>> { | ||||||
|  |     const arr = await this.array() | ||||||
|  |     if (arr === undefined) return new Collection() | ||||||
|  |     const collection = new Collection() | ||||||
|  |     for (const elem of arr) { | ||||||
|  |       // @ts-expect-error
 | ||||||
|  |       collection.set(elem.id, elem) | ||||||
|  |     } | ||||||
|  |     return collection | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   flush(): any { | ||||||
|  |     return this.client.cache.deleteCache(this.cacheName) | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,29 +1,50 @@ | ||||||
| import { Client } from '../models/client.ts' | import { Client } from "../models/client.ts"; | ||||||
| import { Channel } from '../structures/channel.ts' | import { Channel } from "../structures/channel.ts"; | ||||||
| import { User } from '../structures/user.ts' | import { ChannelPayload } from "../types/channel.ts"; | ||||||
| import { ChannelPayload } from '../types/channel.ts' | import { CHANNEL } from "../types/endpoint.ts"; | ||||||
| import { CHANNEL } from '../types/endpoint.ts' | import getChannelByType from "../utils/getChannelByType.ts"; | ||||||
| import { BaseManager } from './BaseManager.ts' | import { BaseManager } from "./BaseManager.ts"; | ||||||
| 
 | 
 | ||||||
| export class ChannelsManager extends BaseManager<ChannelPayload, Channel> { | export class ChannelsManager extends BaseManager<ChannelPayload, Channel> { | ||||||
|   constructor (client: Client) { |   constructor(client: Client) { | ||||||
|     super(client, 'channels', User) |     super(client, "channels", Channel) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Override get method as Generic
 |   // Override get method as Generic
 | ||||||
|   async get<T = Channel> (key: string): Promise<T> { |   async get<T = Channel>(key: string): Promise<T | undefined> { | ||||||
|     return new this.DataType(this.client, this._get(key)) |     const data = await this._get(key) | ||||||
|  |     if (data === undefined) return | ||||||
|  |     let guild | ||||||
|  |     if ((data as any).guild_id !== undefined) { | ||||||
|  |       guild = await this.client.guilds.get((data as any).guild_id) | ||||||
|  |     } | ||||||
|  |     const res = getChannelByType(this.client, data, guild) | ||||||
|  |     return res as any | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async fetch (id: string): Promise<Channel> { |   async array(): Promise<undefined | Channel[]> { | ||||||
|  |     const arr = await (this.client.cache.array(this.cacheName) as ChannelPayload[]) | ||||||
|  |     const result: any[] = [] | ||||||
|  |     for (const elem of arr) { | ||||||
|  |       let guild | ||||||
|  |       if ((elem as any).guild_id !== undefined) { | ||||||
|  |         guild = await this.client.guilds.get((elem as any).guild_id) | ||||||
|  |       } | ||||||
|  |       result.push(getChannelByType(this.client, elem, guild)) | ||||||
|  |     } | ||||||
|  |     return result | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async fetch(id: string): Promise<Channel> { | ||||||
|     return await new Promise((resolve, reject) => { |     return await new Promise((resolve, reject) => { | ||||||
|       this.client.rest |       this.client.rest.get(CHANNEL(id)).then(async data => { | ||||||
|         .get(CHANNEL(id)) |         this.set(id, data as ChannelPayload) | ||||||
|         .then(data => { |         let guild | ||||||
|           this.set(id, data as ChannelPayload) |         if (data.guild_id !== undefined) { | ||||||
|           resolve(new Channel(this.client, data as ChannelPayload)) |           guild = await this.client.guilds.get(data.guild_id) | ||||||
|         }) |         } | ||||||
|         .catch(e => reject(e)) |         resolve(getChannelByType(this.client, data as ChannelPayload, guild)) | ||||||
|  |       }).catch(e => reject(e)) | ||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										45
									
								
								src/managers/GuildChannelsManager.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/managers/GuildChannelsManager.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,45 @@ | ||||||
|  | import { Client } from "../models/client.ts"; | ||||||
|  | import { Channel } from "../structures/channel.ts"; | ||||||
|  | import { Guild } from "../structures/guild.ts"; | ||||||
|  | import { CategoryChannel } from "../structures/guildCategoryChannel.ts"; | ||||||
|  | import { GuildTextChannel } from "../structures/guildTextChannel.ts"; | ||||||
|  | import { VoiceChannel } from "../structures/guildVoiceChannel.ts"; | ||||||
|  | import { GuildChannelCategoryPayload, GuildTextChannelPayload, GuildVoiceChannelPayload } from "../types/channel.ts"; | ||||||
|  | import { CHANNEL } from "../types/endpoint.ts"; | ||||||
|  | import { BaseChildManager } from "./BaseChildManager.ts"; | ||||||
|  | import { ChannelsManager } from "./ChannelsManager.ts"; | ||||||
|  | 
 | ||||||
|  | export type GuildChannelPayloads = GuildTextChannelPayload | GuildVoiceChannelPayload | GuildChannelCategoryPayload | ||||||
|  | export type GuildChannel = GuildTextChannel | VoiceChannel | CategoryChannel | ||||||
|  | 
 | ||||||
|  | export class GuildChannelsManager extends BaseChildManager<GuildChannelPayloads, GuildChannel> { | ||||||
|  |   guild: Guild | ||||||
|  | 
 | ||||||
|  |   constructor(client: Client, parent: ChannelsManager, guild: Guild) { | ||||||
|  |     super(client, parent as any) | ||||||
|  |     this.guild = guild | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async get(id: string): Promise<GuildChannel | undefined> { | ||||||
|  |     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<boolean> { | ||||||
|  |     return this.client.rest.delete(CHANNEL(id)) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async array(): Promise<GuildChannel[]> { | ||||||
|  |     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<boolean> { | ||||||
|  |     const arr = await this.array() | ||||||
|  |     for (const elem of arr) { | ||||||
|  |       this.parent.delete(elem.id) | ||||||
|  |     } | ||||||
|  |     return true | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | @ -1,23 +1,27 @@ | ||||||
| import { Client } from '../models/client.ts' | import { Client } from "../models/client.ts"; | ||||||
| import { Guild } from '../structures/guild.ts' | import { Guild } from "../structures/guild.ts"; | ||||||
| import { GUILD } from '../types/endpoint.ts' | import { GUILD } from "../types/endpoint.ts"; | ||||||
| import { GuildPayload } from '../types/guild.ts' | import { GuildPayload, MemberPayload } from "../types/guild.ts"; | ||||||
| import { BaseManager } from './BaseManager.ts' | import { BaseManager } from "./BaseManager.ts"; | ||||||
|  | import { MembersManager } from "./MembersManager.ts"; | ||||||
| 
 | 
 | ||||||
| export class GuildManager extends BaseManager<GuildPayload, Guild> { | export class GuildManager extends BaseManager<GuildPayload, Guild> { | ||||||
|   constructor (client: Client) { |   constructor (client: Client) { | ||||||
|     super(client, 'guilds', Guild) |     super(client, 'guilds', Guild) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async fetch (id: string): Promise<Guild> { |   async fetch(id: string): Promise<Guild> { | ||||||
|     return await new Promise((resolve, reject) => { |     return await new Promise((resolve, reject) => { | ||||||
|       this.client.rest |       this.client.rest.get(GUILD(id)).then(async (data: any) => { | ||||||
|         .get(GUILD(id)) |         this.set(id, data) | ||||||
|         .then(data => { |         const guild = new Guild(this.client, data) | ||||||
|           this.set(id, data as GuildPayload) |         if ((data as GuildPayload).members !== undefined) { | ||||||
|           resolve(new Guild(this.client, data as GuildPayload)) |           const members = new MembersManager(this.client, guild) | ||||||
|         }) |           await members.fromPayload((data as GuildPayload).members as MemberPayload[]) | ||||||
|         .catch(e => reject(e)) |           guild.members = members | ||||||
|  |         } | ||||||
|  |         resolve(guild) | ||||||
|  |       }).catch(e => reject(e)) | ||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										30
									
								
								src/managers/MembersManager.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/managers/MembersManager.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | ||||||
|  | import { Client } from "../models/client.ts"; | ||||||
|  | import { Guild } from "../structures/guild.ts"; | ||||||
|  | import { Member } from "../structures/member.ts"; | ||||||
|  | import { GUILD_MEMBER } from "../types/endpoint.ts"; | ||||||
|  | import { MemberPayload } from "../types/guild.ts"; | ||||||
|  | import { BaseManager } from "./BaseManager.ts"; | ||||||
|  | 
 | ||||||
|  | export class MembersManager extends BaseManager<MemberPayload, Member> { | ||||||
|  |   guild: Guild | ||||||
|  | 
 | ||||||
|  |   constructor(client: Client, guild: Guild) { | ||||||
|  |     super(client, `members:${guild.id}`, Member) | ||||||
|  |     this.guild = guild | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async fetch(id: string): Promise<Member> { | ||||||
|  |     return await new Promise((resolve, reject) => { | ||||||
|  |       this.client.rest.get(GUILD_MEMBER(this.guild.id, id)).then(data => { | ||||||
|  |         this.set(id, data as MemberPayload) | ||||||
|  |         resolve(new Member(this.client, data as MemberPayload)) | ||||||
|  |       }).catch(e => reject(e)) | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async fromPayload(members: MemberPayload[]): Promise<void> { | ||||||
|  |     for (const member of members) { | ||||||
|  |       await this.set(member.user.id, member) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | @ -1,43 +1,40 @@ | ||||||
| import { Client } from '../models/client.ts' | import { Client } from "../models/client.ts"; | ||||||
| import { Message } from '../structures/message.ts' | import { Message } from "../structures/message.ts"; | ||||||
| import { MessageMentions } from '../structures/MessageMentions.ts' | import { MessageMentions } from "../structures/MessageMentions.ts"; | ||||||
| import { User } from '../structures/user.ts' | import { TextChannel } from "../structures/textChannel.ts"; | ||||||
| import { MessagePayload } from '../types/channel.ts' | import { User } from "../structures/user.ts"; | ||||||
| import { CHANNEL_MESSAGE } from '../types/endpoint.ts' | import { MessagePayload } from "../types/channel.ts"; | ||||||
| import { BaseManager } from './BaseManager.ts' | import { CHANNEL_MESSAGE } from "../types/endpoint.ts"; | ||||||
|  | import { BaseManager } from "./BaseManager.ts"; | ||||||
| 
 | 
 | ||||||
| export class MessagesManager extends BaseManager<MessagePayload, Message> { | export class MessagesManager extends BaseManager<MessagePayload, Message> { | ||||||
|   constructor (client: Client) { |   constructor (client: Client) { | ||||||
|     super(client, 'messages', Message) |     super(client, 'messages', Message) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async fetch (channelID: string, id: string): Promise<Message> { |   async get(key: string): Promise<Message | undefined> { | ||||||
|  |     const raw = await this._get(key) | ||||||
|  |     if (raw === undefined) return | ||||||
|  |     let channel = await this.client.channels.get(raw.channel_id) | ||||||
|  |     if (channel === undefined) channel = await this.client.channels.fetch(raw.channel_id) | ||||||
|  |     if (channel === undefined) return | ||||||
|  |     const author = new User(this.client, raw.author) | ||||||
|  |     const mentions = new MessageMentions() | ||||||
|  |     return new this.DataType(this.client, raw, channel, author, mentions) as any | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async fetch(channelID: string, id: string): Promise<Message> { | ||||||
|     return await new Promise((resolve, reject) => { |     return await new Promise((resolve, reject) => { | ||||||
|       this.client.rest |       this.client.rest.get(CHANNEL_MESSAGE(channelID, id)).then(async data => { | ||||||
|         .get(CHANNEL_MESSAGE(channelID, id)) |         this.set(id, data as MessagePayload) | ||||||
|         .then(async data => { |         let channel: any = await this.client.channels.get<TextChannel>(channelID) | ||||||
|           this.set(id, data as MessagePayload) |         if (channel === undefined) channel = await this.client.channels.fetch(channelID) | ||||||
|           let channel = await this.client.channels.get(channelID) |         const author = new User(this.client, (data as MessagePayload).author) | ||||||
|           if (channel === undefined) |         await this.client.users.set(author.id, (data as MessagePayload).author) | ||||||
|             channel = await this.client.channels.fetch(channelID) |         // TODO: Make this thing work (MessageMentions)
 | ||||||
|           const author = new User(this.client, (data as MessagePayload).author) |         const mentions = new MessageMentions() | ||||||
|           await this.client.users.set( |         resolve(new Message(this.client, data as MessagePayload, channel as TextChannel, author, mentions)) | ||||||
|             author.id, |       }).catch(e => reject(e)) | ||||||
|             (data as MessagePayload).author |  | ||||||
|           ) |  | ||||||
|           // TODO: Make this thing work (MessageMentions)
 |  | ||||||
|           const mentions = new MessageMentions() |  | ||||||
|           resolve( |  | ||||||
|             new Message( |  | ||||||
|               this.client, |  | ||||||
|               data as MessagePayload, |  | ||||||
|               channel, |  | ||||||
|               author, |  | ||||||
|               mentions |  | ||||||
|             ) |  | ||||||
|           ) |  | ||||||
|         }) |  | ||||||
|         .catch(e => reject(e)) |  | ||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -24,4 +24,11 @@ export class RolesManager extends BaseManager<RolePayload, Role> { | ||||||
|         .catch(e => reject(e)) |         .catch(e => reject(e)) | ||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   async fromPayload(roles: RolePayload[]): Promise<boolean> { | ||||||
|  |     for (const role of roles) { | ||||||
|  |       await this.set(role.id, role) | ||||||
|  |     } | ||||||
|  |     return true | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -8,10 +8,11 @@ import { | ||||||
| 
 | 
 | ||||||
| export interface ICacheAdapter { | export interface ICacheAdapter { | ||||||
|   client: Client |   client: Client | ||||||
|   get: (cacheName: string, key: string) => Promise<undefined | any> |   get: (cacheName: string, key: string) => Promise<any> | any | ||||||
|   set: (cacheName: string, key: string, value: any) => Promise<any> |   set: (cacheName: string, key: string, value: any) => Promise<any> | any | ||||||
|   delete: (cacheName: string, key: string) => Promise<boolean> |   delete: (cacheName: string, key: string) => Promise<boolean> | boolean | ||||||
|   array: (cacheName: string) => Promise<any[] | undefined> |   array: (cacheName: string) => undefined | any[] | Promise<any[] | undefined> | ||||||
|  |   deleteCache: (cacheName: string) => any | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export class DefaultCacheAdapter implements ICacheAdapter { | export class DefaultCacheAdapter implements ICacheAdapter { | ||||||
|  | @ -50,6 +51,11 @@ export class DefaultCacheAdapter implements ICacheAdapter { | ||||||
|     if (cache === undefined) return |     if (cache === undefined) return | ||||||
|     return cache.array() |     return cache.array() | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   async deleteCache(cacheName: string): Promise<boolean> { | ||||||
|  |     // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
 | ||||||
|  |     return delete this.data[cacheName] | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export class RedisCacheAdapter implements ICacheAdapter { | export class RedisCacheAdapter implements ICacheAdapter { | ||||||
|  | @ -114,4 +120,9 @@ export class RedisCacheAdapter implements ICacheAdapter { | ||||||
|     const data = await this.redis?.hvals(cacheName) |     const data = await this.redis?.hvals(cacheName) | ||||||
|     return data?.map((e: string) => JSON.parse(e)) |     return data?.map((e: string) => JSON.parse(e)) | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   async deleteCache(cacheName: string): Promise<boolean> { | ||||||
|  |     await this._checkReady() | ||||||
|  |     return await this.redis?.del(cacheName) !== 0 | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -3,18 +3,21 @@ import { GatewayIntents } from '../types/gateway.ts' | ||||||
| import { Gateway } from '../gateway/index.ts' | import { Gateway } from '../gateway/index.ts' | ||||||
| import { RESTManager } from './rest.ts' | import { RESTManager } from './rest.ts' | ||||||
| import EventEmitter from 'https://deno.land/std@0.74.0/node/events.ts' | import EventEmitter from 'https://deno.land/std@0.74.0/node/events.ts' | ||||||
| import { DefaultCacheAdapter, ICacheAdapter } from './CacheAdapter.ts' | import { DefaultCacheAdapter, ICacheAdapter } from "./CacheAdapter.ts" | ||||||
| import { UserManager } from '../managers/UsersManager.ts' | import { UserManager } from "../managers/UsersManager.ts" | ||||||
| import { GuildManager } from '../managers/GuildsManager.ts' | import { GuildManager } from "../managers/GuildsManager.ts" | ||||||
| import { EmojisManager } from '../managers/EmojisManager.ts' | import { EmojisManager } from "../managers/EmojisManager.ts" | ||||||
| import { ChannelsManager } from '../managers/ChannelsManager.ts' | import { ChannelsManager } from "../managers/ChannelsManager.ts" | ||||||
| import { MessagesManager } from '../managers/MessagesManager.ts' | import { MessagesManager } from "../managers/MessagesManager.ts" | ||||||
|  | import { ActivityGame, ClientActivity, ClientPresence } from "../structures/presence.ts" | ||||||
| 
 | 
 | ||||||
| /** Some Client Options to modify behaviour */ | /** Some Client Options to modify behaviour */ | ||||||
| export interface ClientOptions { | export interface ClientOptions { | ||||||
|   token?: string |   token?: string | ||||||
|   intents?: GatewayIntents[] |   intents?: GatewayIntents[] | ||||||
|   cache?: ICacheAdapter |   cache?: ICacheAdapter, | ||||||
|  |   forceNewSession?: boolean, | ||||||
|  |   presence?: ClientPresence | ClientActivity | ActivityGame | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  | @ -28,18 +31,22 @@ export class Client extends EventEmitter { | ||||||
|   token?: string |   token?: string | ||||||
|   cache: ICacheAdapter = new DefaultCacheAdapter(this) |   cache: ICacheAdapter = new DefaultCacheAdapter(this) | ||||||
|   intents?: GatewayIntents[] |   intents?: GatewayIntents[] | ||||||
| 
 |   forceNewSession?: boolean | ||||||
|   users: UserManager = new UserManager(this) |   users: UserManager = new UserManager(this) | ||||||
|   guilds: GuildManager = new GuildManager(this) |   guilds: GuildManager = new GuildManager(this) | ||||||
|   channels: ChannelsManager = new ChannelsManager(this) |   channels: ChannelsManager = new ChannelsManager(this) | ||||||
|   messages: MessagesManager = new MessagesManager(this) |   messages: MessagesManager = new MessagesManager(this) | ||||||
|   emojis: EmojisManager = new EmojisManager(this) |   emojis: EmojisManager = new EmojisManager(this) | ||||||
| 
 | 
 | ||||||
|  |   presence: ClientPresence = new ClientPresence() | ||||||
|  | 
 | ||||||
|   constructor (options: ClientOptions = {}) { |   constructor (options: ClientOptions = {}) { | ||||||
|     super() |     super() | ||||||
|     this.token = options.token |     this.token = options.token | ||||||
|     this.intents = options.intents |     this.intents = options.intents | ||||||
|  |     this.forceNewSession = options.forceNewSession | ||||||
|     if (options.cache !== undefined) this.cache = options.cache |     if (options.cache !== undefined) this.cache = options.cache | ||||||
|  |     if (options.presence !== undefined) this.presence = options.presence instanceof ClientPresence ? options.presence : new ClientPresence(options.presence) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   setAdapter (adapter: ICacheAdapter): Client { |   setAdapter (adapter: ICacheAdapter): Client { | ||||||
|  | @ -47,8 +54,15 @@ export class Client extends EventEmitter { | ||||||
|     return this |     return this | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   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()) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   debug (tag: string, msg: string): void { |   debug (tag: string, msg: string): void { | ||||||
|     this.emit('debug', `[${tag}] ${msg}`) |     this.emit("debug", `[${tag}] ${msg}`) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|  |  | ||||||
|  | @ -52,7 +52,7 @@ export class RESTManager { | ||||||
| 
 | 
 | ||||||
|   constructor (client: Client) { |   constructor (client: Client) { | ||||||
|     this.client = client |     this.client = client | ||||||
|     setTimeout(this.processRateLimitedPaths, 1000) |     setTimeout(() => this.processRateLimitedPaths, 1000) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async processRateLimitedPaths (): Promise<void> { |   async processRateLimitedPaths (): Promise<void> { | ||||||
|  | @ -158,7 +158,7 @@ export class RESTManager { | ||||||
|       'User-Agent': `DiscordBot (discord.deno)` |       'User-Agent': `DiscordBot (discord.deno)` | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (this.client.token !== undefined) delete headers.Authorization |     if (this.client.token === undefined) delete headers.Authorization | ||||||
| 
 | 
 | ||||||
|     if (method === 'get') body = undefined |     if (method === 'get') body = undefined | ||||||
| 
 | 
 | ||||||
|  | @ -233,9 +233,11 @@ export class RESTManager { | ||||||
|           const urlToUse = |           const urlToUse = | ||||||
|             method === 'get' && query !== '' ? `${url}?${query}` : url |             method === 'get' && query !== '' ? `${url}?${query}` : url | ||||||
| 
 | 
 | ||||||
|  |           const requestData = this.createRequestBody(body, method) | ||||||
|  | 
 | ||||||
|           const response = await fetch( |           const response = await fetch( | ||||||
|             urlToUse, |             urlToUse, | ||||||
|             this.createRequestBody(body, method) |             requestData | ||||||
|           ) |           ) | ||||||
|           const bucketIDFromHeaders = this.processHeaders(url, response.headers) |           const bucketIDFromHeaders = this.processHeaders(url, response.headers) | ||||||
|           this.handleStatusCode(response, errorStack) |           this.handleStatusCode(response, errorStack) | ||||||
|  | @ -302,15 +304,17 @@ export class RESTManager { | ||||||
|     // eslint-disable-next-line @typescript-eslint/no-floating-promises
 |     // eslint-disable-next-line @typescript-eslint/no-floating-promises
 | ||||||
|     this.logErrors(response, errorStack) |     this.logErrors(response, errorStack) | ||||||
| 
 | 
 | ||||||
|  |     if(status === HttpResponseCode.Unauthorized) throw new Error("Request was not successful. Invalid Token.") | ||||||
|  | 
 | ||||||
|     switch (status) { |     switch (status) { | ||||||
|       case HttpResponseCode.BadRequest: |       case HttpResponseCode.BadRequest: | ||||||
|       case HttpResponseCode.Unauthorized: |       case HttpResponseCode.Unauthorized: | ||||||
|       case HttpResponseCode.Forbidden: |       case HttpResponseCode.Forbidden: | ||||||
|       case HttpResponseCode.NotFound: |       case HttpResponseCode.NotFound: | ||||||
|       case HttpResponseCode.MethodNotAllowed: |       case HttpResponseCode.MethodNotAllowed: | ||||||
|         throw new Error('Request Client Error') |         throw new Error('Request Client Error.') | ||||||
|       case HttpResponseCode.GatewayUnavailable: |       case HttpResponseCode.GatewayUnavailable: | ||||||
|         throw new Error('Request Server Error') |         throw new Error('Request Server Error.') | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // left are all unknown
 |     // left are all unknown
 | ||||||
|  |  | ||||||
|  | @ -9,7 +9,6 @@ export class DMChannel extends TextChannel { | ||||||
|   constructor (client: Client, data: DMChannelPayload) { |   constructor (client: Client, data: DMChannelPayload) { | ||||||
|     super(client, data) |     super(client, data) | ||||||
|     this.recipients = data.recipients |     this.recipients = data.recipients | ||||||
|     // cache.set('dmchannel', this.id, this)
 |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   protected readFromData (data: DMChannelPayload): void { |   protected readFromData (data: DMChannelPayload): void { | ||||||
|  |  | ||||||
|  | @ -2,13 +2,12 @@ import { Client } from '../models/client.ts' | ||||||
| import { GuildFeatures, GuildPayload } from '../types/guild.ts' | import { GuildFeatures, GuildPayload } from '../types/guild.ts' | ||||||
| import { PresenceUpdatePayload } from '../types/gateway.ts' | import { PresenceUpdatePayload } from '../types/gateway.ts' | ||||||
| import { Base } from './base.ts' | import { Base } from './base.ts' | ||||||
| import { Channel } from './channel.ts' |  | ||||||
| import { Emoji } from './emoji.ts' | import { Emoji } from './emoji.ts' | ||||||
| import { Member } from './member.ts' |  | ||||||
| import { VoiceState } from './voiceState.ts' | import { VoiceState } from './voiceState.ts' | ||||||
| import cache from '../models/cache.ts' | import cache from '../models/cache.ts' | ||||||
| import getChannelByType from '../utils/getChannelByType.ts' | import { RolesManager } from "../managers/RolesManager.ts" | ||||||
| import { RolesManager } from '../managers/RolesManager.ts' | import { GuildChannelsManager } from "../managers/GuildChannelsManager.ts" | ||||||
|  | import { MembersManager } from "../managers/MembersManager.ts" | ||||||
| 
 | 
 | ||||||
| export class Guild extends Base { | export class Guild extends Base { | ||||||
|   id: string |   id: string | ||||||
|  | @ -28,7 +27,7 @@ export class Guild extends Base { | ||||||
|   verificationLevel?: string |   verificationLevel?: string | ||||||
|   defaultMessageNotifications?: string |   defaultMessageNotifications?: string | ||||||
|   explicitContentFilter?: string |   explicitContentFilter?: string | ||||||
|   roles: RolesManager = new RolesManager(this.client, this) |   roles: RolesManager | ||||||
|   emojis?: Emoji[] |   emojis?: Emoji[] | ||||||
|   features?: GuildFeatures[] |   features?: GuildFeatures[] | ||||||
|   mfaLevel?: string |   mfaLevel?: string | ||||||
|  | @ -41,8 +40,8 @@ export class Guild extends Base { | ||||||
|   unavailable: boolean |   unavailable: boolean | ||||||
|   memberCount?: number |   memberCount?: number | ||||||
|   voiceStates?: VoiceState[] |   voiceStates?: VoiceState[] | ||||||
|   members?: Member[] |   members: MembersManager  | ||||||
|   channels?: Channel[] |   channels: GuildChannelsManager | ||||||
|   presences?: PresenceUpdatePayload[] |   presences?: PresenceUpdatePayload[] | ||||||
|   maxPresences?: number |   maxPresences?: number | ||||||
|   maxMembers?: number |   maxMembers?: number | ||||||
|  | @ -61,6 +60,9 @@ export class Guild extends Base { | ||||||
|     super(client, data) |     super(client, data) | ||||||
|     this.id = data.id |     this.id = data.id | ||||||
|     this.unavailable = data.unavailable |     this.unavailable = data.unavailable | ||||||
|  |     this.members = new MembersManager(this.client, this) | ||||||
|  |     this.channels = new GuildChannelsManager(this.client, this.client.channels, this) | ||||||
|  |     this.roles = new RolesManager(this.client, this) | ||||||
| 
 | 
 | ||||||
|     if (!this.unavailable) { |     if (!this.unavailable) { | ||||||
|       this.name = data.name |       this.name = data.name | ||||||
|  | @ -167,22 +169,22 @@ export class Guild extends Base { | ||||||
|       this.joinedAt = data.joined_at ?? this.joinedAt |       this.joinedAt = data.joined_at ?? this.joinedAt | ||||||
|       this.large = data.large ?? this.large |       this.large = data.large ?? this.large | ||||||
|       this.memberCount = data.member_count ?? this.memberCount |       this.memberCount = data.member_count ?? this.memberCount | ||||||
|       this.voiceStates = |       // this.voiceStates =
 | ||||||
|         data.voice_states?.map( |       //   data.voice_states?.map(
 | ||||||
|           v => |       //     v =>
 | ||||||
|             cache.get('voiceState', `${v.guild_id}:${v.user_id}`) ?? |       //       cache.get('voiceState', `${v.guild_id}:${v.user_id}`) ??
 | ||||||
|             new VoiceState(this.client, v) |       //       new VoiceState(this.client, v)
 | ||||||
|         ) ?? this.voiceStates |       //   ) ?? this.voiceStates
 | ||||||
|       this.members = |       // this.members =
 | ||||||
|         data.members?.map( |       //   data.members?.map(
 | ||||||
|           v => |       //     v =>
 | ||||||
|             cache.get('member', `${this.id}:${v.user.id}`) ?? |       //       cache.get('member', `${this.id}:${v.user.id}`) ??
 | ||||||
|             new Member(this.client, v) |       //       new Member(this.client, v)
 | ||||||
|         ) ?? this.members |       //   ) ?? this.members
 | ||||||
|       this.channels = |       // this.channels =
 | ||||||
|         data.channels?.map( |       //   data.channels?.map(
 | ||||||
|           v => cache.get('channel', v.id) ?? getChannelByType(this.client, v) |       //     v => cache.get('channel', v.id) ?? getChannelByType(this.client, v, this)
 | ||||||
|         ) ?? this.members |       //   ) ?? this.members
 | ||||||
|       this.presences = data.presences ?? this.presences |       this.presences = data.presences ?? this.presences | ||||||
|       this.maxPresences = data.max_presences ?? this.maxPresences |       this.maxPresences = data.max_presences ?? this.maxPresences | ||||||
|       this.maxMembers = data.max_members ?? this.maxMembers |       this.maxMembers = data.max_members ?? this.maxMembers | ||||||
|  |  | ||||||
|  | @ -1,6 +1,10 @@ | ||||||
| import { Client } from '../models/client.ts' | import { Client } from '../models/client.ts' | ||||||
| import { Channel } from './channel.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 { | export class CategoryChannel extends Channel { | ||||||
|   guildID: string |   guildID: string | ||||||
|  | @ -8,12 +12,14 @@ export class CategoryChannel extends Channel { | ||||||
|   position: number |   position: number | ||||||
|   permissionOverwrites: Overwrite[] |   permissionOverwrites: Overwrite[] | ||||||
|   nsfw: boolean |   nsfw: boolean | ||||||
|  |   guild: Guild | ||||||
|   parentID?: string |   parentID?: string | ||||||
| 
 | 
 | ||||||
|   constructor (client: Client, data: GuildChannelCategoryPayload) { |   constructor (client: Client, data: GuildChannelCategoryPayload, guild: Guild) { | ||||||
|     super(client, data) |     super(client, data) | ||||||
|     this.guildID = data.guild_id |     this.guildID = data.guild_id | ||||||
|     this.name = data.name |     this.name = data.name | ||||||
|  |     this.guild = guild | ||||||
|     this.position = data.position |     this.position = data.position | ||||||
|     this.permissionOverwrites = data.permission_overwrites |     this.permissionOverwrites = data.permission_overwrites | ||||||
|     this.nsfw = data.nsfw |     this.nsfw = data.nsfw | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| import { Client } from '../models/client.ts' | import { Client } from '../models/client.ts' | ||||||
| import { GuildTextChannelPayload, Overwrite } from '../types/channel.ts' | import { GuildTextChannelPayload, Overwrite } from '../types/channel.ts' | ||||||
| import { TextChannel } from './textChannel.ts' | import { TextChannel } from './textChannel.ts' | ||||||
|  | import { Guild } from "./guild.ts" | ||||||
| 
 | 
 | ||||||
| export class GuildTextChannel extends TextChannel { | export class GuildTextChannel extends TextChannel { | ||||||
|   guildID: string |   guildID: string | ||||||
|  | @ -11,15 +12,17 @@ export class GuildTextChannel extends TextChannel { | ||||||
|   parentID?: string |   parentID?: string | ||||||
|   rateLimit: number |   rateLimit: number | ||||||
|   topic?: string |   topic?: string | ||||||
|  |   guild: Guild | ||||||
| 
 | 
 | ||||||
|   get mention (): string { |   get mention (): string { | ||||||
|     return `<#${this.id}>` |     return `<#${this.id}>` | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   constructor (client: Client, data: GuildTextChannelPayload) { |   constructor (client: Client, data: GuildTextChannelPayload, guild: Guild) { | ||||||
|     super(client, data) |     super(client, data) | ||||||
|     this.guildID = data.guild_id |     this.guildID = data.guild_id | ||||||
|     this.name = data.name |     this.name = data.name | ||||||
|  |     this.guild = guild | ||||||
|     this.position = data.position |     this.position = data.position | ||||||
|     this.permissionOverwrites = data.permission_overwrites |     this.permissionOverwrites = data.permission_overwrites | ||||||
|     this.nsfw = data.nsfw |     this.nsfw = data.nsfw | ||||||
|  |  | ||||||
|  | @ -1,24 +1,27 @@ | ||||||
| import { Client } from '../models/client.ts' | import { Client } from '../models/client.ts' | ||||||
| import { GuildVoiceChannelPayload, Overwrite } from '../types/channel.ts' | import { GuildVoiceChannelPayload, Overwrite } from '../types/channel.ts' | ||||||
| import { Channel } from './channel.ts' | import { Channel } from './channel.ts' | ||||||
|  | import { Guild } from "./guild.ts" | ||||||
| 
 | 
 | ||||||
| export class VoiceChannel extends Channel { | export class VoiceChannel extends Channel { | ||||||
|   bitrate: string |   bitrate: string | ||||||
|   userLimit: number |   userLimit: number | ||||||
|   guildID: string |   guildID: string | ||||||
|   name: string |   name: string | ||||||
|  |   guild: Guild | ||||||
|   position: number |   position: number | ||||||
|   permissionOverwrites: Overwrite[] |   permissionOverwrites: Overwrite[] | ||||||
|   nsfw: boolean |   nsfw: boolean | ||||||
|   parentID?: string |   parentID?: string | ||||||
| 
 | 
 | ||||||
|   constructor (client: Client, data: GuildVoiceChannelPayload) { |   constructor (client: Client, data: GuildVoiceChannelPayload, guild: Guild) { | ||||||
|     super(client, data) |     super(client, data) | ||||||
|     this.bitrate = data.bitrate |     this.bitrate = data.bitrate | ||||||
|     this.userLimit = data.user_limit |     this.userLimit = data.user_limit | ||||||
|     this.guildID = data.guild_id |     this.guildID = data.guild_id | ||||||
|     this.name = data.name |     this.name = data.name | ||||||
|     this.position = data.position |     this.position = data.position | ||||||
|  |     this.guild = guild | ||||||
|     this.permissionOverwrites = data.permission_overwrites |     this.permissionOverwrites = data.permission_overwrites | ||||||
|     this.nsfw = data.nsfw |     this.nsfw = data.nsfw | ||||||
|     this.parentID = data.parent_id |     this.parentID = data.parent_id | ||||||
|  |  | ||||||
|  | @ -1,9 +1,11 @@ | ||||||
| import { Client } from '../models/client.ts' | import { Client } from '../models/client.ts' | ||||||
| import { GuildNewsChannelPayload, Overwrite } from '../types/channel.ts' | import { GuildNewsChannelPayload, Overwrite } from '../types/channel.ts' | ||||||
|  | import { Guild } from "./guild.ts" | ||||||
| import { TextChannel } from './textChannel.ts' | import { TextChannel } from './textChannel.ts' | ||||||
| 
 | 
 | ||||||
| export class NewsChannel extends TextChannel { | export class NewsChannel extends TextChannel { | ||||||
|   guildID: string |   guildID: string | ||||||
|  |   guild: Guild | ||||||
|   name: string |   name: string | ||||||
|   position: number |   position: number | ||||||
|   permissionOverwrites: Overwrite[] |   permissionOverwrites: Overwrite[] | ||||||
|  | @ -11,10 +13,11 @@ export class NewsChannel extends TextChannel { | ||||||
|   parentID?: string |   parentID?: string | ||||||
|   topic?: string |   topic?: string | ||||||
| 
 | 
 | ||||||
|   constructor (client: Client, data: GuildNewsChannelPayload) { |   constructor (client: Client, data: GuildNewsChannelPayload, guild: Guild) { | ||||||
|     super(client, data) |     super(client, data) | ||||||
|     this.guildID = data.guild_id |     this.guildID = data.guild_id | ||||||
|     this.name = data.name |     this.name = data.name | ||||||
|  |     this.guild = guild | ||||||
|     this.position = data.position |     this.position = data.position | ||||||
|     this.permissionOverwrites = data.permission_overwrites |     this.permissionOverwrites = data.permission_overwrites | ||||||
|     this.nsfw = data.nsfw |     this.nsfw = data.nsfw | ||||||
|  |  | ||||||
|  | @ -14,17 +14,19 @@ import { User } from './user.ts' | ||||||
| import { Member } from './member.ts' | import { Member } from './member.ts' | ||||||
| import { Embed } from './embed.ts' | import { Embed } from './embed.ts' | ||||||
| import { CHANNEL_MESSAGE } from '../types/endpoint.ts' | import { CHANNEL_MESSAGE } from '../types/endpoint.ts' | ||||||
| import { Channel } from './channel.ts' | import { MessageMentions } from "./MessageMentions.ts" | ||||||
| import { MessageMentions } from './MessageMentions.ts' | import { TextChannel } from "./textChannel.ts" | ||||||
| import { TextChannel } from './textChannel.ts' | import { DMChannel } from "./dmChannel.ts" | ||||||
|  | import { Guild } from "./guild.ts" | ||||||
| 
 | 
 | ||||||
| export class Message extends Base { | export class Message extends Base { | ||||||
|   // eslint-disable-next-line @typescript-eslint/prefer-readonly
 |   // eslint-disable-next-line @typescript-eslint/prefer-readonly
 | ||||||
|   private data: MessagePayload |   private data: MessagePayload | ||||||
|   id: string |   id: string | ||||||
|   channelID: string |   channelID: string | ||||||
|   channel: Channel |   channel: TextChannel | ||||||
|   guildID?: string |   guildID?: string | ||||||
|  |   guild?: Guild | ||||||
|   author: User |   author: User | ||||||
|   member?: Member |   member?: Member | ||||||
|   content: string |   content: string | ||||||
|  | @ -50,7 +52,7 @@ export class Message extends Base { | ||||||
|   constructor ( |   constructor ( | ||||||
|     client: Client, |     client: Client, | ||||||
|     data: MessagePayload, |     data: MessagePayload, | ||||||
|     channel: Channel, |     channel: TextChannel, | ||||||
|     author: User, |     author: User, | ||||||
|     mentions: MessageMentions |     mentions: MessageMentions | ||||||
|   ) { |   ) { | ||||||
|  | @ -122,9 +124,13 @@ export class Message extends Base { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async edit (text?: string, option?: MessageOption): Promise<Message> { |   async edit (text?: string, option?: MessageOption): Promise<Message> { | ||||||
|     // Seriously eslint?
 |     return this.channel.edit(this.id, text, option)   | ||||||
|     // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
 |   } | ||||||
|     return (this.channel as TextChannel).editMessage(this.id, text, option) | 
 | ||||||
|  |   async reply(text: string, options?: MessageOption): Promise<Message> { | ||||||
|  |     // TODO: Use inline replies once they're out
 | ||||||
|  |     if (this.channel instanceof DMChannel) return this.channel.send(text, options) | ||||||
|  |     return this.channel.send(`${this.author.mention}, ${text}`, options) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async delete (): Promise<void> { |   async delete (): Promise<void> { | ||||||
|  |  | ||||||
							
								
								
									
										123
									
								
								src/structures/presence.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								src/structures/presence.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,123 @@ | ||||||
|  | export type ActivityType = 'PLAYING' | 'STREAMING' | 'LISTENING' | 'WATCHING' | 'CUSTOM_STATUS' | 'COMPETING'; | ||||||
|  | export type StatusType = 'online' | 'invisible' | 'offline' | 'idle' | 'dnd'; | ||||||
|  | 
 | ||||||
|  | export enum ActivityTypes { | ||||||
|  |   PLAYING = 0, | ||||||
|  |   STREAMING = 1, | ||||||
|  |   LISTENING = 2, | ||||||
|  |   WATCHING = 3, | ||||||
|  |   CUSTOM_STATUS = 4, | ||||||
|  |   COMPETING = 5, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export interface ActivityGame { | ||||||
|  |   name: string; | ||||||
|  |   type: 0 | 1 | 2 | 3 | 4 | 5 | ActivityType; | ||||||
|  |   url?: string; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export interface ClientActivity { | ||||||
|  |   status?: StatusType | ||||||
|  |   activity?: ActivityGame | ActivityGame[] | ||||||
|  |   since?: number | null | ||||||
|  |   afk?: boolean | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export interface ClientActivityPayload { | ||||||
|  |   status: StatusType | ||||||
|  |   activities: ActivityGame[] | null | ||||||
|  |   since: number | null | ||||||
|  |   afk: boolean | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export class ClientPresence { | ||||||
|  |   status: StatusType = 'online' | ||||||
|  |   activity?: ActivityGame | ActivityGame[]  | ||||||
|  |   since?: number | null | ||||||
|  |   afk?: boolean | ||||||
|  | 
 | ||||||
|  |   constructor(data?: ClientActivity | ClientActivityPayload | ActivityGame) { | ||||||
|  |     if (data !== undefined) { | ||||||
|  |       if ((data as ClientActivity).activity !== undefined) { | ||||||
|  |         Object.assign(this, data) | ||||||
|  |       } else if ((data as ClientActivityPayload).activities !== undefined) { | ||||||
|  |          | ||||||
|  |       } else if ((data as ActivityGame).name !== undefined) { | ||||||
|  |         if (this.activity === undefined) { | ||||||
|  |           this.activity = data as ActivityGame | ||||||
|  |         } else if (this.activity instanceof Array) { | ||||||
|  |           this.activity.push(data as ActivityGame) | ||||||
|  |         } else this.activity = [ this.activity, data as ActivityGame ] | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   parse(payload: ClientActivityPayload): ClientPresence { | ||||||
|  |     this.afk = payload.afk | ||||||
|  |     this.activity = payload.activities ?? undefined | ||||||
|  |     this.since = payload.since | ||||||
|  |     this.status = payload.status | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static parse(payload: ClientActivityPayload): ClientPresence { | ||||||
|  |     return new ClientPresence().parse(payload) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   create(): ClientActivityPayload { | ||||||
|  |     return { | ||||||
|  |       afk: this.afk === undefined ? false : this.afk, | ||||||
|  |       activities: this.createActivity(), | ||||||
|  |       since: this.since === undefined ? null : this.since, | ||||||
|  |       status: this.status === undefined ? 'online' : this.status | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   createActivity(): ActivityGame[] | null { | ||||||
|  |     // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
 | ||||||
|  |     const activity = this.activity === undefined ? null : (this.activity instanceof Array ? this.activity : [this.activity]) || null | ||||||
|  |     if (activity === null) return activity | ||||||
|  |     else { | ||||||
|  |       activity.map(e => { | ||||||
|  |         if (typeof e.type === "string") e.type = ActivityTypes[e.type] | ||||||
|  |         return e | ||||||
|  |       }) | ||||||
|  |       return activity | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setStatus(status: StatusType): ClientPresence { | ||||||
|  |     this.status = status | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setActivity(activity: ActivityGame): ClientPresence { | ||||||
|  |     this.activity = activity | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setActivities(activities: ActivityGame[]): ClientPresence { | ||||||
|  |     this.activity = activities | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setAFK(afk: boolean): ClientPresence { | ||||||
|  |     this.afk = afk | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   removeAFK(): ClientPresence { | ||||||
|  |     this.afk = false | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   toggleAFK(): ClientPresence { | ||||||
|  |     this.afk = this.afk === undefined ? true : !this.afk | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setSince(since?: number): ClientPresence { | ||||||
|  |     this.since = since | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | @ -27,35 +27,18 @@ export class TextChannel extends Channel { | ||||||
|     if (text !== undefined && option !== undefined) { |     if (text !== undefined && option !== undefined) { | ||||||
|       throw new Error('Either text or option is necessary.') |       throw new Error('Either text or option is necessary.') | ||||||
|     } |     } | ||||||
|     if (this.client.user === undefined) { |     const resp = await this.client.rest.post(CHANNEL_MESSAGES(this.id), { | ||||||
|       throw new Error('Client user has not initialized.') |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     const resp = await fetch(CHANNEL_MESSAGES(this.id), { |  | ||||||
|       headers: { |  | ||||||
|         Authorization: `Bot ${this.client.token}`, |  | ||||||
|         'Content-Type': 'application/json' |  | ||||||
|       }, |  | ||||||
|       method: 'POST', |  | ||||||
|       body: JSON.stringify({ |  | ||||||
|         content: text, |         content: text, | ||||||
|         embed: option?.embed, |         embed: option?.embed, | ||||||
|         file: option?.file, |         file: option?.file, | ||||||
|         tts: option?.tts, |         tts: option?.tts, | ||||||
|         allowed_mentions: option?.allowedMention |         allowed_mentions: option?.allowedMention | ||||||
|       }) |  | ||||||
|     }) |     }) | ||||||
| 
 | 
 | ||||||
|     return new Message( |     return new Message(this.client, resp as any, this, this.client.user as any, new MessageMentions()) | ||||||
|       this.client, |  | ||||||
|       await resp.json(), |  | ||||||
|       this, |  | ||||||
|       this.client.user, |  | ||||||
|       new MessageMentions() |  | ||||||
|     ) |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async editMessage ( |   async edit ( | ||||||
|     message: Message | string, |     message: Message | string, | ||||||
|     text?: string, |     text?: string, | ||||||
|     option?: MessageOption |     option?: MessageOption | ||||||
|  |  | ||||||
|  | @ -1,15 +1,21 @@ | ||||||
| import { Client } from '../models/client.ts' | import { Client } from '../models/client.ts' | ||||||
| import { GatewayIntents } from '../types/gateway.ts' | import { GatewayIntents } from '../types/gateway.ts' | ||||||
| import { TOKEN } from './config.ts' | import { TOKEN } from './config.ts' | ||||||
| import { Channel } from '../structures/channel.ts' |  | ||||||
| import { GuildTextChannel } from '../structures/guildTextChannel.ts' |  | ||||||
| import { TextChannel } from '../structures/textChannel.ts' |  | ||||||
| import { Guild } from '../structures/guild.ts' |  | ||||||
| import { User } from '../structures/user.ts' |  | ||||||
| import { Message } from "../structures/message.ts" | import { Message } from "../structures/message.ts" | ||||||
| import { RedisCacheAdapter } from "../models/CacheAdapter.ts" | import { RedisCacheAdapter } from "../models/CacheAdapter.ts" | ||||||
|  | import { ClientPresence } from "../structures/presence.ts" | ||||||
|  | import { Member } from "../structures/member.ts" | ||||||
|  | import { Role } from "../structures/role.ts" | ||||||
|  | import { GuildChannel } from "../managers/GuildChannelsManager.ts" | ||||||
| 
 | 
 | ||||||
| const bot = new Client() | const bot = new Client({ | ||||||
|  |   presence: new ClientPresence({ | ||||||
|  |     activity: { | ||||||
|  |       name: "Testing", | ||||||
|  |       type: 'COMPETING' | ||||||
|  |     } | ||||||
|  |   }), | ||||||
|  | }) | ||||||
| 
 | 
 | ||||||
| bot.setAdapter(new RedisCacheAdapter(bot, { | bot.setAdapter(new RedisCacheAdapter(bot, { | ||||||
|   hostname: "127.0.0.1", |   hostname: "127.0.0.1", | ||||||
|  | @ -18,60 +24,44 @@ bot.setAdapter(new RedisCacheAdapter(bot, { | ||||||
| 
 | 
 | ||||||
| bot.on('ready', () => { | bot.on('ready', () => { | ||||||
|   console.log(`[Login] Logged in as ${bot.user?.tag}!`) |   console.log(`[Login] Logged in as ${bot.user?.tag}!`) | ||||||
|  |   bot.setPresence({ | ||||||
|  |     name: "Test After Ready", | ||||||
|  |     type: 'COMPETING' | ||||||
|  |   }) | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| bot.on('debug', console.log) | bot.on('debug', console.log) | ||||||
| 
 | 
 | ||||||
| bot.on('channelDelete', (channel: Channel) => { | bot.on('messageCreate', async (msg: Message) => { | ||||||
|   console.log('channelDelete', channel.id) |   if (msg.author.bot === true) return | ||||||
| }) |   if (msg.content === "!ping") { | ||||||
| 
 |     msg.reply(`Pong! Ping: ${bot.ping}ms`) | ||||||
| bot.on('channelUpdate', (before: Channel, after: Channel) => { |   } else if (msg.content === "!members") { | ||||||
|   if (before instanceof GuildTextChannel && after instanceof GuildTextChannel) { |     const col = await msg.guild?.members.collection() | ||||||
|     console.log('channelUpdate', before.name) |     const data = col?.array().map((c: Member, i: number) => { | ||||||
|     console.log('channelUpdate', after.name) |       return `${i + 1}. ${c.user.tag}` | ||||||
|   } else { |     }).join("\n") as string | ||||||
|     console.log('channelUpdate', before.id) |     msg.channel.send("Member List:\n" + data) | ||||||
|     console.log('channelUpdate', after.id) |   } else if (msg.content === "!guilds") { | ||||||
|  |     const guilds = await msg.client.guilds.collection() | ||||||
|  |     msg.channel.send("Guild List:\n" + (guilds.array().map((c, 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) | ||||||
|  |   } 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 | ||||||
|  |     msg.channel.send("Channels List:\n" + data) | ||||||
|   } |   } | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| bot.on('channelCreate', (channel: Channel) => { |  | ||||||
|   console.log('channelCreate', channel.id) |  | ||||||
| }) |  | ||||||
| 
 |  | ||||||
| bot.on('channelPinsUpdate', (before: TextChannel, after: TextChannel) => { |  | ||||||
|   console.log( |  | ||||||
|     'channelPinsUpdate', |  | ||||||
|     before.lastPinTimestamp, |  | ||||||
|     after.lastPinTimestamp |  | ||||||
|   ) |  | ||||||
| }) |  | ||||||
| 
 |  | ||||||
| bot.on('guildBanAdd', (guild: Guild, user: User) => { |  | ||||||
|   console.log('guildBanAdd', guild.id, user.id) |  | ||||||
| }) |  | ||||||
| 
 |  | ||||||
| bot.on('guildBanRemove', (guild: Guild, user: User) => { |  | ||||||
|   console.log('guildBanRemove', guild.id, user.id) |  | ||||||
| }) |  | ||||||
| 
 |  | ||||||
| bot.on('guildCreate', (guild: Guild) => { |  | ||||||
|   console.log('guildCreate', guild.id) |  | ||||||
| }) |  | ||||||
| 
 |  | ||||||
| bot.on('guildDelete', (guild: Guild) => { |  | ||||||
|   console.log('guildDelete', guild.id) |  | ||||||
| }) |  | ||||||
| 
 |  | ||||||
| bot.on('guildUpdate', (before: Guild, after: Guild) => { |  | ||||||
|   console.log('guildUpdate', before.name, after.name) |  | ||||||
| }) |  | ||||||
| 
 |  | ||||||
| bot.on('messageCreate', (msg: Message) => { |  | ||||||
|   console.log(`${msg.author.tag}: ${msg.content}`) |  | ||||||
| }) |  | ||||||
| 
 |  | ||||||
| bot.connect(TOKEN, [ | bot.connect(TOKEN, [ | ||||||
|   GatewayIntents.GUILD_MEMBERS, |   GatewayIntents.GUILD_MEMBERS, | ||||||
|   GatewayIntents.GUILD_PRESENCES, |   GatewayIntents.GUILD_PRESENCES, | ||||||
|  |  | ||||||
|  | @ -187,6 +187,10 @@ const INVITE = (inviteCODE: string): string => | ||||||
| const VOICE_REGIONS = (guildID: string): string => | const VOICE_REGIONS = (guildID: string): string => | ||||||
|   `${DISCORD_API_URL}/v${DISCORD_API_VERSION}/guilds/${guildID}/regions` |   `${DISCORD_API_URL}/v${DISCORD_API_VERSION}/guilds/${guildID}/regions` | ||||||
| 
 | 
 | ||||||
|  | // Client User Endpoint
 | ||||||
|  | const CLIENT_USER = (): string => | ||||||
|  |   `${DISCORD_API_URL}/v${DISCORD_API_VERSION}/users/@me` | ||||||
|  | 
 | ||||||
| export default [ | export default [ | ||||||
|   GUILDS, |   GUILDS, | ||||||
|   GUILD, |   GUILD, | ||||||
|  | @ -204,6 +208,7 @@ export default [ | ||||||
|   GUILD_CHANNEL, |   GUILD_CHANNEL, | ||||||
|   GUILD_CHANNELS, |   GUILD_CHANNELS, | ||||||
|   GUILD_MEMBER, |   GUILD_MEMBER, | ||||||
|  |   CLIENT_USER, | ||||||
|   GUILD_MEMBERS, |   GUILD_MEMBERS, | ||||||
|   GUILD_MEMBER_ROLE, |   GUILD_MEMBER_ROLE, | ||||||
|   GUILD_INVITES, |   GUILD_INVITES, | ||||||
|  | @ -319,6 +324,7 @@ export { | ||||||
|   CUSTOM_EMOJI, |   CUSTOM_EMOJI, | ||||||
|   GUILD_ICON, |   GUILD_ICON, | ||||||
|   GUILD_SPLASH, |   GUILD_SPLASH, | ||||||
|  |   CLIENT_USER, | ||||||
|   GUILD_DISCOVERY_SPLASH, |   GUILD_DISCOVERY_SPLASH, | ||||||
|   GUILD_BANNER, |   GUILD_BANNER, | ||||||
|   DEFAULT_USER_AVATAR, |   DEFAULT_USER_AVATAR, | ||||||
|  |  | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| // https://discord.com/developers/docs/topics/opcodes-and-status-codes#gateway
 | // https://discord.com/developers/docs/topics/opcodes-and-status-codes#gateway
 | ||||||
| // https://discord.com/developers/docs/topics/gateway#commands-and-events-gateway-events
 | // https://discord.com/developers/docs/topics/gateway#commands-and-events-gateway-events
 | ||||||
|  | import { StatusType } from "../../mod.ts" | ||||||
| import { EmojiPayload } from './emoji.ts' | import { EmojiPayload } from './emoji.ts' | ||||||
| import { MemberPayload } from './guild.ts' | import { MemberPayload } from './guild.ts' | ||||||
| import { ActivityPayload } from './presence.ts' | import { ActivityPayload } from './presence.ts' | ||||||
|  | @ -9,7 +10,7 @@ import { UserPayload } from './user.ts' | ||||||
| /** | /** | ||||||
|  * Gateway OPcodes from Discord docs. |  * Gateway OPcodes from Discord docs. | ||||||
|  */ |  */ | ||||||
| enum GatewayOpcodes { // 문서를 확인해본 결과 Opcode 5번은 비어있다. - UnderC -
 | export enum GatewayOpcodes { // 문서를 확인해본 결과 Opcode 5번은 비어있다. - UnderC -
 | ||||||
|   DISPATCH = 0, |   DISPATCH = 0, | ||||||
|   HEARTBEAT = 1, |   HEARTBEAT = 1, | ||||||
|   IDENTIFY = 2, |   IDENTIFY = 2, | ||||||
|  | @ -26,7 +27,7 @@ enum GatewayOpcodes { // 문서를 확인해본 결과 Opcode 5번은 비어있 | ||||||
| /** | /** | ||||||
|  * Gateway Close Codes from Discord docs. |  * Gateway Close Codes from Discord docs. | ||||||
|  */ |  */ | ||||||
| enum GatewayCloseCodes { | export enum GatewayCloseCodes { | ||||||
|   UNKNOWN_ERROR = 4000, |   UNKNOWN_ERROR = 4000, | ||||||
|   UNKNOWN_OPCODE = 4001, |   UNKNOWN_OPCODE = 4001, | ||||||
|   DECODE_ERROR = 4002, |   DECODE_ERROR = 4002, | ||||||
|  | @ -43,7 +44,7 @@ enum GatewayCloseCodes { | ||||||
|   DISALLOWED_INTENTS = 4014 |   DISALLOWED_INTENTS = 4014 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| enum GatewayIntents { | export enum GatewayIntents { | ||||||
|   GUILDS = 1 << 0, |   GUILDS = 1 << 0, | ||||||
|   GUILD_MEMBERS = 1 << 1, |   GUILD_MEMBERS = 1 << 1, | ||||||
|   GUILD_BANS = 1 << 2, |   GUILD_BANS = 1 << 2, | ||||||
|  | @ -61,7 +62,7 @@ enum GatewayIntents { | ||||||
|   DIRECT_MESSAGE_TYPING = 1 << 13 |   DIRECT_MESSAGE_TYPING = 1 << 13 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| enum GatewayEvents { | export enum GatewayEvents { | ||||||
|   Ready = 'READY', |   Ready = 'READY', | ||||||
|   Resumed = 'RESUMED', |   Resumed = 'RESUMED', | ||||||
|   Reconnect = 'RECONNECT', |   Reconnect = 'RECONNECT', | ||||||
|  | @ -111,7 +112,7 @@ export interface IdentityPayload { | ||||||
|   intents: number |   intents: number | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| enum UpdateStatus { | export enum UpdateStatus { | ||||||
|   online = 'online', |   online = 'online', | ||||||
|   dnd = 'dnd', |   dnd = 'dnd', | ||||||
|   afk = 'idle', |   afk = 'idle', | ||||||
|  | @ -291,7 +292,7 @@ export interface MessageReactionRemoveAllPayload { | ||||||
| export interface PresenceUpdatePayload { | export interface PresenceUpdatePayload { | ||||||
|   user: UserPayload |   user: UserPayload | ||||||
|   guild_id: string |   guild_id: string | ||||||
|   status: string |   status: StatusType | ||||||
|   activities: ActivityPayload[] |   activities: ActivityPayload[] | ||||||
|   client_status: UpdateStatus[] |   client_status: UpdateStatus[] | ||||||
| } | } | ||||||
|  | @ -314,12 +315,3 @@ export interface WebhooksUpdatePayload { | ||||||
|   guild_id: string |   guild_id: string | ||||||
|   channel_id: string |   channel_id: string | ||||||
| } | } | ||||||
| 
 |  | ||||||
| // https://discord.com/developers/docs/topics/gateway#typing-start-typing-start-event-fields
 |  | ||||||
| export { |  | ||||||
|   GatewayCloseCodes, |  | ||||||
|   GatewayOpcodes, |  | ||||||
|   GatewayIntents, |  | ||||||
|   GatewayEvents, |  | ||||||
|   UpdateStatus |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| import { ChannelPayload } from './channel.ts' | import { ChannelPayload } from './channel.ts' | ||||||
| import { EmojiPayload } from './emoji.ts' | import { EmojiPayload } from './emoji.ts' | ||||||
| import { PresenceUpdatePayload } from './presence.ts' | import { PresenceUpdatePayload } from './gateway.ts' | ||||||
| import { RolePayload } from './role.ts' | import { RolePayload } from './role.ts' | ||||||
| import { UserPayload } from './user.ts' | import { UserPayload } from './user.ts' | ||||||
| import { VoiceStatePayload } from './voice.ts' | import { VoiceStatePayload } from './voice.ts' | ||||||
|  | @ -63,23 +63,23 @@ export interface MemberPayload { | ||||||
|   mute: boolean |   mute: boolean | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| enum MessageNotification { | export enum MessageNotification { | ||||||
|   ALL_MESSAGES = 0, |   ALL_MESSAGES = 0, | ||||||
|   ONLY_MENTIONS = 1 |   ONLY_MENTIONS = 1 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| enum ContentFilter { | export enum ContentFilter { | ||||||
|   DISABLED = 0, |   DISABLED = 0, | ||||||
|   MEMBERS_WITHOUT_ROLES = 1, |   MEMBERS_WITHOUT_ROLES = 1, | ||||||
|   ALL_MEMBERS = 3 |   ALL_MEMBERS = 3 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| enum MFA { | export enum MFA { | ||||||
|   NONE = 0, |   NONE = 0, | ||||||
|   ELEVATED = 1 |   ELEVATED = 1 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| enum Verification { | export enum Verification { | ||||||
|   NONE = 0, |   NONE = 0, | ||||||
|   LOW = 1, |   LOW = 1, | ||||||
|   MEDIUM = 2, |   MEDIUM = 2, | ||||||
|  | @ -87,14 +87,14 @@ enum Verification { | ||||||
|   VERY_HIGH = 4 |   VERY_HIGH = 4 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| enum PremiumTier { | export enum PremiumTier { | ||||||
|   NONE = 0, |   NONE = 0, | ||||||
|   TIER_1 = 1, |   TIER_1 = 1, | ||||||
|   TIER_2 = 2, |   TIER_2 = 2, | ||||||
|   TIER_3 = 3 |   TIER_3 = 3 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| enum SystemChannelFlags { | export enum SystemChannelFlags { | ||||||
|   SUPPRESS_JOIN_NOTIFICATIONS = 1 << 0, |   SUPPRESS_JOIN_NOTIFICATIONS = 1 << 0, | ||||||
|   SUPPRESS_PREMIUM_SUBSCRIPTIONS = 1 << 1 |   SUPPRESS_PREMIUM_SUBSCRIPTIONS = 1 << 1 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -50,7 +50,7 @@ export interface ActivitySecrets { | ||||||
|   match?: string |   match?: string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| enum ActivityFlags { | export enum ActivityFlags { | ||||||
|   INSTANCE = 1 << 0, |   INSTANCE = 1 << 0, | ||||||
|   JOIN = 1 << 1, |   JOIN = 1 << 1, | ||||||
|   SPECTATE = 1 << 2, |   SPECTATE = 1 << 2, | ||||||
|  | @ -58,5 +58,3 @@ enum ActivityFlags { | ||||||
|   SYNC = 1 << 4, |   SYNC = 1 << 4, | ||||||
|   PLAY = 1 << 5 |   PLAY = 1 << 5 | ||||||
| } | } | ||||||
| 
 |  | ||||||
| export { ActivityFlags } |  | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| // https://discord.com/developers/docs/topics/opcodes-and-status-codes#voice
 | // https://discord.com/developers/docs/topics/opcodes-and-status-codes#voice
 | ||||||
| import { MemberPayload } from './guild.ts' | import { MemberPayload } from './guild.ts' | ||||||
| 
 | 
 | ||||||
| enum VoiceOpcodes { // VoiceOpcodes 추가 - UnderC -
 | export enum VoiceOpcodes { // VoiceOpcodes 추가 - UnderC -
 | ||||||
|   IDENTIFY = 0, |   IDENTIFY = 0, | ||||||
|   SELECT_PROTOCOL = 1, |   SELECT_PROTOCOL = 1, | ||||||
|   READY = 2, |   READY = 2, | ||||||
|  | @ -15,7 +15,7 @@ enum VoiceOpcodes { // VoiceOpcodes 추가 - UnderC - | ||||||
|   CLIENT_DISCONNECT = 13 |   CLIENT_DISCONNECT = 13 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| enum VoiceCloseCodes { | export enum VoiceCloseCodes { | ||||||
|   UNKNOWN_OPCODE = 4001, |   UNKNOWN_OPCODE = 4001, | ||||||
|   NOT_AUTHENTICATED = 4003, |   NOT_AUTHENTICATED = 4003, | ||||||
|   AUTHENTICATION_FAILED = 4004, |   AUTHENTICATION_FAILED = 4004, | ||||||
|  |  | ||||||
|  | @ -1,15 +1,9 @@ | ||||||
| export class Collection<K = string, V = any> extends Map<K, V> { | export class Collection<K = string, V = any> extends Map<K, V> { | ||||||
|   maxSize?: number; |   set(key: K, value: V): this { | ||||||
| 
 |  | ||||||
|   set(key: K, value: V) { |  | ||||||
|     if (this.maxSize || this.maxSize === 0) { |  | ||||||
|       if (this.size >= this.maxSize) return this |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return super.set(key, value) |     return super.set(key, value) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   array() { |   array(): V[] { | ||||||
|     return [...this.values()] |     return [...this.values()] | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -21,53 +15,49 @@ export class Collection<K = string, V = any> extends Map<K, V> { | ||||||
|     return [...this.values()][this.size - 1] |     return [...this.values()][this.size - 1] | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   random() { |   random(): V { | ||||||
|     const arr = [...this.values()] |     const arr = [...this.values()] | ||||||
|     return arr[Math.floor(Math.random() * arr.length)] |     return arr[Math.floor(Math.random() * arr.length)] | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   find(callback: (value: V, key: K) => boolean) { |   find(callback: (value: V, key: K) => boolean): V | undefined { | ||||||
|     for (const key of this.keys()) { |     for (const key of this.keys()) { | ||||||
|       const value = this.get(key)! |       const value = this.get(key) as V | ||||||
|  |       // eslint-disable-next-line standard/no-callback-literal
 | ||||||
|       if (callback(value, key)) return value |       if (callback(value, key)) return value | ||||||
|     } |     } | ||||||
|     // If nothing matched
 |  | ||||||
|      |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   filter(callback: (value: V, key: K) => boolean) { |   filter(callback: (value: V, key: K) => boolean): Collection<K, V> { | ||||||
|     const relevant = new Collection<K, V>() |     const relevant = new Collection<K, V>() | ||||||
|     this.forEach((value, key) => { |     this.forEach((value, key) => { | ||||||
|       if (callback(value, key)) relevant.set(key, value) |       if (callback(value, key)) relevant.set(key, value) | ||||||
|     }); |     }) | ||||||
| 
 |     return relevant | ||||||
|     return relevant; |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   map<T>(callback: (value: V, key: K) => T) { |   map<T>(callback: (value: V, key: K) => T): T[] { | ||||||
|     const results = [] |     const results = [] | ||||||
|     for (const key of this.keys()) { |     for (const key of this.keys()) { | ||||||
|       const value = this.get(key)! |       const value = this.get(key) as V | ||||||
|       results.push(callback(value, key)) |       results.push(callback(value, key)) | ||||||
|     } |     } | ||||||
|     return results |     return results | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   some(callback: (value: V, key: K) => boolean) { |   some(callback: (value: V, key: K) => boolean): boolean { | ||||||
|     for (const key of this.keys()) { |     for (const key of this.keys()) { | ||||||
|       const value = this.get(key)! |       const value = this.get(key) as V | ||||||
|       if (callback(value, key)) return true |       if (callback(value, key)) return true | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     return false |     return false | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   every(callback: (value: V, key: K) => boolean) { |   every(callback: (value: V, key: K) => boolean): boolean { | ||||||
|     for (const key of this.keys()) { |     for (const key of this.keys()) { | ||||||
|       const value = this.get(key)! |       const value = this.get(key) as V | ||||||
|       if (!callback(value, key)) return false |       if (!callback(value, key)) return false | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     return true |     return true | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -75,21 +65,21 @@ export class Collection<K = string, V = any> extends Map<K, V> { | ||||||
|     callback: (accumulator: T, value: V, key: K) => T, |     callback: (accumulator: T, value: V, key: K) => T, | ||||||
|     initialValue?: T, |     initialValue?: T, | ||||||
|   ): T { |   ): T { | ||||||
|     let accumulator: T = initialValue! |     let accumulator: T = initialValue as T | ||||||
| 
 | 
 | ||||||
|     for (const key of this.keys()) { |     for (const key of this.keys()) { | ||||||
|       const value = this.get(key)! |       const value = this.get(key) as V | ||||||
|       accumulator = callback(accumulator, value, key) |       accumulator = callback(accumulator, value, key) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return accumulator |     return accumulator | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   static fromObject<V>(object: { [key: string]: V }) { |   static fromObject<V>(object: { [key: string]: V }): Collection<string, V> { | ||||||
|     return new Collection<string, V>(Object.entries(object)) |     return new Collection<string, V>(Object.entries(object)) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   toObject() { |   toObject(): { [name: string]: V } { | ||||||
|     return Object.entries(this) |     return Object.fromEntries(this) | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | @ -1,3 +1,3 @@ | ||||||
| export const delay = (ms: number) => new Promise((resolve, reject) => { | export const delay = async (ms: number): Promise<true> => await new Promise((resolve, reject) => { | ||||||
|     setTimeout(() => resolve(true), ms); |     setTimeout(() => resolve(true), ms); | ||||||
| }); | }); | ||||||
|  | @ -14,7 +14,9 @@ import { GroupDMChannel } from '../structures/groupChannel.ts' | ||||||
| import { CategoryChannel } from '../structures/guildCategoryChannel.ts' | import { CategoryChannel } from '../structures/guildCategoryChannel.ts' | ||||||
| import { NewsChannel } from '../structures/guildNewsChannel.ts' | import { NewsChannel } from '../structures/guildNewsChannel.ts' | ||||||
| import { VoiceChannel } from '../structures/guildVoiceChannel.ts' | import { VoiceChannel } from '../structures/guildVoiceChannel.ts' | ||||||
| import { TextChannel } from '../structures/textChannel.ts' | import { Guild } from "../structures/guild.ts" | ||||||
|  | import { GuildTextChannel } from "../structures/guildTextChannel.ts" | ||||||
|  | import { TextChannel } from "../structures/textChannel.ts" | ||||||
| 
 | 
 | ||||||
| const getChannelByType = ( | const getChannelByType = ( | ||||||
|   client: Client, |   client: Client, | ||||||
|  | @ -25,7 +27,8 @@ const getChannelByType = ( | ||||||
|     | GuildVoiceChannelPayload |     | GuildVoiceChannelPayload | ||||||
|     | DMChannelPayload |     | DMChannelPayload | ||||||
|     | GroupDMChannelPayload |     | GroupDMChannelPayload | ||||||
|     | ChannelPayload |     | ChannelPayload, | ||||||
|  |   guild?: Guild | ||||||
| ): | ): | ||||||
|   | CategoryChannel |   | CategoryChannel | ||||||
|   | NewsChannel |   | NewsChannel | ||||||
|  | @ -36,13 +39,17 @@ const getChannelByType = ( | ||||||
|   | undefined => { |   | undefined => { | ||||||
|   switch (data.type) { |   switch (data.type) { | ||||||
|     case ChannelTypes.GUILD_CATEGORY: |     case ChannelTypes.GUILD_CATEGORY: | ||||||
|       return new CategoryChannel(client, data as GuildChannelCategoryPayload) |       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: |     case ChannelTypes.GUILD_NEWS: | ||||||
|       return new NewsChannel(client, data as GuildNewsChannelPayload) |       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: |     case ChannelTypes.GUILD_TEXT: | ||||||
|       return new TextChannel(client, data as GuildTextChannelPayload) |       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: |     case ChannelTypes.GUILD_VOICE: | ||||||
|       return new VoiceChannel(client, data as GuildVoiceChannelPayload) |       if (guild === undefined) throw new Error("No Guild was provided to construct Channel") | ||||||
|  |       return new VoiceChannel(client, data as GuildVoiceChannelPayload, guild) | ||||||
|     case ChannelTypes.DM: |     case ChannelTypes.DM: | ||||||
|       return new DMChannel(client, data as DMChannelPayload) |       return new DMChannel(client, data as DMChannelPayload) | ||||||
|     case ChannelTypes.GROUP_DM: |     case ChannelTypes.GROUP_DM: | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue