Merge pull request #66 from DjDeveloperr/slash
SlashClient & RESTManager can run alone and added APIMap
This commit is contained in:
		
						commit
						3695b81de6
					
				
					 6 changed files with 192 additions and 43 deletions
				
			
		|  | @ -18,6 +18,7 @@ import { GatewayCache } from '../managers/gatewayCache.ts' | ||||||
| import { delay } from '../utils/delay.ts' | import { delay } from '../utils/delay.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 EventEmitter from 'https://deno.land/std@0.74.0/node/events.ts' | ||||||
| 
 | 
 | ||||||
| export interface RequestMembersOptions { | export interface RequestMembersOptions { | ||||||
|   limit?: number |   limit?: number | ||||||
|  | @ -34,11 +35,11 @@ export interface VoiceStateOptions { | ||||||
| export const RECONNECT_REASON = 'harmony-reconnect' | export const RECONNECT_REASON = 'harmony-reconnect' | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Handles Discord gateway connection. |  * Handles Discord Gateway connection. | ||||||
|  * |  * | ||||||
|  * You should not use this and rather use Client class. |  * You should not use this and rather use Client class. | ||||||
|  */ |  */ | ||||||
| class Gateway { | export class Gateway extends EventEmitter { | ||||||
|   websocket: WebSocket |   websocket: WebSocket | ||||||
|   token: string |   token: string | ||||||
|   intents: GatewayIntents[] |   intents: GatewayIntents[] | ||||||
|  | @ -55,6 +56,7 @@ class Gateway { | ||||||
|   private timedIdentify: number | null = null |   private timedIdentify: number | null = null | ||||||
| 
 | 
 | ||||||
|   constructor(client: Client, token: string, intents: GatewayIntents[]) { |   constructor(client: Client, token: string, intents: GatewayIntents[]) { | ||||||
|  |     super() | ||||||
|     this.token = token |     this.token = token | ||||||
|     this.intents = intents |     this.intents = intents | ||||||
|     this.client = client |     this.client = client | ||||||
|  | @ -74,6 +76,7 @@ class Gateway { | ||||||
|   private onopen(): void { |   private onopen(): void { | ||||||
|     this.connected = true |     this.connected = true | ||||||
|     this.debug('Connected to Gateway!') |     this.debug('Connected to Gateway!') | ||||||
|  |     this.emit('connect') | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private async onmessage(event: MessageEvent): Promise<void> { |   private async onmessage(event: MessageEvent): Promise<void> { | ||||||
|  | @ -112,6 +115,7 @@ class Gateway { | ||||||
|       case GatewayOpcodes.HEARTBEAT_ACK: |       case GatewayOpcodes.HEARTBEAT_ACK: | ||||||
|         this.heartbeatServerResponded = true |         this.heartbeatServerResponded = true | ||||||
|         this.client.ping = Date.now() - this.lastPingTimestamp |         this.client.ping = Date.now() - this.lastPingTimestamp | ||||||
|  |         this.emit('ping', this.client.ping) | ||||||
|         this.debug( |         this.debug( | ||||||
|           `Received Heartbeat Ack. Ping Recognized: ${this.client.ping}ms` |           `Received Heartbeat Ack. Ping Recognized: ${this.client.ping}ms` | ||||||
|         ) |         ) | ||||||
|  | @ -142,6 +146,7 @@ class Gateway { | ||||||
|           await this.cache.set('seq', s) |           await this.cache.set('seq', s) | ||||||
|         } |         } | ||||||
|         if (t !== null && t !== undefined) { |         if (t !== null && t !== undefined) { | ||||||
|  |           this.emit(t, d) | ||||||
|           this.client.emit('raw', t, d) |           this.client.emit('raw', t, d) | ||||||
| 
 | 
 | ||||||
|           const handler = gatewayHandlers[t] |           const handler = gatewayHandlers[t] | ||||||
|  | @ -158,9 +163,11 @@ class Gateway { | ||||||
|         this.sequenceID = d.seq |         this.sequenceID = d.seq | ||||||
|         await this.cache.set('seq', d.seq) |         await this.cache.set('seq', d.seq) | ||||||
|         await this.cache.set('session_id', this.sessionID) |         await this.cache.set('session_id', this.sessionID) | ||||||
|  |         this.emit('resume') | ||||||
|         break |         break | ||||||
|       } |       } | ||||||
|       case GatewayOpcodes.RECONNECT: { |       case GatewayOpcodes.RECONNECT: { | ||||||
|  |         this.emit('reconnectRequired') | ||||||
|         // eslint-disable-next-line @typescript-eslint/no-floating-promises
 |         // eslint-disable-next-line @typescript-eslint/no-floating-promises
 | ||||||
|         this.reconnect() |         this.reconnect() | ||||||
|         break |         break | ||||||
|  | @ -172,6 +179,7 @@ class Gateway { | ||||||
| 
 | 
 | ||||||
|   private async onclose(event: CloseEvent): Promise<void> { |   private async onclose(event: CloseEvent): Promise<void> { | ||||||
|     if (event.reason === RECONNECT_REASON) return |     if (event.reason === RECONNECT_REASON) return | ||||||
|  |     this.emit('close', event.code, event.reason) | ||||||
|     this.debug(`Connection Closed with code: ${event.code}`) |     this.debug(`Connection Closed with code: ${event.code}`) | ||||||
| 
 | 
 | ||||||
|     if (event.code === GatewayCloseCodes.UNKNOWN_ERROR) { |     if (event.code === GatewayCloseCodes.UNKNOWN_ERROR) { | ||||||
|  | @ -223,7 +231,7 @@ class Gateway { | ||||||
| 
 | 
 | ||||||
|   private onerror(event: Event | ErrorEvent): void { |   private onerror(event: Event | ErrorEvent): void { | ||||||
|     const eventError = event as ErrorEvent |     const eventError = event as ErrorEvent | ||||||
|     console.log(eventError) |     this.emit('error', eventError) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private async sendIdentify(forceNewSession?: boolean): Promise<void> { |   private async sendIdentify(forceNewSession?: boolean): Promise<void> { | ||||||
|  | @ -266,6 +274,7 @@ class Gateway { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     this.debug('Sending Identify payload...') |     this.debug('Sending Identify payload...') | ||||||
|  |     this.emit('sentIdentify') | ||||||
|     this.send({ |     this.send({ | ||||||
|       op: GatewayOpcodes.IDENTIFY, |       op: GatewayOpcodes.IDENTIFY, | ||||||
|       d: payload |       d: payload | ||||||
|  | @ -291,6 +300,7 @@ class Gateway { | ||||||
|         seq: this.sequenceID ?? null |         seq: this.sequenceID ?? null | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |     this.emit('sentResume') | ||||||
|     this.debug('Sending Resume payload...') |     this.debug('Sending Resume payload...') | ||||||
|     this.send(resumePayload) |     this.send(resumePayload) | ||||||
|   } |   } | ||||||
|  | @ -341,6 +351,7 @@ class Gateway { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async reconnect(forceNew?: boolean): Promise<void> { |   async reconnect(forceNew?: boolean): Promise<void> { | ||||||
|  |     this.emit('reconnecting') | ||||||
|     clearInterval(this.heartbeatIntervalID) |     clearInterval(this.heartbeatIntervalID) | ||||||
|     if (forceNew === true) { |     if (forceNew === true) { | ||||||
|       await this.cache.delete('session_id') |       await this.cache.delete('session_id') | ||||||
|  | @ -351,6 +362,7 @@ class Gateway { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   initWebsocket(): void { |   initWebsocket(): void { | ||||||
|  |     this.emit('init') | ||||||
|     this.debug('Initializing WebSocket...') |     this.debug('Initializing WebSocket...') | ||||||
|     this.websocket = new WebSocket( |     this.websocket = new WebSocket( | ||||||
|       // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
 |       // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
 | ||||||
|  | @ -414,5 +426,3 @@ class Gateway { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export type GatewayEventHandler = (gateway: Gateway, d: any) => void | export type GatewayEventHandler = (gateway: Gateway, d: any) => void | ||||||
| 
 |  | ||||||
| export { Gateway } |  | ||||||
|  |  | ||||||
|  | @ -16,6 +16,7 @@ import { SlashClient } from './slashClient.ts' | ||||||
| import { Interaction } from '../structures/slash.ts' | import { Interaction } from '../structures/slash.ts' | ||||||
| import { SlashModule } from './slashModule.ts' | import { SlashModule } from './slashModule.ts' | ||||||
| import type { ShardManager } from './shard.ts' | import type { ShardManager } from './shard.ts' | ||||||
|  | import { Application } from '../structures/application.ts' | ||||||
| 
 | 
 | ||||||
| /** OS related properties sent with Gateway Identify */ | /** OS related properties sent with Gateway Identify */ | ||||||
| export interface ClientProperties { | export interface ClientProperties { | ||||||
|  | @ -26,6 +27,8 @@ export interface ClientProperties { | ||||||
| 
 | 
 | ||||||
| /** Some Client Options to modify behaviour */ | /** Some Client Options to modify behaviour */ | ||||||
| export interface ClientOptions { | export interface ClientOptions { | ||||||
|  |   /** ID of the Client/Application to initialize Slash Client REST */ | ||||||
|  |   id?: string | ||||||
|   /** Token of the Bot/User */ |   /** Token of the Bot/User */ | ||||||
|   token?: string |   token?: string | ||||||
|   /** Gateway Intents */ |   /** Gateway Intents */ | ||||||
|  | @ -100,6 +103,7 @@ export class Client extends EventEmitter { | ||||||
|   }> |   }> | ||||||
| 
 | 
 | ||||||
|   _decoratedSlashModules?: SlashModule[] |   _decoratedSlashModules?: SlashModule[] | ||||||
|  |   _id?: string | ||||||
| 
 | 
 | ||||||
|   private readonly _untypedOn = this.on |   private readonly _untypedOn = this.on | ||||||
| 
 | 
 | ||||||
|  | @ -120,6 +124,7 @@ export class Client extends EventEmitter { | ||||||
| 
 | 
 | ||||||
|   constructor(options: ClientOptions = {}) { |   constructor(options: ClientOptions = {}) { | ||||||
|     super() |     super() | ||||||
|  |     this._id = options.id | ||||||
|     this.token = options.token |     this.token = options.token | ||||||
|     this.intents = options.intents |     this.intents = options.intents | ||||||
|     this.forceNewSession = options.forceNewSession |     this.forceNewSession = options.forceNewSession | ||||||
|  | @ -156,7 +161,9 @@ export class Client extends EventEmitter { | ||||||
|           } |           } | ||||||
|         : options.clientProperties |         : options.clientProperties | ||||||
| 
 | 
 | ||||||
|     this.slash = new SlashClient(this, { |     this.slash = new SlashClient({ | ||||||
|  |       id: () => this.getEstimatedID(), | ||||||
|  |       client: this, | ||||||
|       enabled: options.enableSlash |       enabled: options.enableSlash | ||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
|  | @ -185,8 +192,24 @@ export class Client extends EventEmitter { | ||||||
|     this.emit('debug', `[${tag}] ${msg}`) |     this.emit('debug', `[${tag}] ${msg}`) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // TODO(DjDeveloperr): Implement this
 |   getEstimatedID(): string { | ||||||
|   // fetchApplication(): Promise<Application>
 |     if (this.user !== undefined) return this.user.id | ||||||
|  |     else if (this.token !== undefined) { | ||||||
|  |       try { | ||||||
|  |         return atob(this.token.split('.')[0]) | ||||||
|  |       } catch (e) { | ||||||
|  |         return this._id ?? 'unknown' | ||||||
|  |       } | ||||||
|  |     } else { | ||||||
|  |       return this._id ?? 'unknown' | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Fetch Application of the Client */ | ||||||
|  |   async fetchApplication(): Promise<Application> { | ||||||
|  |     const app = await this.rest.api.oauth2.applications['@me'].get() | ||||||
|  |     return new Application(this, app) | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * This function is used for connecting to discord. |    * This function is used for connecting to discord. | ||||||
|  |  | ||||||
|  | @ -1,5 +1,4 @@ | ||||||
| import * as baseEndpoints from '../consts/urlsAndVersions.ts' | import * as baseEndpoints from '../consts/urlsAndVersions.ts' | ||||||
| import { Client } from './client.ts' |  | ||||||
| import { Collection } from '../utils/collection.ts' | import { Collection } from '../utils/collection.ts' | ||||||
| 
 | 
 | ||||||
| export type RequestMethods = | export type RequestMethods = | ||||||
|  | @ -51,15 +50,67 @@ export interface RateLimit { | ||||||
|   bucket: string | null |   bucket: string | null | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | const METHODS = ['get', 'post', 'patch', 'put', 'delete', 'head'] | ||||||
|  | 
 | ||||||
|  | export type MethodFunction = ( | ||||||
|  |   body?: unknown, | ||||||
|  |   maxRetries?: number, | ||||||
|  |   bucket?: string | null, | ||||||
|  |   rawResponse?: boolean | ||||||
|  | ) => Promise<any> | ||||||
|  | 
 | ||||||
|  | export interface APIMap extends MethodFunction { | ||||||
|  |   get: APIMap | ||||||
|  |   post: APIMap | ||||||
|  |   patch: APIMap | ||||||
|  |   put: APIMap | ||||||
|  |   delete: APIMap | ||||||
|  |   head: APIMap | ||||||
|  |   [name: string]: APIMap | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export const builder = (rest: RESTManager, acum = '/'): APIMap => { | ||||||
|  |   const routes = {} | ||||||
|  |   const proxy = new Proxy(routes, { | ||||||
|  |     get: (_, p, __) => { | ||||||
|  |       if (p === 'toString') return () => acum | ||||||
|  |       if (METHODS.includes(String(p))) { | ||||||
|  |         const method = ((rest as unknown) as { | ||||||
|  |           [name: string]: MethodFunction | ||||||
|  |         })[String(p)] | ||||||
|  |         return async (...args: any[]) => | ||||||
|  |           await method.bind(rest)( | ||||||
|  |             `${baseEndpoints.DISCORD_API_URL}/v${rest.version}${acum.substring( | ||||||
|  |               0, | ||||||
|  |               acum.length - 1 | ||||||
|  |             )}`,
 | ||||||
|  |             ...args | ||||||
|  |           ) | ||||||
|  |       } | ||||||
|  |       return builder(rest, acum + String(p) + '/') | ||||||
|  |     } | ||||||
|  |   }) | ||||||
|  |   return (proxy as unknown) as APIMap | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export interface RESTOptions { | ||||||
|  |   token?: string | ||||||
|  |   headers?: { [name: string]: string | undefined } | ||||||
|  |   canary?: boolean | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export class RESTManager { | export class RESTManager { | ||||||
|   client?: Client |   client?: RESTOptions | ||||||
|   queues: { [key: string]: QueuedItem[] } = {} |   queues: { [key: string]: QueuedItem[] } = {} | ||||||
|   rateLimits = new Collection<string, RateLimit>() |   rateLimits = new Collection<string, RateLimit>() | ||||||
|   globalRateLimit: boolean = false |   globalRateLimit: boolean = false | ||||||
|   processing: boolean = false |   processing: boolean = false | ||||||
|  |   version: number = 8 | ||||||
|  |   api: APIMap | ||||||
| 
 | 
 | ||||||
|   constructor(client?: Client) { |   constructor(client?: RESTOptions) { | ||||||
|     this.client = client |     this.client = client | ||||||
|  |     this.api = builder(this) | ||||||
|     // eslint-disable-next-line @typescript-eslint/no-floating-promises
 |     // eslint-disable-next-line @typescript-eslint/no-floating-promises
 | ||||||
|     this.handleRateLimits() |     this.handleRateLimits() | ||||||
|   } |   } | ||||||
|  | @ -160,10 +211,16 @@ export class RESTManager { | ||||||
|       form.append('file', body.file.blob, body.file.name) |       form.append('file', body.file.blob, body.file.name) | ||||||
|       form.append('payload_json', JSON.stringify({ ...body, file: undefined })) |       form.append('payload_json', JSON.stringify({ ...body, file: undefined })) | ||||||
|       body.file = form |       body.file = form | ||||||
|     } else if (body !== undefined && !['get', 'delete'].includes(method)) { |     } else if ( | ||||||
|  |       body !== undefined && | ||||||
|  |       !['get', 'delete'].includes(method.toLowerCase()) | ||||||
|  |     ) { | ||||||
|       headers['Content-Type'] = 'application/json' |       headers['Content-Type'] = 'application/json' | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     if (this.client?.headers !== undefined) | ||||||
|  |       Object.assign(headers, this.client.headers) | ||||||
|  | 
 | ||||||
|     const data: { [name: string]: any } = { |     const data: { [name: string]: any } = { | ||||||
|       headers, |       headers, | ||||||
|       body: body?.file ?? JSON.stringify(body), |       body: body?.file ?? JSON.stringify(body), | ||||||
|  |  | ||||||
|  | @ -14,10 +14,7 @@ import { | ||||||
| } from '../types/slash.ts' | } from '../types/slash.ts' | ||||||
| import { Collection } from '../utils/collection.ts' | import { Collection } from '../utils/collection.ts' | ||||||
| import { Client } from './client.ts' | import { Client } from './client.ts' | ||||||
| 
 | import { RESTManager } from './rest.ts' | ||||||
| export interface SlashOptions { |  | ||||||
|   enabled?: boolean |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| export class SlashCommand { | export class SlashCommand { | ||||||
|   slash: SlashCommandsManager |   slash: SlashCommandsManager | ||||||
|  | @ -47,20 +44,22 @@ export class SlashCommand { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export class SlashCommandsManager { | export class SlashCommandsManager { | ||||||
|   client: Client |  | ||||||
|   slash: SlashClient |   slash: SlashClient | ||||||
| 
 | 
 | ||||||
|   constructor(client: Client) { |   get rest(): RESTManager { | ||||||
|     this.client = client |     return this.slash.rest | ||||||
|     this.slash = client.slash |   } | ||||||
|  | 
 | ||||||
|  |   constructor(client: SlashClient) { | ||||||
|  |     this.slash = client | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** Get all Global Slash Commands */ |   /** Get all Global Slash Commands */ | ||||||
|   async all(): Promise<Collection<string, SlashCommand>> { |   async all(): Promise<Collection<string, SlashCommand>> { | ||||||
|     const col = new Collection<string, SlashCommand>() |     const col = new Collection<string, SlashCommand>() | ||||||
| 
 | 
 | ||||||
|     const res = (await this.client.rest.get( |     const res = (await this.rest.get( | ||||||
|       APPLICATION_COMMANDS(this.client.user?.id as string) |       APPLICATION_COMMANDS(this.slash.getID()) | ||||||
|     )) as SlashCommandPayload[] |     )) as SlashCommandPayload[] | ||||||
|     if (!Array.isArray(res)) return col |     if (!Array.isArray(res)) return col | ||||||
| 
 | 
 | ||||||
|  | @ -78,9 +77,9 @@ export class SlashCommandsManager { | ||||||
|   ): Promise<Collection<string, SlashCommand>> { |   ): Promise<Collection<string, SlashCommand>> { | ||||||
|     const col = new Collection<string, SlashCommand>() |     const col = new Collection<string, SlashCommand>() | ||||||
| 
 | 
 | ||||||
|     const res = (await this.client.rest.get( |     const res = (await this.rest.get( | ||||||
|       APPLICATION_GUILD_COMMANDS( |       APPLICATION_GUILD_COMMANDS( | ||||||
|         this.client.user?.id as string, |         this.slash.getID(), | ||||||
|         typeof guild === 'string' ? guild : guild.id |         typeof guild === 'string' ? guild : guild.id | ||||||
|       ) |       ) | ||||||
|     )) as SlashCommandPayload[] |     )) as SlashCommandPayload[] | ||||||
|  | @ -100,11 +99,11 @@ export class SlashCommandsManager { | ||||||
|     data: SlashCommandPartial, |     data: SlashCommandPartial, | ||||||
|     guild?: Guild | string |     guild?: Guild | string | ||||||
|   ): Promise<SlashCommand> { |   ): Promise<SlashCommand> { | ||||||
|     const payload = await this.client.rest.post( |     const payload = await this.rest.post( | ||||||
|       guild === undefined |       guild === undefined | ||||||
|         ? APPLICATION_COMMANDS(this.client.user?.id as string) |         ? APPLICATION_COMMANDS(this.slash.getID()) | ||||||
|         : APPLICATION_GUILD_COMMANDS( |         : APPLICATION_GUILD_COMMANDS( | ||||||
|             this.client.user?.id as string, |             this.slash.getID(), | ||||||
|             typeof guild === 'string' ? guild : guild.id |             typeof guild === 'string' ? guild : guild.id | ||||||
|           ), |           ), | ||||||
|       data |       data | ||||||
|  | @ -123,11 +122,11 @@ export class SlashCommandsManager { | ||||||
|     data: SlashCommandPartial, |     data: SlashCommandPartial, | ||||||
|     guild?: Guild | string |     guild?: Guild | string | ||||||
|   ): Promise<SlashCommandsManager> { |   ): Promise<SlashCommandsManager> { | ||||||
|     await this.client.rest.patch( |     await this.rest.patch( | ||||||
|       guild === undefined |       guild === undefined | ||||||
|         ? APPLICATION_COMMAND(this.client.user?.id as string, id) |         ? APPLICATION_COMMAND(this.slash.getID(), id) | ||||||
|         : APPLICATION_GUILD_COMMAND( |         : APPLICATION_GUILD_COMMAND( | ||||||
|             this.client.user?.id as string, |             this.slash.getID(), | ||||||
|             typeof guild === 'string' ? guild : guild.id, |             typeof guild === 'string' ? guild : guild.id, | ||||||
|             id |             id | ||||||
|           ), |           ), | ||||||
|  | @ -141,17 +140,31 @@ export class SlashCommandsManager { | ||||||
|     id: string, |     id: string, | ||||||
|     guild?: Guild | string |     guild?: Guild | string | ||||||
|   ): Promise<SlashCommandsManager> { |   ): Promise<SlashCommandsManager> { | ||||||
|     await this.client.rest.delete( |     await this.rest.delete( | ||||||
|       guild === undefined |       guild === undefined | ||||||
|         ? APPLICATION_COMMAND(this.client.user?.id as string, id) |         ? APPLICATION_COMMAND(this.slash.getID(), id) | ||||||
|         : APPLICATION_GUILD_COMMAND( |         : APPLICATION_GUILD_COMMAND( | ||||||
|             this.client.user?.id as string, |             this.slash.getID(), | ||||||
|             typeof guild === 'string' ? guild : guild.id, |             typeof guild === 'string' ? guild : guild.id, | ||||||
|             id |             id | ||||||
|           ) |           ) | ||||||
|     ) |     ) | ||||||
|     return this |     return this | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   /** Get a Slash Command (global or Guild) */ | ||||||
|  |   async get(id: string, guild?: Guild | string): Promise<SlashCommand> { | ||||||
|  |     const data = await this.rest.get( | ||||||
|  |       guild === undefined | ||||||
|  |         ? APPLICATION_COMMAND(this.slash.getID(), id) | ||||||
|  |         : APPLICATION_GUILD_COMMAND( | ||||||
|  |             this.slash.getID(), | ||||||
|  |             typeof guild === 'string' ? guild : guild.id, | ||||||
|  |             id | ||||||
|  |           ) | ||||||
|  |     ) | ||||||
|  |     return new SlashCommand(this, data) | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export type SlashCommandHandlerCallback = (interaction: Interaction) => any | export type SlashCommandHandlerCallback = (interaction: Interaction) => any | ||||||
|  | @ -163,31 +176,61 @@ export interface SlashCommandHandler { | ||||||
|   handler: SlashCommandHandlerCallback |   handler: SlashCommandHandlerCallback | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | export interface SlashOptions { | ||||||
|  |   id?: string | (() => string) | ||||||
|  |   client?: Client | ||||||
|  |   enabled?: boolean | ||||||
|  |   token?: string | ||||||
|  |   rest?: RESTManager | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export class SlashClient { | export class SlashClient { | ||||||
|   client: Client |   id: string | (() => string) | ||||||
|  |   client?: Client | ||||||
|  |   token?: string | ||||||
|   enabled: boolean = true |   enabled: boolean = true | ||||||
|   commands: SlashCommandsManager |   commands: SlashCommandsManager | ||||||
|   handlers: SlashCommandHandler[] = [] |   handlers: SlashCommandHandler[] = [] | ||||||
|  |   rest: RESTManager | ||||||
| 
 | 
 | ||||||
|   constructor(client: Client, options?: SlashOptions) { |   constructor(options: SlashOptions) { | ||||||
|     this.client = client |     let id = options.id | ||||||
|     this.commands = new SlashCommandsManager(client) |     if (options.token !== undefined) id = atob(options.token?.split('.')[0]) | ||||||
|  |     if (id === undefined) | ||||||
|  |       throw new Error('ID could not be found. Pass at least client or token') | ||||||
|  |     this.id = id | ||||||
|  |     this.client = options.client | ||||||
|  |     this.token = options.token | ||||||
|  |     this.commands = new SlashCommandsManager(this) | ||||||
| 
 | 
 | ||||||
|     if (options !== undefined) { |     if (options !== undefined) { | ||||||
|       this.enabled = options.enabled ?? true |       this.enabled = options.enabled ?? true | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (this.client._decoratedSlash !== undefined) { |     if (this.client?._decoratedSlash !== undefined) { | ||||||
|       this.client._decoratedSlash.forEach((e) => { |       this.client._decoratedSlash.forEach((e) => { | ||||||
|         this.handlers.push(e) |         this.handlers.push(e) | ||||||
|       }) |       }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     this.client.on('interactionCreate', (interaction) => |     this.rest = | ||||||
|  |       options.client === undefined | ||||||
|  |         ? options.rest === undefined | ||||||
|  |           ? new RESTManager({ | ||||||
|  |               token: this.token | ||||||
|  |             }) | ||||||
|  |           : options.rest | ||||||
|  |         : options.client.rest | ||||||
|  | 
 | ||||||
|  |     this.client?.on('interactionCreate', (interaction) => | ||||||
|       this._process(interaction) |       this._process(interaction) | ||||||
|     ) |     ) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   getID(): string { | ||||||
|  |     return typeof this.id === 'string' ? this.id : this.id() | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   /** Adds a new Slash Command Handler */ |   /** Adds a new Slash Command Handler */ | ||||||
|   handle(handler: SlashCommandHandler): SlashClient { |   handle(handler: SlashCommandHandler): SlashClient { | ||||||
|     this.handlers.push(handler) |     this.handlers.push(handler) | ||||||
|  |  | ||||||
|  | @ -60,12 +60,12 @@ class MyClient extends CommandClient { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @subslash('cmd', 'sub-cmd-no-grp') |   @subslash('cmd', 'sub-cmd-no-grp') | ||||||
|   subCmdNoGrp(d: Interaction): void { |   subCmdNoGroup(d: Interaction): void { | ||||||
|     d.respond({ content: 'sub-cmd-no-group worked' }) |     d.respond({ content: 'sub-cmd-no-group worked' }) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @groupslash('cmd', 'sub-cmd-group', 'sub-cmd') |   @groupslash('cmd', 'sub-cmd-group', 'sub-cmd') | ||||||
|   subCmdGrp(d: Interaction): void { |   subCmdGroup(d: Interaction): void { | ||||||
|     d.respond({ content: 'sub-cmd-group worked' }) |     d.respond({ content: 'sub-cmd-group worked' }) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -74,14 +74,23 @@ class MyClient extends CommandClient { | ||||||
|     console.log(d.name) |     console.log(d.name) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   @event() | ||||||
|  |   raw(evt: string, d: any): void { | ||||||
|  |     if (!evt.startsWith('APPLICATION')) return | ||||||
|  |     console.log(evt, d) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   @event() |   @event() | ||||||
|   ready(): void { |   ready(): void { | ||||||
|     console.log(`Logged in as ${this.user?.tag}!`) |     console.log(`Logged in as ${this.user?.tag}!`) | ||||||
|     this.manager.init(this.user?.id as string) |     this.manager.init(this.user?.id as string) | ||||||
|  |     this.slash.commands.all().then(console.log) | ||||||
|  | 
 | ||||||
|  |     // this.rest.api.users['422957901716652033'].get().then(console.log)
 | ||||||
|     // client.slash.commands.create(
 |     // client.slash.commands.create(
 | ||||||
|     //   {
 |     //   {
 | ||||||
|     //     name: 'cmd',
 |     //     name: 'cmd',
 | ||||||
|     //     description: 'Parent command',
 |     //     description: 'Parent command!',
 | ||||||
|     //     options: [
 |     //     options: [
 | ||||||
|     //       {
 |     //       {
 | ||||||
|     //         name: 'sub-cmd-group',
 |     //         name: 'sub-cmd-group',
 | ||||||
|  | @ -121,6 +130,7 @@ class MyClient extends CommandClient { | ||||||
|     //   },
 |     //   },
 | ||||||
|     //   '783319033205751809'
 |     //   '783319033205751809'
 | ||||||
|     // )
 |     // )
 | ||||||
|  |     // client.slash.commands.delete('788719077329207296', '783319033205751809')
 | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -166,7 +176,7 @@ class VCExtension extends Extension { | ||||||
| 
 | 
 | ||||||
|     await player.play(track) |     await player.play(track) | ||||||
| 
 | 
 | ||||||
|     ctx.channel.send(`Now playing ${info.title}!`) |     ctx.channel.send(`Now playing ${info.title}!\nDebug Track: ${track}`) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @command() |   @command() | ||||||
|  |  | ||||||
							
								
								
									
										6
									
								
								src/test/slash-only.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/test/slash-only.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | ||||||
|  | import { SlashClient } from '../models/slashClient.ts' | ||||||
|  | import { TOKEN } from './config.ts' | ||||||
|  | 
 | ||||||
|  | const slash = new SlashClient({ token: TOKEN }) | ||||||
|  | 
 | ||||||
|  | slash.commands.all().then(console.log) | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue