for real
This commit is contained in:
		
						commit
						ab365f9878
					
				
					 27 changed files with 901 additions and 489 deletions
				
			
		
							
								
								
									
										1
									
								
								deps.ts
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								deps.ts
									
										
									
									
									
								
							|  | @ -9,3 +9,4 @@ export type { | ||||||
| } from 'https://deno.land/x/redis@v0.14.1/mod.ts' | } from 'https://deno.land/x/redis@v0.14.1/mod.ts' | ||||||
| export { walk } from 'https://deno.land/std@0.86.0/fs/walk.ts' | export { walk } from 'https://deno.land/std@0.86.0/fs/walk.ts' | ||||||
| export { join } from 'https://deno.land/std@0.86.0/path/mod.ts' | export { join } from 'https://deno.land/std@0.86.0/path/mod.ts' | ||||||
|  | export { Mixin } from 'https://esm.sh/ts-mixer@5.4.0' | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								egg.json
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								egg.json
									
										
									
									
									
								
							|  | @ -4,7 +4,7 @@ | ||||||
|   "entry": "./mod.ts", |   "entry": "./mod.ts", | ||||||
|   "description": "An easy to use Discord API Library for Deno.", |   "description": "An easy to use Discord API Library for Deno.", | ||||||
|   "homepage": "https://github.com/harmonyland/harmony", |   "homepage": "https://github.com/harmonyland/harmony", | ||||||
|   "version": "v1.1.3", |   "version": "v1.1.4", | ||||||
|   "files": [ |   "files": [ | ||||||
|     "./src/**/*", |     "./src/**/*", | ||||||
|     "./deps.ts", |     "./deps.ts", | ||||||
|  |  | ||||||
							
								
								
									
										13
									
								
								mod.ts
									
										
									
									
									
								
							
							
						
						
									
										13
									
								
								mod.ts
									
										
									
									
									
								
							|  | @ -71,7 +71,12 @@ export { | ||||||
| } from './src/structures/presence.ts' | } from './src/structures/presence.ts' | ||||||
| export { Role } from './src/structures/role.ts' | export { Role } from './src/structures/role.ts' | ||||||
| export { Snowflake } from './src/utils/snowflake.ts' | export { Snowflake } from './src/utils/snowflake.ts' | ||||||
| export { TextChannel, GuildTextChannel } from './src/structures/textChannel.ts' | export { TextChannel } from './src/structures/textChannel.ts' | ||||||
|  | export { | ||||||
|  |   GuildTextBasedChannel, | ||||||
|  |   GuildTextChannel, | ||||||
|  |   checkGuildTextBasedChannel | ||||||
|  | } from './src/structures/guildTextChannel.ts' | ||||||
| export type { AllMessageOptions } from './src/structures/textChannel.ts' | export type { AllMessageOptions } from './src/structures/textChannel.ts' | ||||||
| export { MessageReaction } from './src/structures/messageReaction.ts' | export { MessageReaction } from './src/structures/messageReaction.ts' | ||||||
| export { User } from './src/structures/user.ts' | export { User } from './src/structures/user.ts' | ||||||
|  | @ -103,7 +108,10 @@ export type { | ||||||
|   GuildTextChannelPayload, |   GuildTextChannelPayload, | ||||||
|   GuildVoiceChannelPayload, |   GuildVoiceChannelPayload, | ||||||
|   GroupDMChannelPayload, |   GroupDMChannelPayload, | ||||||
|   MessageOptions |   MessageOptions, | ||||||
|  |   OverwriteAsArg, | ||||||
|  |   Overwrite, | ||||||
|  |   OverwriteAsOptions | ||||||
| } from './src/types/channel.ts' | } from './src/types/channel.ts' | ||||||
| export type { EmojiPayload } from './src/types/emoji.ts' | export type { EmojiPayload } from './src/types/emoji.ts' | ||||||
| export { Verification } from './src/types/guild.ts' | export { Verification } from './src/types/guild.ts' | ||||||
|  | @ -113,6 +121,7 @@ export type { | ||||||
|   GuildBanPayload, |   GuildBanPayload, | ||||||
|   GuildFeatures, |   GuildFeatures, | ||||||
|   GuildChannels, |   GuildChannels, | ||||||
|  |   GuildTextBasedChannels, | ||||||
|   GuildCreateOptions, |   GuildCreateOptions, | ||||||
|   GuildCreateChannelOptions, |   GuildCreateChannelOptions, | ||||||
|   GuildCreateRolePayload |   GuildCreateRolePayload | ||||||
|  |  | ||||||
|  | @ -31,7 +31,8 @@ import { webhooksUpdate } from './webhooksUpdate.ts' | ||||||
| import { messageDeleteBulk } from './messageDeleteBulk.ts' | import { messageDeleteBulk } from './messageDeleteBulk.ts' | ||||||
| import { userUpdate } from './userUpdate.ts' | import { userUpdate } from './userUpdate.ts' | ||||||
| import { typingStart } from './typingStart.ts' | import { typingStart } from './typingStart.ts' | ||||||
| import { GuildTextChannel, TextChannel } from '../../structures/textChannel.ts' | import { TextChannel } from '../../structures/textChannel.ts' | ||||||
|  | import { GuildTextBasedChannel } from '../../structures/guildTextChannel.ts' | ||||||
| import { Guild } from '../../structures/guild.ts' | import { Guild } from '../../structures/guild.ts' | ||||||
| import { User } from '../../structures/user.ts' | import { User } from '../../structures/user.ts' | ||||||
| import { Emoji } from '../../structures/emoji.ts' | import { Emoji } from '../../structures/emoji.ts' | ||||||
|  | @ -263,7 +264,7 @@ export type ClientEvents = { | ||||||
|    * @param uncached Set of Messages deleted's IDs which were not cached |    * @param uncached Set of Messages deleted's IDs which were not cached | ||||||
|    */ |    */ | ||||||
|   messageDeleteBulk: [ |   messageDeleteBulk: [ | ||||||
|     channel: GuildTextChannel, |     channel: GuildTextBasedChannel, | ||||||
|     messages: Collection<string, Message>, |     messages: Collection<string, Message>, | ||||||
|     uncached: Set<string> |     uncached: Set<string> | ||||||
|   ] |   ] | ||||||
|  | @ -356,7 +357,7 @@ export type ClientEvents = { | ||||||
|    * @param guild Guild in which Webhooks were updated |    * @param guild Guild in which Webhooks were updated | ||||||
|    * @param channel Channel of which Webhooks were updated |    * @param channel Channel of which Webhooks were updated | ||||||
|    */ |    */ | ||||||
|   webhooksUpdate: [guild: Guild, channel: GuildTextChannel] |   webhooksUpdate: [guild: Guild, channel: GuildTextBasedChannel] | ||||||
|   /** |   /** | ||||||
|    * An Interaction was created |    * An Interaction was created | ||||||
|    * @param interaction Created interaction object |    * @param interaction Created interaction object | ||||||
|  |  | ||||||
|  | @ -1,17 +1,17 @@ | ||||||
| import { Guild } from '../../structures/guild.ts' | import { Guild } from '../../structures/guild.ts' | ||||||
| import { Member } from '../../structures/member.ts' | import { Member } from '../../structures/member.ts' | ||||||
| import { Role } from '../../structures/role.ts' |  | ||||||
| import { | import { | ||||||
|   Interaction, |   Interaction, | ||||||
|   InteractionApplicationCommandResolved, |   InteractionApplicationCommandResolved, | ||||||
|   InteractionChannel |   InteractionChannel | ||||||
| } from '../../structures/slash.ts' | } from '../../structures/slash.ts' | ||||||
| import { GuildTextChannel } from '../../structures/textChannel.ts' | import { GuildTextBasedChannel } from '../../structures/guildTextChannel.ts' | ||||||
| import { User } from '../../structures/user.ts' |  | ||||||
| import { InteractionPayload } from '../../types/slash.ts' | import { InteractionPayload } from '../../types/slash.ts' | ||||||
| import { UserPayload } from '../../types/user.ts' | import { UserPayload } from '../../types/user.ts' | ||||||
| import { Permissions } from '../../utils/permissions.ts' | import { Permissions } from '../../utils/permissions.ts' | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
|  | import { User } from '../../structures/user.ts' | ||||||
|  | import { Role } from '../../structures/role.ts' | ||||||
| 
 | 
 | ||||||
| export const interactionCreate: GatewayEventHandler = async ( | export const interactionCreate: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|  | @ -42,8 +42,8 @@ export const interactionCreate: GatewayEventHandler = async ( | ||||||
|   if (user === undefined) return |   if (user === undefined) return | ||||||
| 
 | 
 | ||||||
|   const channel = |   const channel = | ||||||
|     (await gateway.client.channels.get<GuildTextChannel>(d.channel_id)) ?? |     (await gateway.client.channels.get<GuildTextBasedChannel>(d.channel_id)) ?? | ||||||
|     (await gateway.client.channels.fetch<GuildTextChannel>(d.channel_id)) |     (await gateway.client.channels.fetch<GuildTextBasedChannel>(d.channel_id)) | ||||||
| 
 | 
 | ||||||
|   const resolved: InteractionApplicationCommandResolved = { |   const resolved: InteractionApplicationCommandResolved = { | ||||||
|     users: {}, |     users: {}, | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| import { Message } from '../../structures/message.ts' | import { Message } from '../../structures/message.ts' | ||||||
| import { GuildTextChannel } from '../../structures/textChannel.ts' | import { GuildTextBasedChannel } from '../../structures/guildTextChannel.ts' | ||||||
| import { MessageDeleteBulkPayload } from '../../types/gateway.ts' | import { MessageDeleteBulkPayload } from '../../types/gateway.ts' | ||||||
| import { Collection } from '../../utils/collection.ts' | import { Collection } from '../../utils/collection.ts' | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
|  | @ -8,7 +8,7 @@ export const messageDeleteBulk: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|   d: MessageDeleteBulkPayload |   d: MessageDeleteBulkPayload | ||||||
| ) => { | ) => { | ||||||
|   let channel = await gateway.client.channels.get<GuildTextChannel>( |   let channel = await gateway.client.channels.get<GuildTextBasedChannel>( | ||||||
|     d.channel_id |     d.channel_id | ||||||
|   ) |   ) | ||||||
|   // Fetch the channel if not cached
 |   // Fetch the channel if not cached
 | ||||||
|  | @ -16,7 +16,7 @@ export const messageDeleteBulk: GatewayEventHandler = async ( | ||||||
|     // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
 |     // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
 | ||||||
|     channel = (await gateway.client.channels.fetch( |     channel = (await gateway.client.channels.fetch( | ||||||
|       d.channel_id |       d.channel_id | ||||||
|     )) as GuildTextChannel |     )) as GuildTextBasedChannel | ||||||
| 
 | 
 | ||||||
|   const messages = new Collection<string, Message>() |   const messages = new Collection<string, Message>() | ||||||
|   const uncached = new Set<string>() |   const uncached = new Set<string>() | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| import { Gateway, GatewayEventHandler } from '../index.ts' | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
| import { Guild } from '../../structures/guild.ts' | import { Guild } from '../../structures/guild.ts' | ||||||
| import { WebhooksUpdatePayload } from '../../types/gateway.ts' | import { WebhooksUpdatePayload } from '../../types/gateway.ts' | ||||||
| import { GuildTextChannel } from '../../structures/textChannel.ts' | import { GuildTextBasedChannel } from '../../structures/guildTextChannel.ts' | ||||||
| 
 | 
 | ||||||
| export const webhooksUpdate: GatewayEventHandler = async ( | export const webhooksUpdate: GatewayEventHandler = async ( | ||||||
|   gateway: Gateway, |   gateway: Gateway, | ||||||
|  | @ -10,9 +10,9 @@ export const webhooksUpdate: GatewayEventHandler = async ( | ||||||
|   const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) |   const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) | ||||||
|   if (guild === undefined) return |   if (guild === undefined) return | ||||||
| 
 | 
 | ||||||
|   const channel: GuildTextChannel | undefined = (await guild.channels.get( |   const channel: GuildTextBasedChannel | undefined = (await guild.channels.get( | ||||||
|     d.channel_id |     d.channel_id | ||||||
|   )) as GuildTextChannel |   )) as GuildTextBasedChannel | ||||||
|   if (channel === undefined) |   if (channel === undefined) | ||||||
|     gateway.client.emit('webhooksUpdateUncached', guild, d.channel_id) |     gateway.client.emit('webhooksUpdateUncached', guild, d.channel_id) | ||||||
|   else gateway.client.emit('webhooksUpdate', guild, channel) |   else gateway.client.emit('webhooksUpdate', guild, channel) | ||||||
|  |  | ||||||
|  | @ -64,7 +64,21 @@ export class BaseManager<T, T2> { | ||||||
|     const arr = (await this.array()) ?? [] |     const arr = (await this.array()) ?? [] | ||||||
|     const { readable, writable } = new TransformStream() |     const { readable, writable } = new TransformStream() | ||||||
|     arr.forEach((el) => writable.getWriter().write(el)) |     arr.forEach((el) => writable.getWriter().write(el)) | ||||||
|     yield* readable.getIterator() |     yield* readable | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async fetch(...args: unknown[]): Promise<T2 | undefined> { | ||||||
|  |     return undefined | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Try to get value from cache, if not found then fetch */ | ||||||
|  |   async resolve(key: string): Promise<T2 | undefined> { | ||||||
|  |     const cacheValue = await this.get(key) | ||||||
|  |     if (cacheValue !== undefined) return cacheValue | ||||||
|  |     else { | ||||||
|  |       const fetchValue = await this.fetch(key).catch(() => undefined) | ||||||
|  |       if (fetchValue !== undefined) return fetchValue | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** Deletes everything from Cache */ |   /** Deletes everything from Cache */ | ||||||
|  |  | ||||||
|  | @ -44,6 +44,20 @@ export class BaseChildManager<T, T2> { | ||||||
|     const arr = (await this.array()) ?? [] |     const arr = (await this.array()) ?? [] | ||||||
|     const { readable, writable } = new TransformStream() |     const { readable, writable } = new TransformStream() | ||||||
|     arr.forEach((el: unknown) => writable.getWriter().write(el)) |     arr.forEach((el: unknown) => writable.getWriter().write(el)) | ||||||
|     yield* readable.getIterator() |     yield* readable | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async fetch(...args: unknown[]): Promise<T2 | undefined> { | ||||||
|  |     return this.parent.fetch(...args) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Try to get value from cache, if not found then fetch */ | ||||||
|  |   async resolve(key: string): Promise<T2 | undefined> { | ||||||
|  |     const cacheValue = await this.get(key) | ||||||
|  |     if (cacheValue !== undefined) return cacheValue | ||||||
|  |     else { | ||||||
|  |       const fetchValue = await this.fetch(key).catch(() => undefined) | ||||||
|  |       if (fetchValue !== undefined) return fetchValue | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,10 +1,19 @@ | ||||||
| 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 { ChannelPayload, GuildChannelPayload } from '../types/channel.ts' | import { Embed } from '../structures/embed.ts' | ||||||
|  | import { Message } from '../structures/message.ts' | ||||||
|  | import { TextChannel } from '../structures/textChannel.ts' | ||||||
|  | import { | ||||||
|  |   ChannelPayload, | ||||||
|  |   GuildChannelPayload, | ||||||
|  |   MessageOptions | ||||||
|  | } from '../types/channel.ts' | ||||||
| import { CHANNEL } from '../types/endpoint.ts' | import { CHANNEL } from '../types/endpoint.ts' | ||||||
| import getChannelByType from '../utils/getChannelByType.ts' | import getChannelByType from '../utils/getChannelByType.ts' | ||||||
| import { BaseManager } from './base.ts' | import { BaseManager } from './base.ts' | ||||||
| 
 | 
 | ||||||
|  | export type AllMessageOptions = MessageOptions | Embed | ||||||
|  | 
 | ||||||
| export class ChannelsManager extends BaseManager<ChannelPayload, Channel> { | export class ChannelsManager extends BaseManager<ChannelPayload, Channel> { | ||||||
|   constructor(client: Client) { |   constructor(client: Client) { | ||||||
|     super(client, 'channels', Channel) |     super(client, 'channels', Channel) | ||||||
|  | @ -66,4 +75,105 @@ export class ChannelsManager extends BaseManager<ChannelPayload, Channel> { | ||||||
|         .catch((e) => reject(e)) |         .catch((e) => reject(e)) | ||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   async sendMessage( | ||||||
|  |     channel: string | TextChannel, | ||||||
|  |     content?: string | AllMessageOptions, | ||||||
|  |     option?: AllMessageOptions | ||||||
|  |   ): Promise<Message> { | ||||||
|  |     const channelID = typeof channel === 'string' ? channel : channel.id | ||||||
|  | 
 | ||||||
|  |     if (typeof content === 'object') { | ||||||
|  |       option = content | ||||||
|  |       content = undefined | ||||||
|  |     } | ||||||
|  |     if (content === undefined && option === undefined) { | ||||||
|  |       throw new Error('Either text or option is necessary.') | ||||||
|  |     } | ||||||
|  |     if (option instanceof Embed) { | ||||||
|  |       option = { | ||||||
|  |         embed: option | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const payload: any = { | ||||||
|  |       content: content, | ||||||
|  |       embed: option?.embed, | ||||||
|  |       file: option?.file, | ||||||
|  |       files: option?.files, | ||||||
|  |       tts: option?.tts, | ||||||
|  |       allowed_mentions: option?.allowedMentions, | ||||||
|  |       message_reference: | ||||||
|  |         option?.reply === undefined | ||||||
|  |           ? undefined | ||||||
|  |           : typeof option.reply === 'string' | ||||||
|  |           ? { | ||||||
|  |               message_id: option.reply | ||||||
|  |             } | ||||||
|  |           : typeof option.reply === 'object' | ||||||
|  |           ? option.reply instanceof Message | ||||||
|  |             ? { | ||||||
|  |                 message_id: option.reply.id, | ||||||
|  |                 channel_id: option.reply.channel.id, | ||||||
|  |                 guild_id: option.reply.guild?.id | ||||||
|  |               } | ||||||
|  |             : option.reply | ||||||
|  |           : undefined | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const resp = await this.client.rest.api.channels[channelID].messages.post( | ||||||
|  |       payload | ||||||
|  |     ) | ||||||
|  |     const chan = | ||||||
|  |       typeof channel === 'string' | ||||||
|  |         ? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
 | ||||||
|  |           (await this.get<TextChannel>(channel))! | ||||||
|  |         : channel | ||||||
|  |     const res = new Message(this.client, resp, chan, this.client.user as any) | ||||||
|  |     await res.mentions.fromPayload(resp) | ||||||
|  |     return res | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async editMessage( | ||||||
|  |     channel: string | TextChannel, | ||||||
|  |     message: Message | string, | ||||||
|  |     text?: string | MessageOptions, | ||||||
|  |     option?: MessageOptions | ||||||
|  |   ): Promise<Message> { | ||||||
|  |     const channelID = typeof channel === 'string' ? channel : channel.id | ||||||
|  | 
 | ||||||
|  |     if (text === undefined && option === undefined) { | ||||||
|  |       throw new Error('Either text or option is necessary.') | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (this.client.user === undefined) { | ||||||
|  |       throw new Error('Client user has not initialized.') | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (typeof text === 'object') { | ||||||
|  |       if (typeof option === 'object') Object.assign(option, text) | ||||||
|  |       else option = text | ||||||
|  |       text = undefined | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const newMsg = await this.client.rest.api.channels[channelID].messages[ | ||||||
|  |       typeof message === 'string' ? message : message.id | ||||||
|  |     ].patch({ | ||||||
|  |       content: text, | ||||||
|  |       embed: option?.embed !== undefined ? option.embed.toJSON() : undefined, | ||||||
|  |       // Cannot upload new files with Message
 | ||||||
|  |       // file: option?.file,
 | ||||||
|  |       tts: option?.tts, | ||||||
|  |       allowed_mentions: option?.allowedMentions | ||||||
|  |     }) | ||||||
|  | 
 | ||||||
|  |     const chan = | ||||||
|  |       typeof channel === 'string' | ||||||
|  |         ? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
 | ||||||
|  |           (await this.get<TextChannel>(channel))! | ||||||
|  |         : channel | ||||||
|  |     const res = new Message(this.client, newMsg, chan, this.client.user) | ||||||
|  |     await res.mentions.fromPayload(newMsg) | ||||||
|  |     return res | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -5,7 +5,7 @@ import { CategoryChannel } from '../structures/guildCategoryChannel.ts' | ||||||
| import { | import { | ||||||
|   ChannelTypes, |   ChannelTypes, | ||||||
|   GuildChannelPayload, |   GuildChannelPayload, | ||||||
|   Overwrite |   OverwritePayload | ||||||
| } from '../types/channel.ts' | } from '../types/channel.ts' | ||||||
| import { GuildChannels, GuildChannelPayloads } from '../types/guild.ts' | import { GuildChannels, GuildChannelPayloads } from '../types/guild.ts' | ||||||
| import { CHANNEL, GUILD_CHANNELS } from '../types/endpoint.ts' | import { CHANNEL, GUILD_CHANNELS } from '../types/endpoint.ts' | ||||||
|  | @ -20,7 +20,7 @@ export interface CreateChannelOptions { | ||||||
|   userLimit?: number |   userLimit?: number | ||||||
|   rateLimitPerUser?: number |   rateLimitPerUser?: number | ||||||
|   position?: number |   position?: number | ||||||
|   permissionOverwrites?: Overwrite[] |   permissionOverwrites?: OverwritePayload[] | ||||||
|   parent?: CategoryChannel | string |   parent?: CategoryChannel | string | ||||||
|   nsfw?: boolean |   nsfw?: boolean | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -92,6 +92,9 @@ export class Command implements CommandOptions { | ||||||
|   dmOnly?: boolean |   dmOnly?: boolean | ||||||
|   ownerOnly?: boolean |   ownerOnly?: boolean | ||||||
| 
 | 
 | ||||||
|  |   /** Method called when the command errors */ | ||||||
|  |   onError(ctx: CommandContext, error: Error): any {} | ||||||
|  | 
 | ||||||
|   /** Method executed before executing actual command. Returns bool value - whether to continue or not (optional) */ |   /** Method executed before executing actual command. Returns bool value - whether to continue or not (optional) */ | ||||||
|   beforeExecute(ctx: CommandContext): boolean | Promise<boolean> { |   beforeExecute(ctx: CommandContext): boolean | Promise<boolean> { | ||||||
|     return true |     return true | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| import { Message } from '../structures/message.ts' | import { Message } from '../structures/message.ts' | ||||||
| import { GuildTextChannel } from '../structures/textChannel.ts' | import { GuildTextBasedChannel } from '../structures/guildTextChannel.ts' | ||||||
| import { Client, ClientOptions } from './client.ts' | import { Client, ClientOptions } from './client.ts' | ||||||
| import { | import { | ||||||
|   CategoriesManager, |   CategoriesManager, | ||||||
|  | @ -275,7 +275,7 @@ export class CommandClient extends Client implements CommandClientOptions { | ||||||
|     if ( |     if ( | ||||||
|       command.nsfw === true && |       command.nsfw === true && | ||||||
|       (msg.guild === undefined || |       (msg.guild === undefined || | ||||||
|         ((msg.channel as unknown) as GuildTextChannel).nsfw !== true) |         ((msg.channel as unknown) as GuildTextBasedChannel).nsfw !== true) | ||||||
|     ) |     ) | ||||||
|       return this.emit('commandNSFW', ctx) |       return this.emit('commandNSFW', ctx) | ||||||
| 
 | 
 | ||||||
|  | @ -286,7 +286,8 @@ export class CommandClient extends Client implements CommandClientOptions { | ||||||
| 
 | 
 | ||||||
|     if ( |     if ( | ||||||
|       (command.botPermissions !== undefined || |       (command.botPermissions !== undefined || | ||||||
|         category?.permissions !== undefined) && |         category?.botPermissions !== undefined || | ||||||
|  |         allPermissions !== undefined) && | ||||||
|       msg.guild !== undefined |       msg.guild !== undefined | ||||||
|     ) { |     ) { | ||||||
|       // TODO: Check Overwrites too
 |       // TODO: Check Overwrites too
 | ||||||
|  | @ -315,7 +316,8 @@ export class CommandClient extends Client implements CommandClientOptions { | ||||||
| 
 | 
 | ||||||
|     if ( |     if ( | ||||||
|       (command.userPermissions !== undefined || |       (command.userPermissions !== undefined || | ||||||
|         category?.userPermissions !== undefined) && |         category?.userPermissions !== undefined || | ||||||
|  |         allPermissions !== undefined) && | ||||||
|       msg.guild !== undefined |       msg.guild !== undefined | ||||||
|     ) { |     ) { | ||||||
|       let permissions = |       let permissions = | ||||||
|  | @ -358,8 +360,11 @@ export class CommandClient extends Client implements CommandClientOptions { | ||||||
|       if (beforeExecute === false) return |       if (beforeExecute === false) return | ||||||
| 
 | 
 | ||||||
|       const result = await command.execute(ctx) |       const result = await command.execute(ctx) | ||||||
|       command.afterExecute(ctx, result) |       await command.afterExecute(ctx, result) | ||||||
|     } catch (e) { |     } catch (e) { | ||||||
|  |       await command | ||||||
|  |         .onError(ctx, e) | ||||||
|  |         .catch((e: Error) => this.emit('commandError', ctx, e)) | ||||||
|       this.emit('commandError', ctx, e) |       this.emit('commandError', ctx, e) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | @ -375,7 +380,7 @@ export function command(options?: CommandOptions) { | ||||||
|     })[name] |     })[name] | ||||||
| 
 | 
 | ||||||
|     if (typeof prop !== 'function') |     if (typeof prop !== 'function') | ||||||
|       throw new Error('@command decorator can only be used on functions') |       throw new Error('@command decorator can only be used on class methods') | ||||||
| 
 | 
 | ||||||
|     const command = new Command() |     const command = new Command() | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,6 +1,22 @@ | ||||||
| import { Client } from '../models/client.ts' | import { Client } from '../models/client.ts' | ||||||
| import { ChannelPayload, ChannelTypes } from '../types/channel.ts' | import { | ||||||
|  |   ChannelPayload, | ||||||
|  |   ChannelTypes, | ||||||
|  |   ModifyChannelOption, | ||||||
|  |   ModifyChannelPayload, | ||||||
|  |   Overwrite, | ||||||
|  |   OverwritePayload, | ||||||
|  |   OverwriteAsArg, | ||||||
|  |   OverrideType | ||||||
|  | } from '../types/channel.ts' | ||||||
|  | import { CHANNEL } from '../types/endpoint.ts' | ||||||
|  | import { GuildChannelPayloads, GuildChannels } from '../types/guild.ts' | ||||||
|  | import getChannelByType from '../utils/getChannelByType.ts' | ||||||
|  | import { Permissions } from '../utils/permissions.ts' | ||||||
| import { SnowflakeBase } from './base.ts' | import { SnowflakeBase } from './base.ts' | ||||||
|  | import { Guild } from './guild.ts' | ||||||
|  | import { Member } from './member.ts' | ||||||
|  | import { Role } from './role.ts' | ||||||
| 
 | 
 | ||||||
| export class Channel extends SnowflakeBase { | export class Channel extends SnowflakeBase { | ||||||
|   type: ChannelTypes |   type: ChannelTypes | ||||||
|  | @ -21,3 +37,313 @@ export class Channel extends SnowflakeBase { | ||||||
|     this.id = data.id ?? this.id |     this.id = data.id ?? this.id | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | export class GuildChannel extends Channel { | ||||||
|  |   guildID: string | ||||||
|  |   name: string | ||||||
|  |   position: number | ||||||
|  |   permissionOverwrites: OverwritePayload[] | ||||||
|  |   guild: Guild | ||||||
|  |   nsfw: boolean | ||||||
|  |   parentID?: string | ||||||
|  | 
 | ||||||
|  |   constructor(client: Client, data: GuildChannelPayloads, guild: Guild) { | ||||||
|  |     super(client, data) | ||||||
|  |     this.guildID = data.guild_id | ||||||
|  |     this.name = data.name | ||||||
|  |     this.guild = guild | ||||||
|  |     this.position = data.position | ||||||
|  |     this.permissionOverwrites = data.permission_overwrites | ||||||
|  |     this.nsfw = data.nsfw | ||||||
|  |     this.parentID = data.parent_id | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   readFromData(data: GuildChannelPayloads): void { | ||||||
|  |     super.readFromData(data) | ||||||
|  |     this.guildID = data.guild_id ?? this.guildID | ||||||
|  |     this.name = data.name ?? this.name | ||||||
|  |     this.position = data.position ?? this.position | ||||||
|  |     this.permissionOverwrites = | ||||||
|  |       data.permission_overwrites ?? this.permissionOverwrites | ||||||
|  |     this.nsfw = data.nsfw ?? this.nsfw | ||||||
|  |     this.parentID = data.parent_id ?? this.parentID | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Get Permission Overties for a specific Member or Role */ | ||||||
|  |   async overwritesFor(target: Member | Role | string): Promise<Overwrite[]> { | ||||||
|  |     const stringToObject = | ||||||
|  |       typeof target === 'string' | ||||||
|  |         ? (await this.guild.members.get(target)) ?? | ||||||
|  |           (await this.guild.roles.get(target)) | ||||||
|  |         : target | ||||||
|  | 
 | ||||||
|  |     if (stringToObject === undefined) { | ||||||
|  |       throw new Error('Member or Role not found') | ||||||
|  |     } else { | ||||||
|  |       target = stringToObject | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const roles = | ||||||
|  |       target instanceof Member ? await target.roles.array() : undefined | ||||||
|  | 
 | ||||||
|  |     const overwrites: Overwrite[] = [] | ||||||
|  | 
 | ||||||
|  |     for (const overwrite of this.permissionOverwrites) { | ||||||
|  |       if ( | ||||||
|  |         overwrite.id === this.guild.id || | ||||||
|  |         roles?.some((e) => e.id === overwrite.id) === true || | ||||||
|  |         overwrite.id === target.id | ||||||
|  |       ) { | ||||||
|  |         const id = | ||||||
|  |           (await this.guild.members.get(overwrite.id)) ?? | ||||||
|  |           (await this.guild.roles.get(overwrite.id)) ?? | ||||||
|  |           overwrite.id | ||||||
|  |         const allow = new Permissions(overwrite.allow) | ||||||
|  |         const deny = new Permissions(overwrite.deny) | ||||||
|  | 
 | ||||||
|  |         overwrites.push({ | ||||||
|  |           id, | ||||||
|  |           type: overwrite.type, | ||||||
|  |           allow, | ||||||
|  |           deny | ||||||
|  |         }) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return overwrites | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Get Permissions for a Member in this Channel */ | ||||||
|  |   async permissionsFor(target: Member | Role | string): Promise<Permissions> { | ||||||
|  |     const id = typeof target === 'string' ? target : target.id | ||||||
|  |     if (id === this.guild.ownerID) return new Permissions(Permissions.ALL) | ||||||
|  | 
 | ||||||
|  |     const stringToObject = | ||||||
|  |       typeof target === 'string' | ||||||
|  |         ? (await this.guild.members.get(target)) ?? | ||||||
|  |           (await this.guild.roles.get(target)) | ||||||
|  |         : target | ||||||
|  | 
 | ||||||
|  |     if (stringToObject === undefined) { | ||||||
|  |       throw new Error('Member or Role not found') | ||||||
|  |     } else { | ||||||
|  |       target = stringToObject | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (target.permissions.has('ADMINISTRATOR') === true) | ||||||
|  |       return new Permissions(Permissions.ALL) | ||||||
|  | 
 | ||||||
|  |     const overwrites = await this.overwritesFor(target) | ||||||
|  |     const everyoneOW = overwrites.find((e) => e.id === this.guild.id) | ||||||
|  |     const roleOWs = overwrites.filter((e) => e.type === 0) | ||||||
|  |     const memberOWs = overwrites.filter((e) => e.type === 1) | ||||||
|  | 
 | ||||||
|  |     return target.permissions | ||||||
|  |       .remove(everyoneOW !== undefined ? Number(everyoneOW.deny) : 0) | ||||||
|  |       .add(everyoneOW !== undefined ? Number(everyoneOW.allow) : 0) | ||||||
|  |       .remove(roleOWs.length === 0 ? 0 : roleOWs.map((e) => Number(e.deny))) | ||||||
|  |       .add(roleOWs.length === 0 ? 0 : roleOWs.map((e) => Number(e.allow))) | ||||||
|  |       .remove(memberOWs.length === 0 ? 0 : memberOWs.map((e) => Number(e.deny))) | ||||||
|  |       .add(memberOWs.length === 0 ? 0 : memberOWs.map((e) => Number(e.allow))) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async edit(options?: ModifyChannelOption): Promise<GuildChannels> { | ||||||
|  |     const body: ModifyChannelPayload = { | ||||||
|  |       name: options?.name, | ||||||
|  |       position: options?.position, | ||||||
|  |       permission_overwrites: options?.permissionOverwrites, | ||||||
|  |       parent_id: options?.parentID, | ||||||
|  |       nsfw: options?.nsfw | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const resp = await this.client.rest.patch(CHANNEL(this.id), body) | ||||||
|  | 
 | ||||||
|  |     return ( | ||||||
|  |       (getChannelByType(this.client, resp, this.guild) as | ||||||
|  |         | GuildChannels | ||||||
|  |         | undefined) ?? new GuildChannel(this.client, resp, this.guild) | ||||||
|  |     ) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Edit name of the channel */ | ||||||
|  |   async setName(name: string): Promise<GuildChannels> { | ||||||
|  |     return await this.edit({ name }) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Edit NSFW property of the channel */ | ||||||
|  |   async setNSFW(nsfw: boolean): Promise<GuildChannels> { | ||||||
|  |     return await this.edit({ nsfw }) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Set Permission Overwrites of the Channel */ | ||||||
|  |   async setOverwrites(overwrites: OverwriteAsArg[]): Promise<GuildChannels> { | ||||||
|  |     const result = overwrites.map( | ||||||
|  |       (overwrite): OverwritePayload => { | ||||||
|  |         const id = | ||||||
|  |           typeof overwrite.id === 'string' ? overwrite.id : overwrite.id.id | ||||||
|  |         const allow = | ||||||
|  |           typeof overwrite.allow === 'string' | ||||||
|  |             ? overwrite.allow | ||||||
|  |             : overwrite.allow?.toJSON() ?? '0' | ||||||
|  |         const deny = | ||||||
|  |           typeof overwrite.deny === 'string' | ||||||
|  |             ? overwrite.deny | ||||||
|  |             : overwrite.deny?.toJSON() ?? '0' | ||||||
|  |         const type = | ||||||
|  |           overwrite.id instanceof Role | ||||||
|  |             ? 0 | ||||||
|  |             : overwrite.id instanceof Member | ||||||
|  |             ? 1 | ||||||
|  |             : overwrite.type | ||||||
|  |         if (type === undefined) { | ||||||
|  |           throw new Error('Overwrite type is undefined.') | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return { | ||||||
|  |           id, | ||||||
|  |           type, | ||||||
|  |           allow, | ||||||
|  |           deny | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     ) | ||||||
|  |     return await this.edit({ permissionOverwrites: result }) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Add a Permission Overwrite */ | ||||||
|  |   async addOverwrite(overwrite: OverwriteAsArg): Promise<GuildChannels> { | ||||||
|  |     const overwrites = this.permissionOverwrites | ||||||
|  |     const id = typeof overwrite.id === 'string' ? overwrite.id : overwrite.id.id | ||||||
|  |     const allow = | ||||||
|  |       typeof overwrite.allow === 'string' | ||||||
|  |         ? overwrite.allow | ||||||
|  |         : overwrite.allow?.toJSON() ?? '0' | ||||||
|  |     const deny = | ||||||
|  |       typeof overwrite.deny === 'string' | ||||||
|  |         ? overwrite.deny | ||||||
|  |         : overwrite.deny?.toJSON() ?? '0' | ||||||
|  |     const type = | ||||||
|  |       overwrite.id instanceof Role | ||||||
|  |         ? 0 | ||||||
|  |         : overwrite.id instanceof Member | ||||||
|  |         ? 1 | ||||||
|  |         : overwrite.type | ||||||
|  |     if (type === undefined) { | ||||||
|  |       throw new Error('Overwrite type is undefined.') | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     overwrites.push({ | ||||||
|  |       id, | ||||||
|  |       type, | ||||||
|  |       allow, | ||||||
|  |       deny | ||||||
|  |     }) | ||||||
|  | 
 | ||||||
|  |     return await this.edit({ permissionOverwrites: overwrites }) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Remove a Permission Overwrite */ | ||||||
|  |   async removeOverwrite( | ||||||
|  |     target: Member | Role | string | ||||||
|  |   ): Promise<GuildChannels> { | ||||||
|  |     target = typeof target === 'string' ? target : target.id | ||||||
|  |     if (this.permissionOverwrites.find((e) => e.id === target) === undefined) | ||||||
|  |       throw new Error('Permission Overwrite not found') | ||||||
|  |     const overwrites = this.permissionOverwrites.filter((e) => e.id !== target) | ||||||
|  |     return await this.edit({ permissionOverwrites: overwrites }) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Edit a Permission Overwrite */ | ||||||
|  |   async editOverwrite( | ||||||
|  |     overwrite: OverwriteAsArg, | ||||||
|  |     { | ||||||
|  |       overriteAllow = OverrideType.ADD, | ||||||
|  |       overriteDeny = OverrideType.ADD | ||||||
|  |     }: { | ||||||
|  |       overriteAllow?: OverrideType | ||||||
|  |       overriteDeny?: OverrideType | ||||||
|  |     } | ||||||
|  |   ): Promise<GuildChannels> { | ||||||
|  |     const id = typeof overwrite.id === 'string' ? overwrite.id : overwrite.id.id | ||||||
|  |     const index = this.permissionOverwrites.findIndex((e) => e.id === id) | ||||||
|  |     if (index < 0) throw new Error('Permission Overwrite not found') | ||||||
|  |     const overwrites = this.permissionOverwrites | ||||||
|  | 
 | ||||||
|  |     let allow: string | ||||||
|  |     let deny: string | ||||||
|  | 
 | ||||||
|  |     if ( | ||||||
|  |       overwrite.allow !== undefined && | ||||||
|  |       overriteAllow !== OverrideType.REPLACE | ||||||
|  |     ) { | ||||||
|  |       switch (overriteAllow) { | ||||||
|  |         case OverrideType.ADD: { | ||||||
|  |           const originalAllow = new Permissions(overwrites[index].allow) | ||||||
|  |           const newAllow = new Permissions(overwrite.allow) | ||||||
|  | 
 | ||||||
|  |           allow = originalAllow.add([newAllow]).toJSON() | ||||||
|  |           break | ||||||
|  |         } | ||||||
|  |         case OverrideType.REMOVE: { | ||||||
|  |           const originalAllow = new Permissions(overwrites[index].allow) | ||||||
|  |           const newAllow = new Permissions(overwrite.allow) | ||||||
|  | 
 | ||||||
|  |           allow = originalAllow.remove([newAllow]).toJSON() | ||||||
|  |           break | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } else { | ||||||
|  |       allow = | ||||||
|  |         typeof overwrite.allow === 'string' | ||||||
|  |           ? overwrite.allow | ||||||
|  |           : overwrite.allow?.toJSON() ?? overwrites[index].allow | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (overwrite.deny !== undefined && overriteDeny !== OverrideType.REPLACE) { | ||||||
|  |       switch (overriteDeny) { | ||||||
|  |         case OverrideType.ADD: { | ||||||
|  |           const originalDeny = new Permissions(overwrites[index].deny) | ||||||
|  |           const newDeny = new Permissions(overwrite.deny) | ||||||
|  | 
 | ||||||
|  |           deny = originalDeny.add([newDeny]).toJSON() | ||||||
|  |           break | ||||||
|  |         } | ||||||
|  |         case OverrideType.REMOVE: { | ||||||
|  |           const originalDeny = new Permissions(overwrites[index].deny) | ||||||
|  |           const newDeny = new Permissions(overwrite.deny) | ||||||
|  | 
 | ||||||
|  |           deny = originalDeny.remove([newDeny]).toJSON() | ||||||
|  |           break | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } else { | ||||||
|  |       deny = | ||||||
|  |         typeof overwrite.deny === 'string' | ||||||
|  |           ? overwrite.deny | ||||||
|  |           : overwrite.deny?.toJSON() ?? overwrites[index].deny | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const type = | ||||||
|  |       overwrite.id instanceof Role | ||||||
|  |         ? 0 | ||||||
|  |         : overwrite.id instanceof Member | ||||||
|  |         ? 1 | ||||||
|  |         : overwrite.type | ||||||
|  |     if (type === undefined) { | ||||||
|  |       throw new Error('Overwrite type is undefined.') | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     overwrites[index] = { | ||||||
|  |       id, | ||||||
|  |       type, | ||||||
|  |       allow, | ||||||
|  |       deny | ||||||
|  |     } | ||||||
|  |     return await this.edit({ permissionOverwrites: overwrites }) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Edit position of the channel */ | ||||||
|  |   async setPosition(position: number): Promise<GuildChannels> { | ||||||
|  |     return await this.edit({ position }) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -29,6 +29,15 @@ export class Embed { | ||||||
|   fields?: EmbedField[] |   fields?: EmbedField[] | ||||||
|   files: MessageAttachment[] = [] |   files: MessageAttachment[] = [] | ||||||
| 
 | 
 | ||||||
|  |   static MAX_TITLE_LENGTH = 256 | ||||||
|  |   static MAX_DESCRIPTION_LENGTH = 2048 | ||||||
|  |   static MAX_FIELD_NAME_LENGTH = 256 | ||||||
|  |   static MAX_FIELD_VALUE_LENGTH = 1024 | ||||||
|  |   static MAX_FIELDS_LENGTH = 25 | ||||||
|  |   static MAX_FOOTER_TEXT_LENGTH = 2048 | ||||||
|  |   static MAX_AUTHOR_NAME_LENGTH = 256 | ||||||
|  |   static MAX_EMBED_LENGTH = 6000 | ||||||
|  | 
 | ||||||
|   constructor(data?: EmbedPayload) { |   constructor(data?: EmbedPayload) { | ||||||
|     this.title = data?.title |     this.title = data?.title | ||||||
|     this.type = data?.type |     this.type = data?.type | ||||||
|  | @ -47,6 +56,44 @@ export class Embed { | ||||||
| 
 | 
 | ||||||
|   /** Convert Embed Object to Embed Payload JSON */ |   /** Convert Embed Object to Embed Payload JSON */ | ||||||
|   toJSON(): EmbedPayload { |   toJSON(): EmbedPayload { | ||||||
|  |     let total = 0; | ||||||
|  |     if (this.title?.length !== undefined && this.title?.length > Embed.MAX_TITLE_LENGTH) { | ||||||
|  |       total += Number(this.title.length) | ||||||
|  |       throw new Error(`Embed title cannot exceed ${Embed.MAX_TITLE_LENGTH} characters.`) | ||||||
|  |     } | ||||||
|  |   | ||||||
|  |     if (this.description?.length !== undefined && this.description?.length > Embed.MAX_DESCRIPTION_LENGTH) { | ||||||
|  |       total += Number(this.description.length) | ||||||
|  |       throw new Error(`Embed description cannot exceed ${Embed.MAX_DESCRIPTION_LENGTH} characters.`) | ||||||
|  |     } | ||||||
|  |   | ||||||
|  |     if (this.fields?.length !== undefined) { | ||||||
|  |       this.fields.forEach((field) => { | ||||||
|  |         if (field.name.length > Embed.MAX_FIELD_NAME_LENGTH) { | ||||||
|  |           total += Number(field.name.length) | ||||||
|  |           throw new Error(`Embed field name cannot exceed ${Embed.MAX_FIELD_NAME_LENGTH} characters.`) | ||||||
|  |         } | ||||||
|  |   | ||||||
|  |         if (field.value.length > Embed.MAX_FIELD_VALUE_LENGTH) { | ||||||
|  |           total += Number(field.value.length) | ||||||
|  |           throw new Error(`Embed field value cannot exceed ${Embed.MAX_FIELD_VALUE_LENGTH} characters.`) | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |       if (this.fields.length > Embed.MAX_FIELDS_LENGTH) throw new Error('Embed fields cannot exceed 25 field objects.') | ||||||
|  |     } | ||||||
|  |   | ||||||
|  |     if (this.footer?.text?.length !== undefined && this.footer?.text?.length > Embed.MAX_FOOTER_TEXT_LENGTH) { | ||||||
|  |       total += Number(this.footer?.text?.length) | ||||||
|  |       throw new Error(`Embed footer text cannot exceed ${Embed.MAX_FOOTER_TEXT_LENGTH}.`) | ||||||
|  |     } | ||||||
|  |   | ||||||
|  |     if (this.author?.name?.length !== undefined && this.author?.name?.length > Embed.MAX_AUTHOR_NAME_LENGTH) { | ||||||
|  |       total += Number(this.author?.name?.length) | ||||||
|  |       throw new Error(`Embed author name cannot exceed ${Embed.MAX_AUTHOR_NAME_LENGTH}.`) | ||||||
|  |     } | ||||||
|  |   | ||||||
|  |     if (total > Embed.MAX_EMBED_LENGTH) throw new Error(`Embed characters cannot exceed ${Embed.MAX_EMBED_LENGTH} characters in total.`) | ||||||
|  |      | ||||||
|     return { |     return { | ||||||
|       title: this.title, |       title: this.title, | ||||||
|       type: this.type, |       type: this.type, | ||||||
|  |  | ||||||
|  | @ -1,42 +1,14 @@ | ||||||
| import { Client } from '../models/client.ts' | import { GuildChannel } from './channel.ts' | ||||||
| import { Channel } from './channel.ts' |  | ||||||
| import { | import { | ||||||
|   GuildCategoryChannelPayload, |   GuildCategoryChannelPayload, | ||||||
|   ModifyGuildCategoryChannelOption, |   ModifyGuildCategoryChannelOption, | ||||||
|   ModifyGuildCategoryChannelPayload, |   ModifyGuildCategoryChannelPayload | ||||||
|   Overwrite |  | ||||||
| } from '../types/channel.ts' | } from '../types/channel.ts' | ||||||
| import { Guild } from './guild.ts' |  | ||||||
| import { CHANNEL } from '../types/endpoint.ts' | import { CHANNEL } from '../types/endpoint.ts' | ||||||
| 
 | 
 | ||||||
| export class CategoryChannel extends Channel { | export class CategoryChannel extends GuildChannel { | ||||||
|   guildID: string |  | ||||||
|   name: string |  | ||||||
|   position: number |  | ||||||
|   permissionOverwrites: Overwrite[] |  | ||||||
|   guild: Guild |  | ||||||
|   parentID?: string |  | ||||||
| 
 |  | ||||||
|   constructor(client: Client, data: GuildCategoryChannelPayload, guild: Guild) { |  | ||||||
|     super(client, data) |  | ||||||
|     this.guildID = data.guild_id |  | ||||||
|     this.name = data.name |  | ||||||
|     this.guild = guild |  | ||||||
|     this.position = data.position |  | ||||||
|     this.permissionOverwrites = data.permission_overwrites |  | ||||||
|     this.parentID = data.parent_id |  | ||||||
|     // TODO: Cache in Gateway Event Code
 |  | ||||||
|     // cache.set('guildcategorychannel', this.id, this)
 |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   readFromData(data: GuildCategoryChannelPayload): void { |   readFromData(data: GuildCategoryChannelPayload): void { | ||||||
|     super.readFromData(data) |     super.readFromData(data) | ||||||
|     this.guildID = data.guild_id ?? this.guildID |  | ||||||
|     this.name = data.name ?? this.name |  | ||||||
|     this.position = data.position ?? this.position |  | ||||||
|     this.permissionOverwrites = |  | ||||||
|       data.permission_overwrites ?? this.permissionOverwrites |  | ||||||
|     this.parentID = data.parent_id ?? this.parentID |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async edit( |   async edit( | ||||||
|  |  | ||||||
|  | @ -1,61 +1,3 @@ | ||||||
| import { Client } from '../models/client.ts' | import { GuildTextBasedChannel } from './guildTextChannel.ts' | ||||||
| import { |  | ||||||
|   GuildNewsChannelPayload, |  | ||||||
|   ModifyGuildNewsChannelOption, |  | ||||||
|   ModifyGuildNewsChannelPayload, |  | ||||||
|   Overwrite |  | ||||||
| } from '../types/channel.ts' |  | ||||||
| import { CHANNEL } from '../types/endpoint.ts' |  | ||||||
| import { Guild } from './guild.ts' |  | ||||||
| import { TextChannel } from './textChannel.ts' |  | ||||||
| 
 | 
 | ||||||
| export class NewsChannel extends TextChannel { | export class NewsChannel extends GuildTextBasedChannel {} | ||||||
|   guildID: string |  | ||||||
|   guild: Guild |  | ||||||
|   name: string |  | ||||||
|   position: number |  | ||||||
|   permissionOverwrites: Overwrite[] |  | ||||||
|   nsfw: boolean |  | ||||||
|   parentID?: string |  | ||||||
|   topic?: string |  | ||||||
| 
 |  | ||||||
|   constructor(client: Client, data: GuildNewsChannelPayload, guild: Guild) { |  | ||||||
|     super(client, data) |  | ||||||
|     this.guildID = data.guild_id |  | ||||||
|     this.name = data.name |  | ||||||
|     this.guild = guild |  | ||||||
|     this.position = data.position |  | ||||||
|     this.permissionOverwrites = data.permission_overwrites |  | ||||||
|     this.nsfw = data.nsfw |  | ||||||
|     this.parentID = data.parent_id |  | ||||||
|     this.topic = data.topic |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   readFromData(data: GuildNewsChannelPayload): void { |  | ||||||
|     super.readFromData(data) |  | ||||||
|     this.guildID = data.guild_id ?? this.guildID |  | ||||||
|     this.name = data.name ?? this.name |  | ||||||
|     this.position = data.position ?? this.position |  | ||||||
|     this.permissionOverwrites = |  | ||||||
|       data.permission_overwrites ?? this.permissionOverwrites |  | ||||||
|     this.nsfw = data.nsfw ?? this.nsfw |  | ||||||
|     this.parentID = data.parent_id ?? this.parentID |  | ||||||
|     this.topic = data.topic ?? this.topic |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   async edit(options?: ModifyGuildNewsChannelOption): Promise<NewsChannel> { |  | ||||||
|     const body: ModifyGuildNewsChannelPayload = { |  | ||||||
|       name: options?.name, |  | ||||||
|       position: options?.position, |  | ||||||
|       permission_overwrites: options?.permissionOverwrites, |  | ||||||
|       parent_id: options?.parentID, |  | ||||||
|       type: options?.type, |  | ||||||
|       topic: options?.topic, |  | ||||||
|       nsfw: options?.nsfw |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     const resp = await this.client.rest.patch(CHANNEL(this.id), body) |  | ||||||
| 
 |  | ||||||
|     return new NewsChannel(this.client, resp, this.guild) |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
							
								
								
									
										168
									
								
								src/structures/guildTextChannel.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								src/structures/guildTextChannel.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,168 @@ | ||||||
|  | import { Mixin } from '../../deps.ts' | ||||||
|  | import { TextChannel } from './textChannel.ts' | ||||||
|  | import { GuildChannel } from './channel.ts' | ||||||
|  | import { Client } from '../models/client.ts' | ||||||
|  | import { | ||||||
|  |   ChannelTypes, | ||||||
|  |   GuildTextBasedChannelPayload, | ||||||
|  |   GuildTextChannelPayload, | ||||||
|  |   ModifyGuildTextBasedChannelOption, | ||||||
|  |   ModifyGuildTextBasedChannelPayload, | ||||||
|  |   ModifyGuildTextChannelOption, | ||||||
|  |   ModifyGuildTextChannelPayload | ||||||
|  | } from '../types/channel.ts' | ||||||
|  | import { Guild } from './guild.ts' | ||||||
|  | import { CHANNEL } from '../types/endpoint.ts' | ||||||
|  | import { Message } from './message.ts' | ||||||
|  | import { CreateInviteOptions } from '../managers/invites.ts' | ||||||
|  | import { Invite } from './invite.ts' | ||||||
|  | import { CategoryChannel } from './guildCategoryChannel.ts' | ||||||
|  | 
 | ||||||
|  | const GUILD_TEXT_BASED_CHANNEL_TYPES: ChannelTypes[] = [ | ||||||
|  |   ChannelTypes.GUILD_TEXT, | ||||||
|  |   ChannelTypes.GUILD_NEWS | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | /** Represents a Text Channel but in a Guild */ | ||||||
|  | export class GuildTextBasedChannel extends Mixin(TextChannel, GuildChannel) { | ||||||
|  |   topic?: string | ||||||
|  | 
 | ||||||
|  |   get mention(): string { | ||||||
|  |     return `<#${this.id}>` | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   toString(): string { | ||||||
|  |     return this.mention | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   constructor( | ||||||
|  |     client: Client, | ||||||
|  |     data: GuildTextBasedChannelPayload, | ||||||
|  |     guild: Guild | ||||||
|  |   ) { | ||||||
|  |     super(client, data, guild) | ||||||
|  |     this.topic = data.topic | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   readFromData(data: GuildTextBasedChannelPayload): void { | ||||||
|  |     super.readFromData(data) | ||||||
|  |     this.topic = data.topic ?? this.topic | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Edit the Guild Text Channel */ | ||||||
|  |   async edit( | ||||||
|  |     options?: ModifyGuildTextBasedChannelOption | ||||||
|  |   ): Promise<GuildTextBasedChannel> { | ||||||
|  |     const body: ModifyGuildTextBasedChannelPayload = { | ||||||
|  |       name: options?.name, | ||||||
|  |       position: options?.position, | ||||||
|  |       permission_overwrites: options?.permissionOverwrites, | ||||||
|  |       parent_id: options?.parentID, | ||||||
|  |       nsfw: options?.nsfw, | ||||||
|  |       topic: options?.topic | ||||||
|  |       // rate_limit_per_user: options?.slowmode
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const resp = await this.client.rest.patch(CHANNEL(this.id), body) | ||||||
|  | 
 | ||||||
|  |     return new GuildTextBasedChannel(this.client, resp, this.guild) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * Bulk Delete Messages in a Guild Text Channel | ||||||
|  |    * @param messages Messages to delete. Can be a number, or Array of Message or IDs | ||||||
|  |    */ | ||||||
|  |   async bulkDelete( | ||||||
|  |     messages: Array<Message | string> | number | ||||||
|  |   ): Promise<GuildTextBasedChannel> { | ||||||
|  |     let ids: string[] = [] | ||||||
|  | 
 | ||||||
|  |     if (Array.isArray(messages)) | ||||||
|  |       ids = messages.map((e) => (typeof e === 'string' ? e : e.id)) | ||||||
|  |     else { | ||||||
|  |       let list = await this.messages.array() | ||||||
|  |       if (list.length < messages) list = (await this.fetchMessages()).array() | ||||||
|  |       ids = list | ||||||
|  |         .sort((b, a) => a.createdAt.getTime() - b.createdAt.getTime()) | ||||||
|  |         .filter((e, i) => i < messages) | ||||||
|  |         .filter( | ||||||
|  |           (e) => | ||||||
|  |             new Date().getTime() - e.createdAt.getTime() <= | ||||||
|  |             1000 * 60 * 60 * 24 * 14 | ||||||
|  |         ) | ||||||
|  |         .map((e) => e.id) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ids = [...new Set(ids)] | ||||||
|  |     if (ids.length < 2 || ids.length > 100) | ||||||
|  |       throw new Error('bulkDelete can only delete messages in range 2-100') | ||||||
|  | 
 | ||||||
|  |     await this.client.rest.api.channels[this.id].messages['bulk-delete'].post({ | ||||||
|  |       messages: ids | ||||||
|  |     }) | ||||||
|  | 
 | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Create an Invite for this Channel */ | ||||||
|  |   async createInvite(options?: CreateInviteOptions): Promise<Invite> { | ||||||
|  |     return this.guild.invites.create(this.id, options) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Edit topic of the channel */ | ||||||
|  |   async setTopic(topic: string): Promise<GuildTextBasedChannel> { | ||||||
|  |     return await this.edit({ topic }) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Edit category of the channel */ | ||||||
|  |   async setCategory( | ||||||
|  |     category: CategoryChannel | string | ||||||
|  |   ): Promise<GuildTextBasedChannel> { | ||||||
|  |     return await this.edit({ | ||||||
|  |       parentID: typeof category === 'object' ? category.id : category | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export const checkGuildTextBasedChannel = ( | ||||||
|  |   channel: TextChannel | ||||||
|  | ): channel is GuildTextBasedChannel => | ||||||
|  |   GUILD_TEXT_BASED_CHANNEL_TYPES.includes(channel.type) | ||||||
|  | 
 | ||||||
|  | export class GuildTextChannel extends GuildTextBasedChannel { | ||||||
|  |   slowmode: number | ||||||
|  | 
 | ||||||
|  |   constructor(client: Client, data: GuildTextChannelPayload, guild: Guild) { | ||||||
|  |     super(client, data, guild) | ||||||
|  |     this.slowmode = data.rate_limit_per_user | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   readFromData(data: GuildTextChannelPayload): void { | ||||||
|  |     super.readFromData(data) | ||||||
|  |     this.slowmode = data.rate_limit_per_user ?? this.slowmode | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Edit the Guild Text Channel */ | ||||||
|  |   async edit( | ||||||
|  |     options?: ModifyGuildTextChannelOption | ||||||
|  |   ): Promise<GuildTextChannel> { | ||||||
|  |     const body: ModifyGuildTextChannelPayload = { | ||||||
|  |       name: options?.name, | ||||||
|  |       position: options?.position, | ||||||
|  |       permission_overwrites: options?.permissionOverwrites, | ||||||
|  |       parent_id: options?.parentID, | ||||||
|  |       nsfw: options?.nsfw, | ||||||
|  |       topic: options?.topic, | ||||||
|  |       rate_limit_per_user: options?.slowmode | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const resp = await this.client.rest.patch(CHANNEL(this.id), body) | ||||||
|  | 
 | ||||||
|  |     return new GuildTextChannel(this.client, resp, this.guild) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Edit Slowmode of the channel */ | ||||||
|  |   async setSlowmode(slowmode?: number | null): Promise<GuildTextChannel> { | ||||||
|  |     return await this.edit({ slowmode: slowmode ?? null }) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | @ -4,11 +4,10 @@ import { Client } from '../models/client.ts' | ||||||
| import { | import { | ||||||
|   GuildVoiceChannelPayload, |   GuildVoiceChannelPayload, | ||||||
|   ModifyVoiceChannelOption, |   ModifyVoiceChannelOption, | ||||||
|   ModifyVoiceChannelPayload, |   ModifyVoiceChannelPayload | ||||||
|   Overwrite |  | ||||||
| } from '../types/channel.ts' | } from '../types/channel.ts' | ||||||
| import { CHANNEL } from '../types/endpoint.ts' | import { CHANNEL } from '../types/endpoint.ts' | ||||||
| import { Channel } from './channel.ts' | import { GuildChannel } from './channel.ts' | ||||||
| import { Guild } from './guild.ts' | import { Guild } from './guild.ts' | ||||||
| import { VoiceState } from './voiceState.ts' | import { VoiceState } from './voiceState.ts' | ||||||
| 
 | 
 | ||||||
|  | @ -16,26 +15,14 @@ export interface VoiceServerData extends VoiceServerUpdateData { | ||||||
|   sessionID: string |   sessionID: string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export class VoiceChannel extends Channel { | export class VoiceChannel extends GuildChannel { | ||||||
|   bitrate: string |   bitrate: string | ||||||
|   userLimit: number |   userLimit: number | ||||||
|   guildID: string |  | ||||||
|   name: string |  | ||||||
|   guild: Guild |  | ||||||
|   position: number |  | ||||||
|   permissionOverwrites: Overwrite[] |  | ||||||
|   parentID?: string |  | ||||||
| 
 | 
 | ||||||
|   constructor(client: Client, data: GuildVoiceChannelPayload, guild: Guild) { |   constructor(client: Client, data: GuildVoiceChannelPayload, guild: Guild) { | ||||||
|     super(client, data) |     super(client, data, guild) | ||||||
|     this.bitrate = data.bitrate |     this.bitrate = data.bitrate | ||||||
|     this.userLimit = data.user_limit |     this.userLimit = data.user_limit | ||||||
|     this.guildID = data.guild_id |  | ||||||
|     this.name = data.name |  | ||||||
|     this.position = data.position |  | ||||||
|     this.guild = guild |  | ||||||
|     this.permissionOverwrites = data.permission_overwrites |  | ||||||
|     this.parentID = data.parent_id |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** Join the Voice Channel */ |   /** Join the Voice Channel */ | ||||||
|  | @ -104,12 +91,6 @@ export class VoiceChannel extends Channel { | ||||||
|     super.readFromData(data) |     super.readFromData(data) | ||||||
|     this.bitrate = data.bitrate ?? this.bitrate |     this.bitrate = data.bitrate ?? this.bitrate | ||||||
|     this.userLimit = data.user_limit ?? this.userLimit |     this.userLimit = data.user_limit ?? this.userLimit | ||||||
|     this.guildID = data.guild_id ?? this.guildID |  | ||||||
|     this.name = data.name ?? this.name |  | ||||||
|     this.position = data.position ?? this.position |  | ||||||
|     this.permissionOverwrites = |  | ||||||
|       data.permission_overwrites ?? this.permissionOverwrites |  | ||||||
|     this.parentID = data.parent_id ?? this.parentID |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async edit(options?: ModifyVoiceChannelOption): Promise<VoiceChannel> { |   async edit(options?: ModifyVoiceChannelOption): Promise<VoiceChannel> { | ||||||
|  |  | ||||||
|  | @ -13,7 +13,8 @@ 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 { MessageMentions } from './messageMentions.ts' | import { MessageMentions } from './messageMentions.ts' | ||||||
| import { GuildTextChannel, TextChannel } from './textChannel.ts' | import { TextChannel } from './textChannel.ts' | ||||||
|  | import { GuildTextBasedChannel } from './guildTextChannel.ts' | ||||||
| import { Guild } from './guild.ts' | import { Guild } from './guild.ts' | ||||||
| import { MessageReactionsManager } from '../managers/messageReactions.ts' | import { MessageReactionsManager } from '../managers/messageReactions.ts' | ||||||
| import { MessageSticker } from './messageSticker.ts' | import { MessageSticker } from './messageSticker.ts' | ||||||
|  | @ -126,8 +127,10 @@ export class Message extends SnowflakeBase { | ||||||
|       const newMember = await this.guild?.members.get(this.member?.id) |       const newMember = await this.guild?.members.get(this.member?.id) | ||||||
|       if (newMember !== undefined) this.member = newMember |       if (newMember !== undefined) this.member = newMember | ||||||
|     } |     } | ||||||
|     if (((this.channel as unknown) as GuildTextChannel).guild !== undefined) |     if ( | ||||||
|       this.guild = ((this.channel as unknown) as GuildTextChannel).guild |       ((this.channel as unknown) as GuildTextBasedChannel).guild !== undefined | ||||||
|  |     ) | ||||||
|  |       this.guild = ((this.channel as unknown) as GuildTextBasedChannel).guild | ||||||
|     if (this.guild !== undefined && this.guildID === undefined) |     if (this.guild !== undefined && this.guildID === undefined) | ||||||
|       this.guildID = this.guild.id |       this.guildID = this.guild.id | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| import { Client } from '../models/client.ts' | import { Client } from '../models/client.ts' | ||||||
| import { MessagePayload } from '../types/channel.ts' | import { MessagePayload } from '../types/channel.ts' | ||||||
| import { Collection } from '../utils/collection.ts' | import { Collection } from '../utils/collection.ts' | ||||||
| import { GuildTextChannel } from './textChannel.ts' | import { GuildTextBasedChannel } from './guildTextChannel.ts' | ||||||
| import { Message } from './message.ts' | import { Message } from './message.ts' | ||||||
| import { Role } from './role.ts' | import { Role } from './role.ts' | ||||||
| import { User } from './user.ts' | import { User } from './user.ts' | ||||||
|  | @ -11,7 +11,7 @@ export class MessageMentions { | ||||||
|   message: Message |   message: Message | ||||||
|   users: Collection<string, User> = new Collection() |   users: Collection<string, User> = new Collection() | ||||||
|   roles: Collection<string, Role> = new Collection() |   roles: Collection<string, Role> = new Collection() | ||||||
|   channels: Collection<string, GuildTextChannel> = new Collection() |   channels: Collection<string, GuildTextBasedChannel> = new Collection() | ||||||
|   everyone: boolean = false |   everyone: boolean = false | ||||||
| 
 | 
 | ||||||
|   static EVERYONE_MENTION = /@(everyone|here)/g |   static EVERYONE_MENTION = /@(everyone|here)/g | ||||||
|  | @ -39,7 +39,7 @@ export class MessageMentions { | ||||||
|     } |     } | ||||||
|     if (payload.mention_channels !== undefined) { |     if (payload.mention_channels !== undefined) { | ||||||
|       for (const mentionChannel of payload.mention_channels) { |       for (const mentionChannel of payload.mention_channels) { | ||||||
|         const channel = await this.client.channels.get<GuildTextChannel>( |         const channel = await this.client.channels.get<GuildTextBasedChannel>( | ||||||
|           mentionChannel.id |           mentionChannel.id | ||||||
|         ) |         ) | ||||||
|         if (channel !== undefined) this.channels.set(channel.id, channel) |         if (channel !== undefined) this.channels.set(channel.id, channel) | ||||||
|  | @ -51,7 +51,7 @@ export class MessageMentions { | ||||||
|     if (matchChannels !== null) { |     if (matchChannels !== null) { | ||||||
|       for (const id of matchChannels) { |       for (const id of matchChannels) { | ||||||
|         const parsedID = id.substr(2, id.length - 3) |         const parsedID = id.substr(2, id.length - 3) | ||||||
|         const channel = await this.client.channels.get<GuildTextChannel>( |         const channel = await this.client.channels.get<GuildTextBasedChannel>( | ||||||
|           parsedID |           parsedID | ||||||
|         ) |         ) | ||||||
|         if (channel !== undefined) this.channels.set(channel.id, channel) |         if (channel !== undefined) this.channels.set(channel.id, channel) | ||||||
|  |  | ||||||
|  | @ -23,10 +23,11 @@ import { SnowflakeBase } from './base.ts' | ||||||
| import { Channel } from './channel.ts' | import { Channel } from './channel.ts' | ||||||
| import { Embed } from './embed.ts' | import { Embed } from './embed.ts' | ||||||
| import { Guild } from './guild.ts' | import { Guild } from './guild.ts' | ||||||
|  | import { GuildTextChannel } from './guildTextChannel.ts' | ||||||
| import { Member } from './member.ts' | import { Member } from './member.ts' | ||||||
| import { Message } from './message.ts' | import { Message } from './message.ts' | ||||||
| import { Role } from './role.ts' | import { Role } from './role.ts' | ||||||
| import { GuildTextChannel, TextChannel } from './textChannel.ts' | import { TextChannel } from './textChannel.ts' | ||||||
| import { User } from './user.ts' | import { User } from './user.ts' | ||||||
| 
 | 
 | ||||||
| interface WebhookMessageOptions extends MessageOptions { | interface WebhookMessageOptions extends MessageOptions { | ||||||
|  |  | ||||||
|  | @ -1,31 +1,18 @@ | ||||||
| import { CreateInviteOptions } from '../managers/invites.ts' |  | ||||||
| import { MessagesManager } from '../managers/messages.ts' | import { MessagesManager } from '../managers/messages.ts' | ||||||
| import { Client } from '../models/client.ts' | import { Client } from '../models/client.ts' | ||||||
| import { | import { | ||||||
|   GuildTextChannelPayload, |  | ||||||
|   MessageOptions, |   MessageOptions, | ||||||
|   MessagePayload, |   MessagePayload, | ||||||
|   MessageReference, |  | ||||||
|   ModifyGuildTextChannelOption, |  | ||||||
|   ModifyGuildTextChannelPayload, |  | ||||||
|   Overwrite, |  | ||||||
|   TextChannelPayload |   TextChannelPayload | ||||||
| } from '../types/channel.ts' | } from '../types/channel.ts' | ||||||
| import { | import { | ||||||
|   CHANNEL, |  | ||||||
|   CHANNEL_MESSAGE, |  | ||||||
|   CHANNEL_MESSAGES, |  | ||||||
|   MESSAGE_REACTION_ME, |   MESSAGE_REACTION_ME, | ||||||
|   MESSAGE_REACTION_USER |   MESSAGE_REACTION_USER | ||||||
| } from '../types/endpoint.ts' | } from '../types/endpoint.ts' | ||||||
| import { Collection } from '../utils/collection.ts' | import { Collection } from '../utils/collection.ts' | ||||||
| import { Permissions } from '../utils/permissions.ts' |  | ||||||
| import { Channel } from './channel.ts' | import { Channel } from './channel.ts' | ||||||
| import { Embed } from './embed.ts' | import { Embed } from './embed.ts' | ||||||
| import { Emoji } from './emoji.ts' | import { Emoji } from './emoji.ts' | ||||||
| import { Guild } from './guild.ts' |  | ||||||
| import { CategoryChannel } from './guildCategoryChannel.ts' |  | ||||||
| import { Invite } from './invite.ts' |  | ||||||
| import { Member } from './member.ts' | import { Member } from './member.ts' | ||||||
| import { Message } from './message.ts' | import { Message } from './message.ts' | ||||||
| import { User } from './user.ts' | import { User } from './user.ts' | ||||||
|  | @ -62,42 +49,11 @@ export class TextChannel extends Channel { | ||||||
|     option?: AllMessageOptions, |     option?: AllMessageOptions, | ||||||
|     reply?: Message |     reply?: Message | ||||||
|   ): Promise<Message> { |   ): Promise<Message> { | ||||||
|     if (typeof content === 'object') { |     return this.client.channels.sendMessage( | ||||||
|       option = content |       this, | ||||||
|       content = undefined |       content, | ||||||
|     } |       Object.assign(option ?? {}, { reply }) | ||||||
|     if (content === undefined && option === undefined) { |     ) | ||||||
|       throw new Error('Either text or option is necessary.') |  | ||||||
|     } |  | ||||||
|     if (option instanceof Embed) { |  | ||||||
|       option = { |  | ||||||
|         embed: option |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     const payload: any = { |  | ||||||
|       content: content, |  | ||||||
|       embed: option?.embed, |  | ||||||
|       file: option?.file, |  | ||||||
|       files: option?.files, |  | ||||||
|       tts: option?.tts, |  | ||||||
|       allowed_mentions: option?.allowedMentions |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (reply !== undefined) { |  | ||||||
|       const reference: MessageReference = { |  | ||||||
|         message_id: reply.id, |  | ||||||
|         channel_id: reply.channel.id, |  | ||||||
|         guild_id: reply.guild?.id |  | ||||||
|       } |  | ||||||
|       payload.message_reference = reference |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     const resp = await this.client.rest.post(CHANNEL_MESSAGES(this.id), payload) |  | ||||||
| 
 |  | ||||||
|     const res = new Message(this.client, resp, this, this.client.user as any) |  | ||||||
|     await res.mentions.fromPayload(resp) |  | ||||||
|     return res |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|  | @ -111,32 +67,7 @@ export class TextChannel extends Channel { | ||||||
|     text?: string, |     text?: string, | ||||||
|     option?: MessageOptions |     option?: MessageOptions | ||||||
|   ): Promise<Message> { |   ): Promise<Message> { | ||||||
|     if (text === undefined && option === undefined) { |     return this.client.channels.editMessage(this, message, text, option) | ||||||
|       throw new Error('Either text or option is necessary.') |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (this.client.user === undefined) { |  | ||||||
|       throw new Error('Client user has not initialized.') |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     const newMsg = await this.client.rest.patch( |  | ||||||
|       CHANNEL_MESSAGE( |  | ||||||
|         this.id, |  | ||||||
|         typeof message === 'string' ? message : message.id |  | ||||||
|       ), |  | ||||||
|       { |  | ||||||
|         content: text, |  | ||||||
|         embed: option?.embed !== undefined ? option.embed.toJSON() : undefined, |  | ||||||
|         // Cannot upload new files with Message
 |  | ||||||
|         // file: option?.file,
 |  | ||||||
|         tts: option?.tts, |  | ||||||
|         allowed_mentions: option?.allowedMentions |  | ||||||
|       } |  | ||||||
|     ) |  | ||||||
| 
 |  | ||||||
|     const res = new Message(this.client, newMsg, this, this.client.user) |  | ||||||
|     await res.mentions.fromPayload(newMsg) |  | ||||||
|     return res |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** Add a reaction to a Message in this Channel */ |   /** Add a reaction to a Message in this Channel */ | ||||||
|  | @ -244,225 +175,3 @@ export class TextChannel extends Channel { | ||||||
|     return this |     return this | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 |  | ||||||
| /** Represents a Text Channel but in a Guild */ |  | ||||||
| export class GuildTextChannel extends TextChannel { |  | ||||||
|   guildID: string |  | ||||||
|   name: string |  | ||||||
|   position: number |  | ||||||
|   permissionOverwrites: Overwrite[] |  | ||||||
|   nsfw: boolean |  | ||||||
|   parentID?: string |  | ||||||
|   slowmode: number |  | ||||||
|   topic?: string |  | ||||||
|   guild: Guild |  | ||||||
| 
 |  | ||||||
|   get mention(): string { |  | ||||||
|     return `<#${this.id}>` |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   toString(): string { |  | ||||||
|     return this.mention |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   constructor(client: Client, data: GuildTextChannelPayload, guild: Guild) { |  | ||||||
|     super(client, data) |  | ||||||
|     this.guildID = data.guild_id |  | ||||||
|     this.name = data.name |  | ||||||
|     this.guild = guild |  | ||||||
|     this.position = data.position |  | ||||||
|     this.permissionOverwrites = data.permission_overwrites |  | ||||||
|     this.nsfw = data.nsfw |  | ||||||
|     this.parentID = data.parent_id |  | ||||||
|     this.topic = data.topic |  | ||||||
|     this.slowmode = data.rate_limit_per_user |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   readFromData(data: GuildTextChannelPayload): void { |  | ||||||
|     super.readFromData(data) |  | ||||||
|     this.guildID = data.guild_id ?? this.guildID |  | ||||||
|     this.name = data.name ?? this.name |  | ||||||
|     this.position = data.position ?? this.position |  | ||||||
|     this.permissionOverwrites = |  | ||||||
|       data.permission_overwrites ?? this.permissionOverwrites |  | ||||||
|     this.nsfw = data.nsfw ?? this.nsfw |  | ||||||
|     this.parentID = data.parent_id ?? this.parentID |  | ||||||
|     this.topic = data.topic ?? this.topic |  | ||||||
|     this.slowmode = data.rate_limit_per_user ?? this.slowmode |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /** Edit the Guild Text Channel */ |  | ||||||
|   async edit( |  | ||||||
|     options?: ModifyGuildTextChannelOption |  | ||||||
|   ): Promise<GuildTextChannel> { |  | ||||||
|     const body: ModifyGuildTextChannelPayload = { |  | ||||||
|       name: options?.name, |  | ||||||
|       position: options?.position, |  | ||||||
|       permission_overwrites: options?.permissionOverwrites, |  | ||||||
|       parent_id: options?.parentID, |  | ||||||
|       nsfw: options?.nsfw, |  | ||||||
|       topic: options?.topic, |  | ||||||
|       rate_limit_per_user: options?.slowmode |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     const resp = await this.client.rest.patch(CHANNEL(this.id), body) |  | ||||||
| 
 |  | ||||||
|     return new GuildTextChannel(this.client, resp, this.guild) |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /** |  | ||||||
|    * Bulk Delete Messages in a Guild Text Channel |  | ||||||
|    * @param messages Messages to delete. Can be a number, or Array of Message or IDs |  | ||||||
|    */ |  | ||||||
|   async bulkDelete( |  | ||||||
|     messages: Array<Message | string> | number |  | ||||||
|   ): Promise<GuildTextChannel> { |  | ||||||
|     let ids: string[] = [] |  | ||||||
| 
 |  | ||||||
|     if (Array.isArray(messages)) |  | ||||||
|       ids = messages.map((e) => (typeof e === 'string' ? e : e.id)) |  | ||||||
|     else { |  | ||||||
|       let list = await this.messages.array() |  | ||||||
|       if (list.length < messages) list = (await this.fetchMessages()).array() |  | ||||||
|       ids = list |  | ||||||
|         .sort((b, a) => a.createdAt.getTime() - b.createdAt.getTime()) |  | ||||||
|         .filter((e, i) => i < messages) |  | ||||||
|         .filter( |  | ||||||
|           (e) => |  | ||||||
|             new Date().getTime() - e.createdAt.getTime() <= |  | ||||||
|             1000 * 60 * 60 * 24 * 14 |  | ||||||
|         ) |  | ||||||
|         .map((e) => e.id) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     ids = [...new Set(ids)] |  | ||||||
|     if (ids.length < 2 || ids.length > 100) |  | ||||||
|       throw new Error('bulkDelete can only delete messages in range 2-100') |  | ||||||
| 
 |  | ||||||
|     await this.client.rest.api.channels[this.id].messages['bulk-delete'].post({ |  | ||||||
|       messages: ids |  | ||||||
|     }) |  | ||||||
| 
 |  | ||||||
|     return this |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /** Create an Invite for this Channel */ |  | ||||||
|   async createInvite(options?: CreateInviteOptions): Promise<Invite> { |  | ||||||
|     return this.guild.invites.create(this.id, options) |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /** Get Permission Overties for a specific Member */ |  | ||||||
|   async overwritesFor(member: Member | string): Promise<Overwrite[]> { |  | ||||||
|     member = (typeof member === 'string' |  | ||||||
|       ? await this.guild.members.get(member) |  | ||||||
|       : member) as Member |  | ||||||
|     if (member === undefined) throw new Error('Member not found') |  | ||||||
|     const roles = await member.roles.array() |  | ||||||
| 
 |  | ||||||
|     const overwrites: Overwrite[] = [] |  | ||||||
| 
 |  | ||||||
|     for (const overwrite of this.permissionOverwrites) { |  | ||||||
|       if (overwrite.id === this.guild.id) { |  | ||||||
|         overwrites.push(overwrite) |  | ||||||
|       } else if (roles.some((e) => e.id === overwrite.id) === true) { |  | ||||||
|         overwrites.push(overwrite) |  | ||||||
|       } else if (overwrite.id === member.id) { |  | ||||||
|         overwrites.push(overwrite) |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return overwrites |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /** Get Permissions for a Member in this Channel */ |  | ||||||
|   async permissionsFor(member: Member | string): Promise<Permissions> { |  | ||||||
|     const id = typeof member === 'string' ? member : member.id |  | ||||||
|     if (id === this.guild.ownerID) return new Permissions(Permissions.ALL) |  | ||||||
| 
 |  | ||||||
|     member = (typeof member === 'string' |  | ||||||
|       ? await this.guild.members.get(member) |  | ||||||
|       : member) as Member |  | ||||||
|     if (member === undefined) throw new Error('Member not found') |  | ||||||
| 
 |  | ||||||
|     if (member.permissions.has('ADMINISTRATOR') === true) |  | ||||||
|       return new Permissions(Permissions.ALL) |  | ||||||
| 
 |  | ||||||
|     const overwrites = await this.overwritesFor(member) |  | ||||||
|     const everyoneOW = overwrites.find((e) => e.id === this.guild.id) |  | ||||||
|     const roleOWs = overwrites.filter((e) => e.type === 0) |  | ||||||
|     const memberOWs = overwrites.filter((e) => e.type === 1) |  | ||||||
| 
 |  | ||||||
|     return member.permissions |  | ||||||
|       .remove(everyoneOW !== undefined ? Number(everyoneOW.deny) : 0) |  | ||||||
|       .add(everyoneOW !== undefined ? Number(everyoneOW.allow) : 0) |  | ||||||
|       .remove(roleOWs.length === 0 ? 0 : roleOWs.map((e) => Number(e.deny))) |  | ||||||
|       .add(roleOWs.length === 0 ? 0 : roleOWs.map((e) => Number(e.allow))) |  | ||||||
|       .remove(memberOWs.length === 0 ? 0 : memberOWs.map((e) => Number(e.deny))) |  | ||||||
|       .add(memberOWs.length === 0 ? 0 : memberOWs.map((e) => Number(e.allow))) |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /** Edit name of the channel */ |  | ||||||
|   async setName(name: string): Promise<GuildTextChannel> { |  | ||||||
|     return await this.edit({ name }) |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /** Edit topic of the channel */ |  | ||||||
|   async setTopic(topic: string): Promise<GuildTextChannel> { |  | ||||||
|     return await this.edit({ topic }) |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /** Edit topic of the channel */ |  | ||||||
|   async setCategory( |  | ||||||
|     category: CategoryChannel | string |  | ||||||
|   ): Promise<GuildTextChannel> { |  | ||||||
|     return await this.edit({ |  | ||||||
|       parentID: typeof category === 'object' ? category.id : category |  | ||||||
|     }) |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /** Edit position of the channel */ |  | ||||||
|   async setPosition(position: number): Promise<GuildTextChannel> { |  | ||||||
|     return await this.edit({ position }) |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /** Edit Slowmode of the channel */ |  | ||||||
|   async setSlowmode(slowmode?: number | null): Promise<GuildTextChannel> { |  | ||||||
|     return await this.edit({ slowmode: slowmode ?? null }) |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /** Edit NSFW property of the channel */ |  | ||||||
|   async setNSFW(nsfw: boolean): Promise<GuildTextChannel> { |  | ||||||
|     return await this.edit({ nsfw }) |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /** Set Permission Overwrites of the Channel */ |  | ||||||
|   async setOverwrites(overwrites: Overwrite[]): Promise<GuildTextChannel> { |  | ||||||
|     return await this.edit({ permissionOverwrites: overwrites }) |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /** Add a Permission Overwrite */ |  | ||||||
|   async addOverwrite(overwrite: Overwrite): Promise<GuildTextChannel> { |  | ||||||
|     const overwrites = this.permissionOverwrites |  | ||||||
|     overwrites.push(overwrite) |  | ||||||
|     return await this.edit({ permissionOverwrites: overwrites }) |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /** Remove a Permission Overwrite */ |  | ||||||
|   async removeOverwrite(id: string): Promise<GuildTextChannel> { |  | ||||||
|     if (this.permissionOverwrites.findIndex((e) => e.id === id) < 0) |  | ||||||
|       throw new Error('Permission Overwrite not found') |  | ||||||
|     const overwrites = this.permissionOverwrites.filter((e) => e.id !== id) |  | ||||||
|     return await this.edit({ permissionOverwrites: overwrites }) |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /** Edit a Permission Overwrite */ |  | ||||||
|   async editOverwrite(overwrite: Overwrite): Promise<GuildTextChannel> { |  | ||||||
|     const index = this.permissionOverwrites.findIndex( |  | ||||||
|       (e) => e.id === overwrite.id |  | ||||||
|     ) |  | ||||||
|     if (index < 0) throw new Error('Permission Overwrite not found') |  | ||||||
|     const overwrites = this.permissionOverwrites |  | ||||||
|     overwrites[index] = overwrite |  | ||||||
|     return await this.edit({ permissionOverwrites: overwrites }) |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -9,11 +9,13 @@ import { | ||||||
|   Guild, |   Guild, | ||||||
|   EveryChannelTypes, |   EveryChannelTypes, | ||||||
|   ChannelTypes, |   ChannelTypes, | ||||||
|   GuildTextChannel |   GuildTextChannel, | ||||||
|  |   checkGuildTextBasedChannel, | ||||||
|  |   Permissions | ||||||
| } from '../../mod.ts' | } from '../../mod.ts' | ||||||
| import { Collector } from '../models/collectors.ts' | import { Collector } from '../models/collectors.ts' | ||||||
| import { MessageAttachment } from '../structures/message.ts' | import { MessageAttachment } from '../structures/message.ts' | ||||||
| import { Permissions } from '../utils/permissions.ts' | import { OverrideType } from '../types/channel.ts' | ||||||
| import { TOKEN } from './config.ts' | import { TOKEN } from './config.ts' | ||||||
| 
 | 
 | ||||||
| const client = new Client({ | const client = new Client({ | ||||||
|  | @ -181,7 +183,8 @@ client.on('messageCreate', async (msg: Message) => { | ||||||
|     if (typeof vs !== 'object') return |     if (typeof vs !== 'object') return | ||||||
|     vs.channel?.join() |     vs.channel?.join() | ||||||
|   } else if (msg.content === '!getOverwrites') { |   } else if (msg.content === '!getOverwrites') { | ||||||
|     if (msg.channel.type !== ChannelTypes.GUILD_TEXT) { |     // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
 | ||||||
|  |     if (!checkGuildTextBasedChannel(msg.channel)) { | ||||||
|       return msg.channel.send("This isn't a guild text channel!") |       return msg.channel.send("This isn't a guild text channel!") | ||||||
|     } |     } | ||||||
|     // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
 |     // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
 | ||||||
|  | @ -193,11 +196,9 @@ client.on('messageCreate', async (msg: Message) => { | ||||||
|       `Your permission overwrites:\n${overwrites |       `Your permission overwrites:\n${overwrites | ||||||
|         .map( |         .map( | ||||||
|           (over) => |           (over) => | ||||||
|             `ID: ${over.id}\nAllowed:\n${new Permissions(over.allow) |             `ID: ${over.id}\nAllowed:\n${over.allow | ||||||
|               .toArray() |               .toArray() | ||||||
|               .join('\n')}\nDenied:\n${new Permissions(over.deny) |               .join('\n')}\nDenied:\n${over.deny.toArray().join('\n')}` | ||||||
|               .toArray() |  | ||||||
|               .join('\n')}` |  | ||||||
|         ) |         ) | ||||||
|         .join('\n\n')}` |         .join('\n\n')}` | ||||||
|     ) |     ) | ||||||
|  | @ -206,11 +207,40 @@ client.on('messageCreate', async (msg: Message) => { | ||||||
|       return msg.channel.send("This isn't a guild text channel!") |       return msg.channel.send("This isn't a guild text channel!") | ||||||
|     } |     } | ||||||
|     // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
 |     // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
 | ||||||
|     const permissions = await (msg.channel as GuildTextChannel).permissionsFor( |     const permissions = await ((msg.channel as unknown) as GuildTextChannel).permissionsFor( | ||||||
|       // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
 |       // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
 | ||||||
|       msg.member as Member |       msg.member as Member | ||||||
|     ) |     ) | ||||||
|     msg.channel.send(`Your permissions:\n${permissions.toArray().join('\n')}`) |     msg.channel.send(`Your permissions:\n${permissions.toArray().join('\n')}`) | ||||||
|  |   } else if (msg.content === '!addBasicOverwrites') { | ||||||
|  |     // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
 | ||||||
|  |     if (!checkGuildTextBasedChannel(msg.channel)) { | ||||||
|  |       return msg.channel.send("This isn't a guild text channel!") | ||||||
|  |     } | ||||||
|  |     if (msg.member !== undefined) { | ||||||
|  |       await msg.channel.addOverwrite({ | ||||||
|  |         id: msg.member, | ||||||
|  |         allow: Permissions.DEFAULT.toString() | ||||||
|  |       }) | ||||||
|  |       msg.channel.send(`Done!`) | ||||||
|  |     } | ||||||
|  |   } else if (msg.content === '!updateBasicOverwrites') { | ||||||
|  |     // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
 | ||||||
|  |     if (!checkGuildTextBasedChannel(msg.channel)) { | ||||||
|  |       return msg.channel.send("This isn't a guild text channel!") | ||||||
|  |     } | ||||||
|  |     if (msg.member !== undefined) { | ||||||
|  |       await msg.channel.editOverwrite( | ||||||
|  |         { | ||||||
|  |           id: msg.member, | ||||||
|  |           allow: Permissions.DEFAULT.toString() | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           overriteAllow: OverrideType.REMOVE | ||||||
|  |         } | ||||||
|  |       ) | ||||||
|  |       msg.channel.send(`Done!`) | ||||||
|  |     } | ||||||
|   } else if (msg.content === '!addAllRoles') { |   } else if (msg.content === '!addAllRoles') { | ||||||
|     const roles = await msg.guild?.roles.array() |     const roles = await msg.guild?.roles.array() | ||||||
|     if (roles !== undefined) { |     if (roles !== undefined) { | ||||||
|  | @ -234,6 +264,20 @@ client.on('messageCreate', async (msg: Message) => { | ||||||
|       buf += `\n${role.name}` |       buf += `\n${role.name}` | ||||||
|     } |     } | ||||||
|     msg.reply(buf) |     msg.reply(buf) | ||||||
|  |   } else if (msg.content === '!timer') { | ||||||
|  |     msg.channel.send('3...').then((msg) => { | ||||||
|  |       setTimeout(() => { | ||||||
|  |         msg.edit('2...').then((msg) => { | ||||||
|  |           setTimeout(() => { | ||||||
|  |             msg.edit('1...').then((msg) => { | ||||||
|  |               setTimeout(() => { | ||||||
|  |                 msg.edit('ok wut') | ||||||
|  |               }, 1000) | ||||||
|  |             }) | ||||||
|  |           }, 1000) | ||||||
|  |         }) | ||||||
|  |       }, 1000) | ||||||
|  |     }) | ||||||
|   } |   } | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,5 +1,8 @@ | ||||||
| import { Embed } from '../structures/embed.ts' | import { Embed } from '../structures/embed.ts' | ||||||
| import { MessageAttachment } from '../structures/message.ts' | import { Member } from '../structures/member.ts' | ||||||
|  | import { Message, MessageAttachment } from '../structures/message.ts' | ||||||
|  | import { Role } from '../structures/role.ts' | ||||||
|  | import { Permissions } from '../utils/permissions.ts' | ||||||
| import { EmojiPayload } from './emoji.ts' | import { EmojiPayload } from './emoji.ts' | ||||||
| import { MemberPayload } from './guild.ts' | import { MemberPayload } from './guild.ts' | ||||||
| import { UserPayload } from './user.ts' | import { UserPayload } from './user.ts' | ||||||
|  | @ -18,25 +21,23 @@ export interface GuildChannelPayload extends ChannelPayload { | ||||||
|   guild_id: string |   guild_id: string | ||||||
|   name: string |   name: string | ||||||
|   position: number |   position: number | ||||||
|   permission_overwrites: Overwrite[] |   permission_overwrites: OverwritePayload[] | ||||||
|  |   nsfw: boolean | ||||||
|   parent_id?: string |   parent_id?: string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface GuildTextChannelPayload | export interface GuildTextBasedChannelPayload | ||||||
|   extends TextChannelPayload, |   extends TextChannelPayload, | ||||||
|     GuildChannelPayload { |     GuildChannelPayload { | ||||||
|   nsfw: boolean |  | ||||||
|   rate_limit_per_user: number |  | ||||||
|   topic?: string |   topic?: string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface GuildNewsChannelPayload | export interface GuildTextChannelPayload extends GuildTextBasedChannelPayload { | ||||||
|   extends TextChannelPayload, |   rate_limit_per_user: number | ||||||
|     GuildChannelPayload { |  | ||||||
|   topic?: string |  | ||||||
|   nsfw: boolean |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | export interface GuildNewsChannelPayload extends GuildTextBasedChannelPayload {} | ||||||
|  | 
 | ||||||
| export interface GuildVoiceChannelPayload extends GuildChannelPayload { | export interface GuildVoiceChannelPayload extends GuildChannelPayload { | ||||||
|   bitrate: string |   bitrate: string | ||||||
|   user_limit: number |   user_limit: number | ||||||
|  | @ -59,25 +60,27 @@ export interface GuildCategoryChannelPayload | ||||||
| export interface ModifyChannelPayload { | export interface ModifyChannelPayload { | ||||||
|   name?: string |   name?: string | ||||||
|   position?: number | null |   position?: number | null | ||||||
|   permission_overwrites?: Overwrite[] | null |   permission_overwrites?: OverwritePayload[] | null | ||||||
|   parent_id?: string |   parent_id?: string | ||||||
|  |   nsfw?: boolean | null | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface ModifyGuildCategoryChannelPayload | export interface ModifyGuildCategoryChannelPayload | ||||||
|   extends ModifyChannelPayload {} |   extends ModifyChannelPayload {} | ||||||
| 
 | 
 | ||||||
| export interface ModifyGuildTextChannelPayload extends ModifyChannelPayload { | export interface ModifyGuildTextBasedChannelPayload | ||||||
|  |   extends ModifyChannelPayload { | ||||||
|   type?: number |   type?: number | ||||||
|   topic?: string | null |   topic?: string | null | ||||||
|   nsfw?: boolean | null | } | ||||||
|  | 
 | ||||||
|  | export interface ModifyGuildTextChannelPayload | ||||||
|  |   extends ModifyGuildTextBasedChannelPayload { | ||||||
|   rate_limit_per_user?: number | null |   rate_limit_per_user?: number | null | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface ModifyGuildNewsChannelPayload extends ModifyChannelPayload { | export interface ModifyGuildNewsChannelPayload | ||||||
|   type?: number |   extends ModifyGuildTextBasedChannelPayload {} | ||||||
|   topic?: string | null |  | ||||||
|   nsfw?: boolean | null |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| export interface ModifyVoiceChannelPayload extends ModifyChannelPayload { | export interface ModifyVoiceChannelPayload extends ModifyChannelPayload { | ||||||
|   bitrate?: number | null |   bitrate?: number | null | ||||||
|  | @ -87,37 +90,65 @@ export interface ModifyVoiceChannelPayload extends ModifyChannelPayload { | ||||||
| export interface ModifyChannelOption { | export interface ModifyChannelOption { | ||||||
|   name?: string |   name?: string | ||||||
|   position?: number | null |   position?: number | null | ||||||
|   permissionOverwrites?: Overwrite[] | null |   permissionOverwrites?: OverwritePayload[] | null | ||||||
|   parentID?: string |   parentID?: string | ||||||
|  |   nsfw?: boolean | null | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface ModifyGuildCategoryChannelOption extends ModifyChannelOption {} | export interface ModifyGuildCategoryChannelOption extends ModifyChannelOption {} | ||||||
| 
 | 
 | ||||||
| export interface ModifyGuildTextChannelOption extends ModifyChannelOption { | export interface ModifyGuildTextBasedChannelOption extends ModifyChannelOption { | ||||||
|   type?: number |   type?: number | ||||||
|   topic?: string | null |   topic?: string | null | ||||||
|   nsfw?: boolean | null | } | ||||||
|  | 
 | ||||||
|  | export interface ModifyGuildTextChannelOption | ||||||
|  |   extends ModifyGuildTextBasedChannelOption { | ||||||
|   slowmode?: number | null |   slowmode?: number | null | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface ModifyGuildNewsChannelOption extends ModifyChannelOption { | export interface ModifyGuildNewsChannelOption | ||||||
|   type?: number |   extends ModifyGuildTextBasedChannelOption {} | ||||||
|   topic?: string | null |  | ||||||
|   nsfw?: boolean | null |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| export interface ModifyVoiceChannelOption extends ModifyChannelOption { | export interface ModifyVoiceChannelOption extends ModifyChannelOption { | ||||||
|   bitrate?: number | null |   bitrate?: number | null | ||||||
|   userLimit?: number | null |   userLimit?: number | null | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface Overwrite { | export enum OverwriteType { | ||||||
|  |   ROLE = 0, | ||||||
|  |   USER = 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export interface OverwritePayload { | ||||||
|   id: string |   id: string | ||||||
|   type: number |   type: OverwriteType | ||||||
|   allow: string |   allow: string | ||||||
|   deny: string |   deny: string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | export interface Overwrite { | ||||||
|  |   id: string | Role | Member | ||||||
|  |   type: OverwriteType | ||||||
|  |   allow: Permissions | ||||||
|  |   deny: Permissions | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export interface OverwriteAsOptions { | ||||||
|  |   id: string | Role | Member | ||||||
|  |   type?: OverwriteType | ||||||
|  |   allow?: string | Permissions | ||||||
|  |   deny?: string | Permissions | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export type OverwriteAsArg = OverwriteAsOptions | OverwritePayload | ||||||
|  | 
 | ||||||
|  | export enum OverrideType { | ||||||
|  |   ADD = 0, | ||||||
|  |   REMOVE = 1, | ||||||
|  |   REPLACE = 2 | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export enum ChannelTypes { | export enum ChannelTypes { | ||||||
|   GUILD_TEXT = 0, |   GUILD_TEXT = 0, | ||||||
|   DM = 1, |   DM = 1, | ||||||
|  | @ -175,6 +206,7 @@ export interface MessageOptions { | ||||||
|   file?: MessageAttachment |   file?: MessageAttachment | ||||||
|   files?: MessageAttachment[] |   files?: MessageAttachment[] | ||||||
|   allowedMentions?: AllowedMentionsPayload |   allowedMentions?: AllowedMentionsPayload | ||||||
|  |   reply?: Message | MessageReference | string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface ChannelMention { | export interface ChannelMention { | ||||||
|  |  | ||||||
|  | @ -1,13 +1,20 @@ | ||||||
|  | import { GuildChannel } from '../structures/channel.ts' | ||||||
| import { Emoji } from '../structures/emoji.ts' | import { Emoji } from '../structures/emoji.ts' | ||||||
| import { CategoryChannel } from '../structures/guildCategoryChannel.ts' | import { CategoryChannel } from '../structures/guildCategoryChannel.ts' | ||||||
|  | import { NewsChannel } from '../structures/guildNewsChannel.ts' | ||||||
| import { VoiceChannel } from '../structures/guildVoiceChannel.ts' | import { VoiceChannel } from '../structures/guildVoiceChannel.ts' | ||||||
| import { Role } from '../structures/role.ts' | import { Role } from '../structures/role.ts' | ||||||
| import { GuildTextChannel } from '../structures/textChannel.ts' | import { | ||||||
|  |   GuildTextChannel, | ||||||
|  |   GuildTextBasedChannel | ||||||
|  | } from '../structures/guildTextChannel.ts' | ||||||
| import { ApplicationPayload } from './application.ts' | import { ApplicationPayload } from './application.ts' | ||||||
| import { | import { | ||||||
|   ChannelPayload, |   ChannelPayload, | ||||||
|   ChannelTypes, |   ChannelTypes, | ||||||
|   GuildCategoryChannelPayload, |   GuildCategoryChannelPayload, | ||||||
|  |   GuildNewsChannelPayload, | ||||||
|  |   GuildTextBasedChannelPayload, | ||||||
|   GuildTextChannelPayload, |   GuildTextChannelPayload, | ||||||
|   GuildVoiceChannelPayload |   GuildVoiceChannelPayload | ||||||
| } from './channel.ts' | } from './channel.ts' | ||||||
|  | @ -171,11 +178,26 @@ export interface GuildWidgetPayload { | ||||||
|   presence_count: number |   presence_count: number | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export type GuildChannelPayloads = | export type GuildTextBasedPayloads = | ||||||
|  |   | GuildTextBasedChannelPayload | ||||||
|   | GuildTextChannelPayload |   | GuildTextChannelPayload | ||||||
|  |   | GuildNewsChannelPayload | ||||||
|  | 
 | ||||||
|  | export type GuildChannelPayloads = | ||||||
|  |   | GuildTextBasedPayloads | ||||||
|   | GuildVoiceChannelPayload |   | GuildVoiceChannelPayload | ||||||
|   | GuildCategoryChannelPayload |   | GuildCategoryChannelPayload | ||||||
| export type GuildChannels = GuildTextChannel | VoiceChannel | CategoryChannel | 
 | ||||||
|  | export type GuildTextBasedChannels = | ||||||
|  |   | GuildTextBasedChannel | ||||||
|  |   | GuildTextChannel | ||||||
|  |   | NewsChannel | ||||||
|  | 
 | ||||||
|  | export type GuildChannels = | ||||||
|  |   | GuildChannel | ||||||
|  |   | GuildTextBasedChannels | ||||||
|  |   | VoiceChannel | ||||||
|  |   | CategoryChannel | ||||||
| 
 | 
 | ||||||
| export interface GuildCreatePayload { | export interface GuildCreatePayload { | ||||||
|   name: string |   name: string | ||||||
|  |  | ||||||
|  | @ -6,6 +6,7 @@ import { | ||||||
|   GroupDMChannelPayload, |   GroupDMChannelPayload, | ||||||
|   GuildCategoryChannelPayload, |   GuildCategoryChannelPayload, | ||||||
|   GuildNewsChannelPayload, |   GuildNewsChannelPayload, | ||||||
|  |   GuildTextBasedChannelPayload, | ||||||
|   GuildTextChannelPayload, |   GuildTextChannelPayload, | ||||||
|   GuildVoiceChannelPayload, |   GuildVoiceChannelPayload, | ||||||
|   TextChannelPayload |   TextChannelPayload | ||||||
|  | @ -13,16 +14,21 @@ import { | ||||||
| import { DMChannel } from '../structures/dmChannel.ts' | import { DMChannel } from '../structures/dmChannel.ts' | ||||||
| import { GroupDMChannel } from '../structures/groupChannel.ts' | import { GroupDMChannel } from '../structures/groupChannel.ts' | ||||||
| import { CategoryChannel } from '../structures/guildCategoryChannel.ts' | import { CategoryChannel } from '../structures/guildCategoryChannel.ts' | ||||||
|  | import { | ||||||
|  |   GuildTextBasedChannel, | ||||||
|  |   GuildTextChannel | ||||||
|  | } from '../structures/guildTextChannel.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 { Guild } from '../structures/guild.ts' | import { Guild } from '../structures/guild.ts' | ||||||
| import { GuildTextChannel, TextChannel } from '../structures/textChannel.ts' | import { TextChannel } from '../structures/textChannel.ts' | ||||||
| import { Channel } from '../structures/channel.ts' | import { Channel, GuildChannel } from '../structures/channel.ts' | ||||||
| 
 | 
 | ||||||
| export type EveryTextChannelTypes = | export type EveryTextChannelTypes = | ||||||
|   | TextChannel |   | TextChannel | ||||||
|   | NewsChannel |   | NewsChannel | ||||||
|   | GuildTextChannel |   | GuildTextChannel | ||||||
|  |   | GuildTextBasedChannel | ||||||
|   | DMChannel |   | DMChannel | ||||||
|   | GroupDMChannel |   | GroupDMChannel | ||||||
| 
 | 
 | ||||||
|  | @ -30,11 +36,13 @@ export type EveryTextChannelPayloadTypes = | ||||||
|   | TextChannelPayload |   | TextChannelPayload | ||||||
|   | GuildNewsChannelPayload |   | GuildNewsChannelPayload | ||||||
|   | GuildTextChannelPayload |   | GuildTextChannelPayload | ||||||
|  |   | GuildTextBasedChannelPayload | ||||||
|   | DMChannelPayload |   | DMChannelPayload | ||||||
|   | GroupDMChannelPayload |   | GroupDMChannelPayload | ||||||
| 
 | 
 | ||||||
| export type EveryChannelTypes = | export type EveryChannelTypes = | ||||||
|   | Channel |   | Channel | ||||||
|  |   | GuildChannel | ||||||
|   | CategoryChannel |   | CategoryChannel | ||||||
|   | VoiceChannel |   | VoiceChannel | ||||||
|   | EveryTextChannelTypes |   | EveryTextChannelTypes | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue