Merge pull request #27 from DjDeveloperr/main
Added CommandClient, Update README with latest examples, remove client from Adapters, simplify Intents
This commit is contained in:
		
						commit
						5dc03895a6
					
				
					 19 changed files with 685 additions and 120 deletions
				
			
		
							
								
								
									
										75
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										75
									
								
								README.md
									
										
									
									
									
								
							|  | @ -1,10 +1,22 @@ | ||||||
| # discord-deno | # discord-deno | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
| 
 | 
 | ||||||
| [](https://github.com/RichardLitt/standard-readme) | [](https://github.com/RichardLitt/standard-readme) | ||||||
| 
 | 
 | ||||||
| **An easy to use Discord API Library for Deno** | **An easy to use Discord API Library for Deno.** | ||||||
|  | * Lightweight and easy to use. | ||||||
|  | * Built-in Command Framework, | ||||||
|  |   * Easily build Commands on the fly. | ||||||
|  |   * Compltely Customizable. | ||||||
|  |   * Complete Object-Oriented approach. | ||||||
|  | * 100% Discord API Coverage. | ||||||
|  | * Customizable caching. | ||||||
|  |   * Built in support for Redis. | ||||||
|  |   * Write Custom Cache Adapters. | ||||||
|  | * Complete TypeScript support. | ||||||
|  | 
 | ||||||
|  | Note: Library is yet under development and not completely usable. You're still always welcome to use, but there may be breaking changes. | ||||||
| 
 | 
 | ||||||
| ## Table of Contents | ## Table of Contents | ||||||
| 
 | 
 | ||||||
|  | @ -15,25 +27,70 @@ | ||||||
| - [License](#license) | - [License](#license) | ||||||
| 
 | 
 | ||||||
| ## Usage | ## Usage | ||||||
|  | Right now, the package is not published anywhere, as its not completely usable. | ||||||
|  | You can import it from this Raw GitHub URL: https://raw.githubusercontent.com/discord-deno/discord.deno/main/mod.ts | ||||||
| 
 | 
 | ||||||
|  | For a quick example, run this: | ||||||
|  | ```bash | ||||||
|  | deno run --allow-net https://raw.githubusercontent.com/discord-deno/discord.deno/main/examples/ping.ts | ||||||
|  | ``` | ||||||
|  | And input your bot's token and Intents. | ||||||
|  | 
 | ||||||
|  | Here is a small example of how to use discord.deno, | ||||||
| ```ts | ```ts | ||||||
| import { Client } from 'https://deno.land/x/discord-deno/models/client.ts' | import { Client, Message, Intents } from 'https://raw.githubusercontent.com/discord-deno/discord.deno/main/mod.ts' | ||||||
| import { Message } from 'https://deno.land/x/discord-deno/structures/message.ts' |  | ||||||
| 
 | 
 | ||||||
| const bot = new Client() | const client = new Client() | ||||||
| 
 | 
 | ||||||
| bot.on('messageCreate', (msg: Message): void => { | // Listen for event when client is ready (Identified through gateway / Resumed) | ||||||
|  | client.on('ready', () => { | ||||||
|  |   console.log(`Ready! User: ${client.user?.tag}`) | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | // Listen for event whenever a Message is sent | ||||||
|  | client.on('messageCreate', (msg: Message): void => { | ||||||
|   if (msg.content === '!ping') { |   if (msg.content === '!ping') { | ||||||
|     msg.channel.send(`Pong! ping: ${bot.ping}`) |     msg.channel.send(`Pong! WS Ping: ${client.ping}`) | ||||||
|   } |   } | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| bot.connect(TOKEN, [GatewayIntents.GUILD_MESSAGES]) | // Connect to gateway | ||||||
|  | // Replace with your bot's token and intents (Intents.All, Intents.Presence, Intents.GuildMembers) | ||||||
|  | client.connect('super secret token comes here', Intents.All) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Or with CommandClient! | ||||||
|  | ```ts | ||||||
|  | import { CommandClient, Command, CommandContext, Message, Intents } from 'https://raw.githubusercontent.com/discord-deno/discord.deno/main/mod.ts' | ||||||
|  | 
 | ||||||
|  | const client = new CommandClient({ | ||||||
|  |   prefix: '!' | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | // Listen for event when client is ready (Identified through gateway / Resumed) | ||||||
|  | client.on('ready', () => { | ||||||
|  |   console.log(`Ready! User: ${client.user?.tag}`) | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | // Create a new Command | ||||||
|  | class PingCommand extends Command { | ||||||
|  |   name = "ping" | ||||||
|  | 
 | ||||||
|  |   execute(ctx: CommandContext) { | ||||||
|  |     ctx.message.reply(`pong! Ping: ${ctx.client.ping}ms`) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | client.commands.add(PingCommand) | ||||||
|  | 
 | ||||||
|  | // Connect to gateway | ||||||
|  | // Replace with your bot's token and intents (Intents.All, Intents.Presence, Intents.GuildMembers) | ||||||
|  | client.connect('super secret token comes here', Intents.All) | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ## Docs | ## Docs | ||||||
| 
 | 
 | ||||||
| Not made yet | Not made yet. | ||||||
| 
 | 
 | ||||||
| ## Maintainer | ## Maintainer | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										41
									
								
								examples/ping.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								examples/ping.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,41 @@ | ||||||
|  | import { Client, Message, Intents } from '../mod.ts' | ||||||
|  | 
 | ||||||
|  | const client = new Client(); | ||||||
|  | 
 | ||||||
|  | client.on("ready", () => { | ||||||
|  |     console.log(`Logged in as ${client.user?.tag}!`); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | client.on("messageCreate", (msg: Message) => { | ||||||
|  |     if (msg.content === "!ping") { | ||||||
|  |         console.log("Command Used: Ping"); | ||||||
|  |         msg.reply("pong!"); | ||||||
|  |     } | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | console.log("discord.deno - ping example"); | ||||||
|  | 
 | ||||||
|  | const token = prompt("Input Bot Token:"); | ||||||
|  | if (token === null) { | ||||||
|  |     console.log("No token provided"); | ||||||
|  |     Deno.exit(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const intents = prompt("Input Intents (0 = All, 1 = Presence, 2 = Server Members, 3 = None):"); | ||||||
|  | if (intents === null || !["0", "1", "2", "3"].includes(intents)) { | ||||||
|  |     console.log("No intents provided"); | ||||||
|  |     Deno.exit(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | let ints; | ||||||
|  | if (intents === "0") { | ||||||
|  |     ints = Intents.All; | ||||||
|  | } else if (intents === "1") { | ||||||
|  |     ints = Intents.Presence; | ||||||
|  | } else if (intents === "2") { | ||||||
|  |     ints = Intents.GuildMembers; | ||||||
|  | } else { | ||||||
|  |     ints = Intents.None; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | client.connect(token, ints); | ||||||
							
								
								
									
										3
									
								
								mod.ts
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								mod.ts
									
										
									
									
									
								
							|  | @ -3,6 +3,8 @@ export * from './src/models/client.ts' | ||||||
| export * from './src/models/rest.ts' | export * from './src/models/rest.ts' | ||||||
| export * from './src/models/cacheAdapter.ts' | export * from './src/models/cacheAdapter.ts' | ||||||
| export * from './src/models/shard.ts' | export * from './src/models/shard.ts' | ||||||
|  | export * from './src/models/command.ts' | ||||||
|  | export * from './src/models/commandClient.ts' | ||||||
| export * from './src/managers/base.ts' | export * from './src/managers/base.ts' | ||||||
| export * from './src/managers/baseChild.ts' | export * from './src/managers/baseChild.ts' | ||||||
| export * from './src/managers/channels.ts' | export * from './src/managers/channels.ts' | ||||||
|  | @ -53,3 +55,4 @@ export * from './src/types/user.ts' | ||||||
| export * from './src/types/voice.ts' | export * from './src/types/voice.ts' | ||||||
| export * from './src/types/webhook.ts' | export * from './src/types/webhook.ts' | ||||||
| export * from './src/utils/collection.ts' | export * from './src/utils/collection.ts' | ||||||
|  | export * from './src/utils/intents.ts' | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| import { unzlib } from 'https://deno.land/x/denoflate/mod.ts' | import { unzlib } from 'https://deno.land/x/denoflate@1.1/mod.ts' | ||||||
| import { Client } from '../models/client.ts' | import { Client } from '../models/client.ts' | ||||||
| import { | import { | ||||||
|   DISCORD_GATEWAY_URL, |   DISCORD_GATEWAY_URL, | ||||||
|  | @ -76,21 +76,10 @@ class Gateway { | ||||||
|         this.debug( |         this.debug( | ||||||
|           `Received HELLO. Heartbeat Interval: ${this.heartbeatInterval}` |           `Received HELLO. Heartbeat Interval: ${this.heartbeatInterval}` | ||||||
|         ) |         ) | ||||||
|         this.heartbeatIntervalID = setInterval(() => { |  | ||||||
|           if (this.heartbeatServerResponded) { |  | ||||||
|             this.heartbeatServerResponded = false |  | ||||||
|           } else { |  | ||||||
|             clearInterval(this.heartbeatIntervalID) |  | ||||||
|             // eslint-disable-next-line @typescript-eslint/no-floating-promises
 |  | ||||||
|             this.reconnect() |  | ||||||
|             return |  | ||||||
|           } |  | ||||||
| 
 | 
 | ||||||
|           this.send({ |         this.sendHeartbeat() | ||||||
|             op: GatewayOpcodes.HEARTBEAT, |         this.heartbeatIntervalID = setInterval(() => { | ||||||
|             d: this.sequenceID ?? null |           this.heartbeat() | ||||||
|           }) |  | ||||||
|           this.lastPingTimestamp = Date.now() |  | ||||||
|         }, this.heartbeatInterval) |         }, this.heartbeatInterval) | ||||||
| 
 | 
 | ||||||
|         if (!this.initialized) { |         if (!this.initialized) { | ||||||
|  | @ -201,6 +190,7 @@ class Gateway { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private async sendIdentify(forceNewSession?: boolean): Promise<void> { |   private async sendIdentify(forceNewSession?: boolean): Promise<void> { | ||||||
|  |     if (this.client.bot === true) { | ||||||
|       this.debug('Fetching /gateway/bot...') |       this.debug('Fetching /gateway/bot...') | ||||||
|       const info = await this.client.rest.get(GATEWAY_BOT()) |       const info = await this.client.rest.get(GATEWAY_BOT()) | ||||||
|       if (info.session_start_limit.remaining === 0) |       if (info.session_start_limit.remaining === 0) | ||||||
|  | @ -221,7 +211,9 @@ class Gateway { | ||||||
|           return await this.sendResume() |           return await this.sendResume() | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     this.send({ |     } | ||||||
|  | 
 | ||||||
|  |     const payload: any = { | ||||||
|       op: GatewayOpcodes.IDENTIFY, |       op: GatewayOpcodes.IDENTIFY, | ||||||
|       d: { |       d: { | ||||||
|         token: this.token, |         token: this.token, | ||||||
|  | @ -238,7 +230,24 @@ class Gateway { | ||||||
|         ), |         ), | ||||||
|         presence: this.client.presence.create() |         presence: this.client.presence.create() | ||||||
|       } |       } | ||||||
|     }) |     } | ||||||
|  | 
 | ||||||
|  |     if (this.client.bot === false) { | ||||||
|  |       // TODO: Complete Selfbot support
 | ||||||
|  |       this.debug("Modify Identify Payload for Self-bot..") | ||||||
|  |       // delete payload.d['intents']
 | ||||||
|  |       // payload.d.intents = Intents.None
 | ||||||
|  |       payload.d.presence = null | ||||||
|  |       payload.d.properties = { | ||||||
|  |         $os: "Windows", | ||||||
|  |         $browser: "Firefox", | ||||||
|  |         $device: "" | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       this.debug("Warn: Support for selfbots is incomplete") | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     this.send(payload) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private async sendResume(): Promise<void> { |   private async sendResume(): Promise<void> { | ||||||
|  | @ -305,6 +314,29 @@ class Gateway { | ||||||
|       d: data |       d: data | ||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   sendHeartbeat(): void { | ||||||
|  |     const payload = { | ||||||
|  |       op: GatewayOpcodes.HEARTBEAT, | ||||||
|  |       d: this.sequenceID ?? null | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     this.send(payload) | ||||||
|  |     this.lastPingTimestamp = Date.now() | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   heartbeat(): void { | ||||||
|  |     if (this.heartbeatServerResponded) { | ||||||
|  |       this.heartbeatServerResponded = false | ||||||
|  |     } else { | ||||||
|  |       clearInterval(this.heartbeatIntervalID) | ||||||
|  |       // eslint-disable-next-line @typescript-eslint/no-floating-promises
 | ||||||
|  |       this.reconnect() | ||||||
|  |       return | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     this.sendHeartbeat() | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export type GatewayEventHandler = (gateway: Gateway, d: any) => void | export type GatewayEventHandler = (gateway: Gateway, d: any) => void | ||||||
|  |  | ||||||
|  | @ -1,5 +1,4 @@ | ||||||
| import { Collection } from '../utils/collection.ts' | import { Collection } from '../utils/collection.ts' | ||||||
| import { Client } from './client.ts' |  | ||||||
| import { | import { | ||||||
|   connect, |   connect, | ||||||
|   Redis, |   Redis, | ||||||
|  | @ -7,7 +6,6 @@ import { | ||||||
| } from 'https://denopkg.com/keroxp/deno-redis/mod.ts' | } from 'https://denopkg.com/keroxp/deno-redis/mod.ts' | ||||||
| 
 | 
 | ||||||
| export interface ICacheAdapter { | export interface ICacheAdapter { | ||||||
|   client: Client |  | ||||||
|   get: (cacheName: string, key: string) => Promise<any> | any |   get: (cacheName: string, key: string) => Promise<any> | any | ||||||
|   set: (cacheName: string, key: string, value: any) => Promise<any> | any |   set: (cacheName: string, key: string, value: any) => Promise<any> | any | ||||||
|   delete: (cacheName: string, key: string) => Promise<boolean> | boolean |   delete: (cacheName: string, key: string) => Promise<boolean> | boolean | ||||||
|  | @ -16,15 +14,10 @@ export interface ICacheAdapter { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export class DefaultCacheAdapter implements ICacheAdapter { | export class DefaultCacheAdapter implements ICacheAdapter { | ||||||
|   client: Client |  | ||||||
|   data: { |   data: { | ||||||
|     [name: string]: Collection<string, any> |     [name: string]: Collection<string, any> | ||||||
|   } = {} |   } = {} | ||||||
| 
 | 
 | ||||||
|   constructor (client: Client) { |  | ||||||
|     this.client = client |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   async get (cacheName: string, key: string): Promise<undefined | any> { |   async get (cacheName: string, key: string): Promise<undefined | any> { | ||||||
|     const cache = this.data[cacheName] |     const cache = this.data[cacheName] | ||||||
|     if (cache === undefined) return |     if (cache === undefined) return | ||||||
|  | @ -59,13 +52,11 @@ export class DefaultCacheAdapter implements ICacheAdapter { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export class RedisCacheAdapter implements ICacheAdapter { | export class RedisCacheAdapter implements ICacheAdapter { | ||||||
|   client: Client |  | ||||||
|   _redis: Promise<Redis> |   _redis: Promise<Redis> | ||||||
|   redis?: Redis |   redis?: Redis | ||||||
|   ready: boolean = false |   ready: boolean = false | ||||||
| 
 | 
 | ||||||
|   constructor (client: Client, options: RedisConnectOptions) { |   constructor (options: RedisConnectOptions) { | ||||||
|     this.client = client |  | ||||||
|     this._redis = connect(options) |     this._redis = connect(options) | ||||||
|     this._redis.then( |     this._redis.then( | ||||||
|       redis => { |       redis => { | ||||||
|  |  | ||||||
|  | @ -18,6 +18,8 @@ export interface ClientOptions { | ||||||
|   cache?: ICacheAdapter, |   cache?: ICacheAdapter, | ||||||
|   forceNewSession?: boolean, |   forceNewSession?: boolean, | ||||||
|   presence?: ClientPresence | ClientActivity | ActivityGame |   presence?: ClientPresence | ClientActivity | ActivityGame | ||||||
|  |   bot?: boolean | ||||||
|  |   canary?: boolean | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  | @ -29,7 +31,7 @@ export class Client extends EventEmitter { | ||||||
|   user?: User |   user?: User | ||||||
|   ping = 0 |   ping = 0 | ||||||
|   token?: string |   token?: string | ||||||
|   cache: ICacheAdapter = new DefaultCacheAdapter(this) |   cache: ICacheAdapter = new DefaultCacheAdapter() | ||||||
|   intents?: GatewayIntents[] |   intents?: GatewayIntents[] | ||||||
|   forceNewSession?: boolean |   forceNewSession?: boolean | ||||||
|   users: UserManager = new UserManager(this) |   users: UserManager = new UserManager(this) | ||||||
|  | @ -37,6 +39,8 @@ export class Client extends EventEmitter { | ||||||
|   channels: ChannelsManager = new ChannelsManager(this) |   channels: ChannelsManager = new ChannelsManager(this) | ||||||
|   messages: MessagesManager = new MessagesManager(this) |   messages: MessagesManager = new MessagesManager(this) | ||||||
|   emojis: EmojisManager = new EmojisManager(this) |   emojis: EmojisManager = new EmojisManager(this) | ||||||
|  |   bot: boolean = true | ||||||
|  |   canary: boolean = false | ||||||
| 
 | 
 | ||||||
|   presence: ClientPresence = new ClientPresence() |   presence: ClientPresence = new ClientPresence() | ||||||
| 
 | 
 | ||||||
|  | @ -47,6 +51,8 @@ export class Client extends EventEmitter { | ||||||
|     this.forceNewSession = options.forceNewSession |     this.forceNewSession = options.forceNewSession | ||||||
|     if (options.cache !== undefined) this.cache = options.cache |     if (options.cache !== undefined) this.cache = options.cache | ||||||
|     if (options.presence !== undefined) this.presence = options.presence instanceof ClientPresence ? options.presence : new ClientPresence(options.presence) |     if (options.presence !== undefined) this.presence = options.presence instanceof ClientPresence ? options.presence : new ClientPresence(options.presence) | ||||||
|  |     if (options.bot === false) this.bot = false | ||||||
|  |     if (options.canary === true) this.canary = true | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   setAdapter (adapter: ICacheAdapter): Client { |   setAdapter (adapter: ICacheAdapter): Client { | ||||||
|  |  | ||||||
							
								
								
									
										126
									
								
								src/models/command.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								src/models/command.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,126 @@ | ||||||
|  | import { Message } from "../structures/message.ts" | ||||||
|  | import { TextChannel } from "../structures/textChannel.ts" | ||||||
|  | import { User } from "../structures/user.ts" | ||||||
|  | import { Collection } from "../utils/collection.ts" | ||||||
|  | import { CommandClient } from "./commandClient.ts" | ||||||
|  | 
 | ||||||
|  | export interface CommandContext { | ||||||
|  |   /** The Client object */ | ||||||
|  |   client: CommandClient | ||||||
|  |   /** Message which was parsed for Command */ | ||||||
|  |   message: Message | ||||||
|  |   /** The Author of the Message */ | ||||||
|  |   author: User | ||||||
|  |   /** The Channel in which Command was used */ | ||||||
|  |   channel: TextChannel | ||||||
|  |   /** Prefix which was used */ | ||||||
|  |   prefix: string | ||||||
|  |   /** Oject of Command which was used */ | ||||||
|  |   command: Command | ||||||
|  |   /** Name of Command which was used */ | ||||||
|  |   name: string | ||||||
|  |   /** Array of Arguments used with Command */ | ||||||
|  |   args: string[] | ||||||
|  |   /** Complete Raw String of Arguments */ | ||||||
|  |   argString: string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export class Command { | ||||||
|  |   /** Name of the Command */ | ||||||
|  |   name: string = "" | ||||||
|  |   /** Description of the Command */ | ||||||
|  |   description?: string | ||||||
|  |   /** Array of Aliases of Command, or only string */ | ||||||
|  |   aliases?: string | string[] | ||||||
|  |   /** Usage of Command, only Argument Names */ | ||||||
|  |   usage?: string | string[] | ||||||
|  |   /** Usage Example of Command, only Arguments (without Prefix and Name) */ | ||||||
|  |   examples?: string | string[] | ||||||
|  |   /** Does the Command take Arguments? Maybe number of required arguments? */ | ||||||
|  |   args?: number | boolean | ||||||
|  |   /** Permission(s) required for using Command */ | ||||||
|  |   permissions?: string | string[] | ||||||
|  |   /** Whether the Command can only be used in Guild (if allowed in DMs) */ | ||||||
|  |   guildOnly?: boolean | ||||||
|  |   /** Whether the Command can only be used in Bot's DMs (if allowed) */ | ||||||
|  |   dmOnly?: boolean | ||||||
|  |   /** Whether the Command can only be used by Bot Owners */ | ||||||
|  |   ownerOnly?: boolean | ||||||
|  | 
 | ||||||
|  |   execute(ctx?: CommandContext): any { } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export class CommandsManager { | ||||||
|  |   client: CommandClient | ||||||
|  |   list: Collection<string, Command> = new Collection() | ||||||
|  | 
 | ||||||
|  |   constructor(client: CommandClient) { | ||||||
|  |     this.client = client | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Find a Command by name/alias */ | ||||||
|  |   find(search: string): Command | undefined { | ||||||
|  |     if (this.client.caseSensitive === false) search = search.toLowerCase() | ||||||
|  |     return this.list.find((cmd: Command): boolean => { | ||||||
|  |       const name = this.client.caseSensitive === true ? cmd.name : cmd.name.toLowerCase() | ||||||
|  |       if (name === search) return true | ||||||
|  |       else if (cmd.aliases !== undefined) { | ||||||
|  |         let aliases: string[] | ||||||
|  |         if (typeof cmd.aliases === "string") aliases = [cmd.aliases] | ||||||
|  |         else aliases = cmd.aliases | ||||||
|  |         if (this.client.caseSensitive === false) aliases = aliases.map(e => e.toLowerCase()) | ||||||
|  |         return aliases.includes(search) | ||||||
|  |       } else return false | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Check whether a Command exists or not */ | ||||||
|  |   exists(search: Command | string): boolean { | ||||||
|  |     let exists = false | ||||||
|  |     if (typeof search === "string") return this.find(search) !== undefined | ||||||
|  |     else { | ||||||
|  |       exists = this.find(search.name) !== undefined | ||||||
|  |       if (search.aliases !== undefined) { | ||||||
|  |         const aliases: string[] = typeof search.aliases === "string" ? [search.aliases] : search.aliases | ||||||
|  |         exists = aliases.map(alias => this.find(alias) !== undefined).find(e => e) ?? false | ||||||
|  |       } | ||||||
|  |       return exists | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Add a Command */ | ||||||
|  |   add(cmd: Command | typeof Command): boolean { | ||||||
|  |     // eslint-disable-next-line new-cap
 | ||||||
|  |     if (!(cmd instanceof Command)) cmd = new cmd() | ||||||
|  |     if (this.exists(cmd)) return false | ||||||
|  |     this.list.set(cmd.name, cmd) | ||||||
|  |     return true | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Delete a Command */ | ||||||
|  |   delete(cmd: string | Command): boolean { | ||||||
|  |     const find = typeof cmd === "string" ? this.find(cmd) : cmd | ||||||
|  |     if (find === undefined) return false | ||||||
|  |     else return this.list.delete(find.name) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export interface ParsedCommand { | ||||||
|  |   name: string | ||||||
|  |   args: string[] | ||||||
|  |   argString: string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export const parseCommand = (client: CommandClient, msg: Message, prefix: string): ParsedCommand => { | ||||||
|  |   let content = msg.content.slice(prefix.length) | ||||||
|  |   if (client.spacesAfterPrefix === true) content = content.trim() | ||||||
|  |   const args = content.split(client.betterArgs === true ? /[\S\s]*/ : / +/) | ||||||
|  |   const name = args.shift() as string | ||||||
|  |   const argString = content.slice(name.length).trim() | ||||||
|  | 
 | ||||||
|  |   return { | ||||||
|  |     name, | ||||||
|  |     args, | ||||||
|  |     argString | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										161
									
								
								src/models/commandClient.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								src/models/commandClient.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,161 @@ | ||||||
|  | import { Embed, Message } from '../../mod.ts' | ||||||
|  | import { Client, ClientOptions } from './client.ts' | ||||||
|  | import { CommandContext, CommandsManager, parseCommand } from './command.ts' | ||||||
|  | 
 | ||||||
|  | type PrefixReturnType = string | string[] | Promise<string | string[]> | ||||||
|  | 
 | ||||||
|  | export interface CommandClientOptions extends ClientOptions { | ||||||
|  |   prefix: string | string[] | ||||||
|  |   mentionPrefix?: boolean | ||||||
|  |   getGuildPrefix?: (guildID: string) => PrefixReturnType | ||||||
|  |   getUserPrefix?: (userID: string) => PrefixReturnType | ||||||
|  |   spacesAfterPrefix?: boolean | ||||||
|  |   betterArgs?: boolean | ||||||
|  |   owners?: string[] | ||||||
|  |   allowBots?: boolean | ||||||
|  |   allowDMs?: boolean | ||||||
|  |   caseSensitive?: boolean | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type CommandText = string | Embed | ||||||
|  | 
 | ||||||
|  | export interface CommandTexts { | ||||||
|  |   GUILD_ONLY?: CommandText | ||||||
|  |   OWNER_ONLY?: CommandText | ||||||
|  |   DMS_ONLY?: CommandText | ||||||
|  |   ERROR?: CommandText | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export const DefaultCommandTexts: CommandTexts = { | ||||||
|  |   GUILD_ONLY: 'This command can only be used in a Server!', | ||||||
|  |   OWNER_ONLY: 'This command can only be used by Bot Owners!', | ||||||
|  |   DMS_ONLY: 'This command can only be used in Bot\'s DMs!', | ||||||
|  |   ERROR: 'An error occured while executing command!' | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | interface Replaces { | ||||||
|  |   [name: string]: string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export const massReplace = (text: string, replaces: Replaces): string => { | ||||||
|  |   Object.entries(replaces).forEach(replace => { | ||||||
|  |     text = text.replace(new RegExp(`{{${replace[0]}}}`, 'g'), replace[1]) | ||||||
|  |   }) | ||||||
|  |   return text | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export class CommandClient extends Client { | ||||||
|  |   prefix: string | string[] | ||||||
|  |   mentionPrefix: boolean | ||||||
|  |   getGuildPrefix: (guildID: string) => PrefixReturnType | ||||||
|  |   getUserPrefix: (userID: string) => PrefixReturnType | ||||||
|  |   spacesAfterPrefix: boolean | ||||||
|  |   betterArgs: boolean | ||||||
|  |   owners: string[] | ||||||
|  |   allowBots: boolean | ||||||
|  |   allowDMs: boolean | ||||||
|  |   caseSensitive: boolean | ||||||
|  |   commands: CommandsManager = new CommandsManager(this) | ||||||
|  |   texts: CommandTexts = DefaultCommandTexts | ||||||
|  | 
 | ||||||
|  |   constructor(options: CommandClientOptions) { | ||||||
|  |     super(options) | ||||||
|  |     this.prefix = options.prefix | ||||||
|  |     this.mentionPrefix = options.mentionPrefix === undefined ? false : options.mentionPrefix | ||||||
|  |     this.getGuildPrefix = options.getGuildPrefix === undefined ? (id: string) => this.prefix : options.getGuildPrefix | ||||||
|  |     this.getUserPrefix = options.getUserPrefix === undefined ? (id: string) => this.prefix : options.getUserPrefix | ||||||
|  |     this.spacesAfterPrefix = options.spacesAfterPrefix === undefined ? false : options.spacesAfterPrefix | ||||||
|  |     this.betterArgs = options.betterArgs === undefined ? false : options.betterArgs | ||||||
|  |     this.owners = options.owners === undefined ? [] : options.owners | ||||||
|  |     this.allowBots = options.allowBots === undefined ? false : options.allowBots | ||||||
|  |     this.allowDMs = options.allowDMs === undefined ? true : options.allowDMs | ||||||
|  |     this.caseSensitive = options.caseSensitive === undefined ? false : options.caseSensitive | ||||||
|  | 
 | ||||||
|  |     this.on('messageCreate', async (msg: Message) => await this.processMessage(msg)) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async processMessage(msg: Message): Promise<any> { | ||||||
|  |     if (!this.allowBots && msg.author.bot === true) return | ||||||
|  | 
 | ||||||
|  |     let prefix: string | string[] = this.prefix | ||||||
|  | 
 | ||||||
|  |     if (msg.guild !== undefined) { | ||||||
|  |       let guildPrefix = this.getGuildPrefix(msg.guild.id) | ||||||
|  |       if (guildPrefix instanceof Promise) guildPrefix = await guildPrefix | ||||||
|  |       prefix = guildPrefix | ||||||
|  |     } else { | ||||||
|  |       let userPrefix = this.getUserPrefix(msg.author.id) | ||||||
|  |       if (userPrefix instanceof Promise) userPrefix = await userPrefix | ||||||
|  |       prefix = userPrefix | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (typeof prefix === 'string') { | ||||||
|  |       if (msg.content.startsWith(prefix) === false) return | ||||||
|  |     } else { | ||||||
|  |       const usedPrefix = prefix.find(v => msg.content.startsWith(v)) | ||||||
|  |       if (usedPrefix === undefined) return | ||||||
|  |       else prefix = usedPrefix | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const parsed = parseCommand(this, msg, prefix) | ||||||
|  |     const command = this.commands.find(parsed.name) | ||||||
|  | 
 | ||||||
|  |     if (command === undefined) return | ||||||
|  | 
 | ||||||
|  |     const baseReplaces: Replaces = { | ||||||
|  |       command: command.name, | ||||||
|  |       nameUsed: parsed.name, | ||||||
|  |       prefix, | ||||||
|  |       username: msg.author.username, | ||||||
|  |       tag: msg.author.tag, | ||||||
|  |       mention: msg.author.mention, | ||||||
|  |       id: msg.author.id | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (command.guildOnly === true && msg.guild === undefined) { | ||||||
|  |       if (this.texts.GUILD_ONLY !== undefined) return this.sendProcessedText(msg, this.texts.GUILD_ONLY, baseReplaces) | ||||||
|  |       return | ||||||
|  |     } | ||||||
|  |     if (command.dmOnly === true && msg.guild !== undefined) { | ||||||
|  |       if (this.texts.DMS_ONLY !== undefined) return this.sendProcessedText(msg, this.texts.DMS_ONLY, baseReplaces) | ||||||
|  |       return | ||||||
|  |     } | ||||||
|  |     if (command.ownerOnly === true && !this.owners.includes(msg.author.id)) { | ||||||
|  |       if (this.texts.OWNER_ONLY !== undefined) return this.sendProcessedText(msg, this.texts.OWNER_ONLY, baseReplaces) | ||||||
|  |       return | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const ctx: CommandContext = { | ||||||
|  |       client: this, | ||||||
|  |       name: parsed.name, | ||||||
|  |       prefix, | ||||||
|  |       args: parsed.args, | ||||||
|  |       argString: parsed.argString, | ||||||
|  |       message: msg, | ||||||
|  |       author: msg.author, | ||||||
|  |       command, | ||||||
|  |       channel: msg.channel | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     try { | ||||||
|  |       this.emit('commandUsed', { context: ctx }) | ||||||
|  |       command.execute(ctx) | ||||||
|  |     } catch (e) { | ||||||
|  |       if (this.texts.ERROR !== undefined) return this.sendProcessedText(msg, this.texts.ERROR, Object.assign(baseReplaces, { error: e.message })) | ||||||
|  |       this.emit('commandError', { command, parsed, error: e }) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   sendProcessedText(msg: Message, text: CommandText, replaces: Replaces): any { | ||||||
|  |     if (typeof text === "string") { | ||||||
|  |       text = massReplace(text, replaces) | ||||||
|  |       return msg.channel.send(text) | ||||||
|  |     } else { | ||||||
|  |       if (text.description !== undefined) text.description = massReplace(text.description, replaces) | ||||||
|  |       if (text.title !== undefined) text.description = massReplace(text.title, replaces) | ||||||
|  |       if (text.author?.name !== undefined) text.description = massReplace(text.author.name, replaces) | ||||||
|  |       if (text.footer?.text !== undefined) text.description = massReplace(text.footer.text, replaces) | ||||||
|  |       return msg.channel.send(text) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| import { delay } from '../utils/index.ts' | import { delay } from '../utils/index.ts' | ||||||
| import * as baseEndpoints from '../consts/urlsAndVersions.ts' | import * as baseEndpoints from '../consts/urlsAndVersions.ts' | ||||||
| import { Client } from './client.ts' | import { Client } from './client.ts' | ||||||
|  | import { getBuildInfo } from "../utils/buildInfo.ts" | ||||||
| 
 | 
 | ||||||
| export enum HttpResponseCode { | export enum HttpResponseCode { | ||||||
|   Ok = 200, |   Ok = 200, | ||||||
|  | @ -175,11 +176,29 @@ export class RESTManager { | ||||||
|       headers['Content-Type'] = 'application/json' |       headers['Content-Type'] = 'application/json' | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return { |     const data: { [name: string]: any } = { | ||||||
|       headers, |       headers, | ||||||
|       body: body?.file ?? JSON.stringify(body), |       body: body?.file ?? JSON.stringify(body), | ||||||
|       method: method.toUpperCase() |       method: method.toUpperCase() | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     if (this.client.bot === false) { | ||||||
|  |       // This is a selfbot. Use requests similar to Discord Client
 | ||||||
|  |       data.headers.authorization = this.client.token as string | ||||||
|  |       data.headers['accept-language'] = 'en-US' | ||||||
|  |       data.headers.accept = '*/*' | ||||||
|  |       data.headers['sec-fetch-dest'] = 'empty' | ||||||
|  |       data.headers['sec-fetch-mode'] = 'cors' | ||||||
|  |       data.headers['sec-fetch-site'] = 'same-origin' | ||||||
|  |       data.headers['x-super-properties'] = btoa(JSON.stringify(getBuildInfo(this.client))) | ||||||
|  |       delete data.headers['User-Agent'] | ||||||
|  |       delete data.headers.Authorization | ||||||
|  |       headers.credentials = 'include' | ||||||
|  |       headers.mode = 'cors' | ||||||
|  |       headers.referrerPolicy = 'no-referrer-when-downgrade' | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return data | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async checkRatelimits (url: string): Promise<number | false> { |   async checkRatelimits (url: string): Promise<number | false> { | ||||||
|  | @ -230,9 +249,14 @@ export class RESTManager { | ||||||
|                   ) |                   ) | ||||||
|                   .join('&') |                   .join('&') | ||||||
|               : '' |               : '' | ||||||
|           const urlToUse = |           let urlToUse = | ||||||
|             method === 'get' && query !== '' ? `${url}?${query}` : url |             method === 'get' && query !== '' ? `${url}?${query}` : url | ||||||
| 
 | 
 | ||||||
|  |           if (this.client.canary === true) { | ||||||
|  |             const split = urlToUse.split('//') | ||||||
|  |             urlToUse = split[0] + '//canary.' + split[1] | ||||||
|  |           } | ||||||
|  | 
 | ||||||
|           const requestData = this.createRequestBody(body, method) |           const requestData = this.createRequestBody(body, method) | ||||||
| 
 | 
 | ||||||
|           const response = await fetch( |           const response = await fetch( | ||||||
|  |  | ||||||
|  | @ -2,9 +2,12 @@ import { Client } from '../models/client.ts' | ||||||
| import { MessageOption, TextChannelPayload } from '../types/channel.ts' | import { MessageOption, TextChannelPayload } from '../types/channel.ts' | ||||||
| import { CHANNEL_MESSAGE, CHANNEL_MESSAGES } from '../types/endpoint.ts' | import { CHANNEL_MESSAGE, CHANNEL_MESSAGES } from '../types/endpoint.ts' | ||||||
| import { Channel } from './channel.ts' | import { Channel } from './channel.ts' | ||||||
|  | import { Embed } from "./embed.ts" | ||||||
| import { Message } from './message.ts' | import { Message } from './message.ts' | ||||||
| import { MessageMentions } from './messageMentions.ts' | import { MessageMentions } from './messageMentions.ts' | ||||||
| 
 | 
 | ||||||
|  | type AllMessageOptions = MessageOption | Embed | ||||||
|  | 
 | ||||||
| export class TextChannel extends Channel { | export class TextChannel extends Channel { | ||||||
|   lastMessageID?: string |   lastMessageID?: string | ||||||
|   lastPinTimestamp?: string |   lastPinTimestamp?: string | ||||||
|  | @ -23,10 +26,18 @@ export class TextChannel extends Channel { | ||||||
|     this.lastPinTimestamp = data.last_pin_timestamp ?? this.lastPinTimestamp |     this.lastPinTimestamp = data.last_pin_timestamp ?? this.lastPinTimestamp | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async send (text?: string, option?: MessageOption): Promise<Message> { |   async send (text?: string | AllMessageOptions, option?: AllMessageOptions): Promise<Message> { | ||||||
|  |     if(typeof text === "object") { | ||||||
|  |       option = text | ||||||
|  |       text = undefined | ||||||
|  |     } | ||||||
|     if (text === undefined && option === undefined) { |     if (text === undefined && option === undefined) { | ||||||
|       throw new Error('Either text or option is necessary.') |       throw new Error('Either text or option is necessary.') | ||||||
|     } |     } | ||||||
|  |     if(option instanceof Embed) option = { | ||||||
|  |       embed: option | ||||||
|  |     } | ||||||
|  |      | ||||||
|     const resp = await this.client.rest.post(CHANNEL_MESSAGES(this.id), { |     const resp = await this.client.rest.post(CHANNEL_MESSAGES(this.id), { | ||||||
|         content: text, |         content: text, | ||||||
|         embed: option?.embed, |         embed: option?.embed, | ||||||
|  |  | ||||||
							
								
								
									
										18
									
								
								src/test/cmd.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/test/cmd.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | ||||||
|  | import { CommandClient, Intents } from '../../mod.ts'; | ||||||
|  | import PingCommand from "./cmds/ping.ts"; | ||||||
|  | import { TOKEN } from './config.ts' | ||||||
|  | 
 | ||||||
|  | const client = new CommandClient({ | ||||||
|  |   prefix: ["pls", "!"], | ||||||
|  |   spacesAfterPrefix: true | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | client.on('debug', console.log) | ||||||
|  | 
 | ||||||
|  | client.on('ready', () => { | ||||||
|  |   console.log(`[Login] Logged in as ${client.user?.tag}!`) | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | client.commands.add(PingCommand) | ||||||
|  | 
 | ||||||
|  | client.connect(TOKEN, Intents.All) | ||||||
							
								
								
									
										11
									
								
								src/test/cmds/ping.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/test/cmds/ping.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | ||||||
|  | import { Command } from "../../../mod.ts"; | ||||||
|  | import { CommandContext } from "../../models/command.ts"; | ||||||
|  | 
 | ||||||
|  | export default class PingCommand extends Command { | ||||||
|  |   name = "ping" | ||||||
|  |   dmOnly = true | ||||||
|  | 
 | ||||||
|  |   execute(ctx: CommandContext): void { | ||||||
|  |     ctx.message.reply(`pong! Latency: ${ctx.client.ping}ms`) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | @ -1,90 +1,62 @@ | ||||||
| import { Client } from '../models/client.ts' | import { Client, Intents, GuildTextChannel, Message, ClientPresence, Member, Role, GuildChannel, Embed, Guild } from '../../mod.ts'; | ||||||
| import { GatewayIntents } from '../types/gateway.ts' |  | ||||||
| import { TOKEN } from './config.ts' | import { TOKEN } from './config.ts' | ||||||
| import { Message } from "../structures/message.ts" |  | ||||||
| import { DefaultCacheAdapter } from "../models/cacheAdapter.ts" |  | ||||||
| import { ClientPresence } from "../structures/presence.ts" |  | ||||||
| import { Member } from "../structures/member.ts" |  | ||||||
| import { Role } from "../structures/role.ts" |  | ||||||
| import { GuildChannel } from "../managers/guildChannels.ts" |  | ||||||
| import { TextChannel } from "../structures/textChannel.ts" |  | ||||||
| import { Embed } from "../structures/embed.ts" |  | ||||||
| import { Guild } from "../structures/guild.ts" |  | ||||||
| 
 | 
 | ||||||
| const bot = new Client({ | const client = new Client({ | ||||||
|   presence: new ClientPresence({ |   presence: new ClientPresence({ | ||||||
|     activity: { |       name: 'Pokémon Sword', | ||||||
|       name: "Testing", |  | ||||||
|       type: 'COMPETING' |       type: 'COMPETING' | ||||||
|     } |  | ||||||
|   }), |   }), | ||||||
|  |   // bot: false,
 | ||||||
|  |   // cache: new RedisCacheAdapter({
 | ||||||
|  |   //   hostname: '127.0.0.1',
 | ||||||
|  |   //   port: 6379
 | ||||||
|  |   // }) // Defaults to in-memory Caching
 | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| bot.setAdapter(new DefaultCacheAdapter(bot)) | client.on('ready', () => { | ||||||
| 
 |   console.log(`[Login] Logged in as ${client.user?.tag}!`) | ||||||
| bot.on('ready', () => { |  | ||||||
|   console.log(`[Login] Logged in as ${bot.user?.tag}!`) |  | ||||||
|   bot.setPresence({ |  | ||||||
|     name: "Test After Ready", |  | ||||||
|     type: 'COMPETING' |  | ||||||
|   }) |  | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| bot.on('debug', console.log) | client.on('debug', console.log) | ||||||
| 
 | 
 | ||||||
| bot.on('channelPinsUpdate', (before: TextChannel, after: TextChannel) => { | client.on('channelUpdate', (before: GuildTextChannel, after: GuildTextChannel) => { | ||||||
|   console.log(before.send('', { |   console.log(before.send('', { | ||||||
|     embed: new Embed({ |     embed: new Embed({ | ||||||
|       title: 'Test', |       title: 'Channel Update', | ||||||
|       description: 'Test Embed' |       description: `Name Before: ${before.name}\nName After: ${after.name}` | ||||||
|     }) |     }) | ||||||
|   })) |   })) | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| bot.on('messageCreate', async (msg: Message) => { | client.on('messageCreate', async (msg: Message) => { | ||||||
|   if (msg.author.bot === true) return |   if (msg.author.bot === true) return | ||||||
|   if (msg.content === "!ping") { |   console.log(`${msg.author.tag}: ${msg.content}`) | ||||||
|     msg.reply(`Pong! Ping: ${bot.ping}ms`) |   if (msg.content === '!ping') { | ||||||
|   } else if (msg.content === "!members") { |     msg.reply(`Pong! Ping: ${client.ping}ms`) | ||||||
|  |   } else if (msg.content === '!members') { | ||||||
|     const col = await msg.guild?.members.collection() |     const col = await msg.guild?.members.collection() | ||||||
|     const data = col?.array().map((c: Member, i: number) => { |     const data = col?.array().map((c: Member, i: number) => { | ||||||
|       return `${i + 1}. ${c.user.tag}` |       return `${i + 1}. ${c.user.tag}` | ||||||
|     }).join("\n") as string |     }).join("\n") as string | ||||||
|     msg.channel.send("Member List:\n" + data) |     msg.channel.send("Member List:\n" + data) | ||||||
|   } else if (msg.content === "!guilds") { |   } else if (msg.content === '!guilds') { | ||||||
|     const guilds = await msg.client.guilds.collection() |     const guilds = await msg.client.guilds.collection() | ||||||
|     msg.channel.send("Guild List:\n" + (guilds.array().map((c: Guild, i: number) => { |     msg.channel.send('Guild List:\n' + (guilds.array().map((c: Guild, i: number) => { | ||||||
|       return `${i + 1}. ${c.name} - ${c.memberCount} members` |       return `${i + 1}. ${c.name} - ${c.memberCount} members` | ||||||
|     }).join("\n") as string)) |     }).join("\n") as string)) | ||||||
|   } else if (msg.content === "!roles") { |   } else if (msg.content === '!roles') { | ||||||
|     const col = await msg.guild?.roles.collection() |     const col = await msg.guild?.roles.collection() | ||||||
|     const data = col?.array().map((c: Role, i: number) => { |     const data = col?.array().map((c: Role, i: number) => { | ||||||
|       return `${i + 1}. ${c.name}` |       return `${i + 1}. ${c.name}` | ||||||
|     }).join("\n") as string |     }).join("\n") as string | ||||||
|     msg.channel.send("Roles List:\n" + data) |     msg.channel.send("Roles List:\n" + data) | ||||||
|   } else if (msg.content === "!channels") { |   } else if (msg.content === '!channels') { | ||||||
|     const col = await msg.guild?.channels.array() |     const col = await msg.guild?.channels.array() | ||||||
|     const data = col?.map((c: GuildChannel, i: number) => { |     const data = col?.map((c: GuildChannel, i: number) => { | ||||||
|       return `${i + 1}. ${c.name}` |       return `${i + 1}. ${c.name}` | ||||||
|     }).join("\n") as string |     }).join("\n") as string | ||||||
|     msg.channel.send("Channels List:\n" + data) |     msg.channel.send('Channels List:\n' + data) | ||||||
|   } |   } | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| bot.connect(TOKEN, [ | client.connect(TOKEN, Intents.None) | ||||||
|   GatewayIntents.GUILD_MEMBERS, |  | ||||||
|   GatewayIntents.GUILD_PRESENCES, |  | ||||||
|   GatewayIntents.GUILD_MESSAGES, |  | ||||||
|   GatewayIntents.DIRECT_MESSAGES, |  | ||||||
|   GatewayIntents.DIRECT_MESSAGE_REACTIONS, |  | ||||||
|   GatewayIntents.DIRECT_MESSAGE_TYPING, |  | ||||||
|   GatewayIntents.GUILDS, |  | ||||||
|   GatewayIntents.GUILD_BANS, |  | ||||||
|   GatewayIntents.GUILD_EMOJIS, |  | ||||||
|   GatewayIntents.GUILD_INTEGRATIONS, |  | ||||||
|   GatewayIntents.GUILD_INVITES, |  | ||||||
|   GatewayIntents.GUILD_MESSAGE_REACTIONS, |  | ||||||
|   GatewayIntents.GUILD_MESSAGE_TYPING, |  | ||||||
|   GatewayIntents.GUILD_VOICE_STATES, |  | ||||||
|   GatewayIntents.GUILD_WEBHOOKS |  | ||||||
| ]) |  | ||||||
|  |  | ||||||
							
								
								
									
										40
									
								
								src/utils/buildInfo.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/utils/buildInfo.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,40 @@ | ||||||
|  | /* eslint-disable @typescript-eslint/naming-convention */ | ||||||
|  | import { Client } from "../models/client.ts"; | ||||||
|  | 
 | ||||||
|  | export const getBuildInfo = (client: Client): { | ||||||
|  |     os: string | ||||||
|  |     os_version: string | ||||||
|  |     browser: string | ||||||
|  |     browser_version: string | ||||||
|  |     browser_user_agent: string | ||||||
|  |     client_build_number: number | ||||||
|  |     client_event_source: null | ||||||
|  |     release_channel: string | ||||||
|  | } => { | ||||||
|  |     const os = 'Windows' | ||||||
|  |     const os_version = '10' | ||||||
|  |     let client_build_number = 71073 | ||||||
|  |     const client_event_source = null | ||||||
|  |     let release_channel = 'stable' | ||||||
|  |     if (client.canary === true) { | ||||||
|  |         release_channel = 'canary' | ||||||
|  |         client_build_number = 71076 | ||||||
|  |     } | ||||||
|  |     const browser = 'Firefox' | ||||||
|  |     const browser_version = '83.0' | ||||||
|  |     const browser_user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 ' + browser + '/' + browser_version | ||||||
|  |     // TODO: Use current OS properties, but also browser_user_agent accordingly
 | ||||||
|  |     // if (Deno.build.os === 'darwin') os = 'MacOS'
 | ||||||
|  |     // else if (Deno.build.os === 'linux') os = 'Ubuntu'
 | ||||||
|  | 
 | ||||||
|  |     return { | ||||||
|  |         os, | ||||||
|  |         os_version, | ||||||
|  |         browser, | ||||||
|  |         browser_version, | ||||||
|  |         browser_user_agent, | ||||||
|  |         client_build_number, | ||||||
|  |         client_event_source, | ||||||
|  |         release_channel, | ||||||
|  |     } | ||||||
|  | }; | ||||||
							
								
								
									
										72
									
								
								src/utils/intents.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/utils/intents.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,72 @@ | ||||||
|  | import { GatewayIntents } from "../types/gateway.ts"; | ||||||
|  | 
 | ||||||
|  | // eslint-disable-next-line @typescript-eslint/no-extraneous-class
 | ||||||
|  | export class Intents { | ||||||
|  |   static All: number[] = [ | ||||||
|  |     GatewayIntents.GUILD_MEMBERS, | ||||||
|  |     GatewayIntents.GUILD_PRESENCES, | ||||||
|  |     GatewayIntents.GUILD_MESSAGES, | ||||||
|  |     GatewayIntents.DIRECT_MESSAGES, | ||||||
|  |     GatewayIntents.DIRECT_MESSAGE_REACTIONS, | ||||||
|  |     GatewayIntents.DIRECT_MESSAGE_TYPING, | ||||||
|  |     GatewayIntents.GUILDS, | ||||||
|  |     GatewayIntents.GUILD_BANS, | ||||||
|  |     GatewayIntents.GUILD_EMOJIS, | ||||||
|  |     GatewayIntents.GUILD_INTEGRATIONS, | ||||||
|  |     GatewayIntents.GUILD_INVITES, | ||||||
|  |     GatewayIntents.GUILD_MESSAGE_REACTIONS, | ||||||
|  |     GatewayIntents.GUILD_MESSAGE_TYPING, | ||||||
|  |     GatewayIntents.GUILD_VOICE_STATES, | ||||||
|  |     GatewayIntents.GUILD_WEBHOOKS | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   static Presence: number[] = [ | ||||||
|  |     GatewayIntents.GUILD_PRESENCES, | ||||||
|  |     GatewayIntents.GUILD_MESSAGES, | ||||||
|  |     GatewayIntents.DIRECT_MESSAGES, | ||||||
|  |     GatewayIntents.DIRECT_MESSAGE_REACTIONS, | ||||||
|  |     GatewayIntents.DIRECT_MESSAGE_TYPING, | ||||||
|  |     GatewayIntents.GUILDS, | ||||||
|  |     GatewayIntents.GUILD_BANS, | ||||||
|  |     GatewayIntents.GUILD_EMOJIS, | ||||||
|  |     GatewayIntents.GUILD_INTEGRATIONS, | ||||||
|  |     GatewayIntents.GUILD_INVITES, | ||||||
|  |     GatewayIntents.GUILD_MESSAGE_REACTIONS, | ||||||
|  |     GatewayIntents.GUILD_MESSAGE_TYPING, | ||||||
|  |     GatewayIntents.GUILD_VOICE_STATES, | ||||||
|  |     GatewayIntents.GUILD_WEBHOOKS | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   static GuildMembers: number[] = [ | ||||||
|  |     GatewayIntents.GUILD_MEMBERS, | ||||||
|  |     GatewayIntents.GUILD_MESSAGES, | ||||||
|  |     GatewayIntents.DIRECT_MESSAGES, | ||||||
|  |     GatewayIntents.DIRECT_MESSAGE_REACTIONS, | ||||||
|  |     GatewayIntents.DIRECT_MESSAGE_TYPING, | ||||||
|  |     GatewayIntents.GUILDS, | ||||||
|  |     GatewayIntents.GUILD_BANS, | ||||||
|  |     GatewayIntents.GUILD_EMOJIS, | ||||||
|  |     GatewayIntents.GUILD_INTEGRATIONS, | ||||||
|  |     GatewayIntents.GUILD_INVITES, | ||||||
|  |     GatewayIntents.GUILD_MESSAGE_REACTIONS, | ||||||
|  |     GatewayIntents.GUILD_MESSAGE_TYPING, | ||||||
|  |     GatewayIntents.GUILD_VOICE_STATES, | ||||||
|  |     GatewayIntents.GUILD_WEBHOOKS | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   static None: number[] = [ | ||||||
|  |     GatewayIntents.GUILD_MESSAGES, | ||||||
|  |     GatewayIntents.DIRECT_MESSAGES, | ||||||
|  |     GatewayIntents.DIRECT_MESSAGE_REACTIONS, | ||||||
|  |     GatewayIntents.DIRECT_MESSAGE_TYPING, | ||||||
|  |     GatewayIntents.GUILDS, | ||||||
|  |     GatewayIntents.GUILD_BANS, | ||||||
|  |     GatewayIntents.GUILD_EMOJIS, | ||||||
|  |     GatewayIntents.GUILD_INTEGRATIONS, | ||||||
|  |     GatewayIntents.GUILD_INVITES, | ||||||
|  |     GatewayIntents.GUILD_MESSAGE_REACTIONS, | ||||||
|  |     GatewayIntents.GUILD_MESSAGE_TYPING, | ||||||
|  |     GatewayIntents.GUILD_VOICE_STATES, | ||||||
|  |     GatewayIntents.GUILD_WEBHOOKS | ||||||
|  |   ] | ||||||
|  | } | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue