diff --git a/src/gateway/handlers/guildCreate.ts b/src/gateway/handlers/guildCreate.ts index 4549834..1d90d74 100644 --- a/src/gateway/handlers/guildCreate.ts +++ b/src/gateway/handlers/guildCreate.ts @@ -27,6 +27,11 @@ export const guildCreate: GatewayEventHandler = async ( if (d.voice_states !== undefined) await guild.voiceStates.fromPayload(d.voice_states) + for (const emojiPayload of d.emojis) { + if (emojiPayload.id === null) continue + await gateway.client.emojis.set(emojiPayload.id, emojiPayload) + } + if (hasGuild === undefined) { // It wasn't lazy load, so emit event gateway.client.emit('guildCreate', guild) diff --git a/src/gateway/handlers/guildDelete.ts b/src/gateway/handlers/guildDelete.ts index 5685a70..f554f99 100644 --- a/src/gateway/handlers/guildDelete.ts +++ b/src/gateway/handlers/guildDelete.ts @@ -13,6 +13,7 @@ export const guildDelete: GatewayEventHandler = async ( await guild.channels.flush() await guild.roles.flush() await guild.presences.flush() + await guild.emojis.flush() await gateway.client.guilds._delete(d.id) gateway.client.emit('guildDelete', guild) diff --git a/src/models/rest.ts b/src/models/rest.ts index ad31f8c..054c425 100644 --- a/src/models/rest.ts +++ b/src/models/rest.ts @@ -3,6 +3,7 @@ import { Embed } from '../structures/embed.ts' import { MessageAttachment } from '../structures/message.ts' import { Collection } from '../utils/collection.ts' import { Client } from './client.ts' +import { simplifyAPIError } from '../utils/err_fmt.ts' export type RequestMethods = | 'get' @@ -44,9 +45,36 @@ export class DiscordAPIError extends Error { name = 'DiscordAPIError' error?: DiscordAPIErrorPayload - constructor(message?: string, error?: DiscordAPIErrorPayload) { - super(message) - this.error = error + constructor(error: string | DiscordAPIErrorPayload) { + super() + const err: any = typeof error === 'object' ? { ...error } : {} + delete err.url + delete err.status + delete err.message + + const fmt = Object.entries( + typeof error === 'object' ? simplifyAPIError(error.errors) : {} + ) + this.message = + typeof error === 'string' + ? error + : `\n${error.method} ${error.url.slice(7)} returned ${error.status}\n${ + error.message + }${ + fmt.length === 0 + ? '' + : fmt + .map( + (e) => + ` at ${e[0]}:\n${e[1] + .map((e) => ` - ${e}`) + .join('\n')}` + ) + .join('\n') + } ${Deno.inspect(err, { + depth: Infinity + })}` + if (typeof error === 'object') this.error = error } } @@ -451,44 +479,21 @@ export class RESTManager { new DiscordAPIError(`Request was Unauthorized. Invalid Token.\n${text}`) ) + const _data = { ...data } + if (_data?.headers !== undefined) delete _data.headers + if (_data?.method !== undefined) delete _data.method + // At this point we know it is error const error: DiscordAPIErrorPayload = { - url: response.url, + url: new URL(response.url).pathname, status, method: data.method, code: body?.code, message: body?.message, - errors: Object.fromEntries( - Object.entries( - (body?.errors as { - [name: string]: { - _errors: Array<{ code: string; message: string }> - } - }) ?? {} - ).map((entry) => { - return [entry[0], entry[1]._errors ?? []] - }) - ), - requestData: data + errors: body?.errors ?? {}, + requestData: _data } - // if (typeof error.errors === 'object') { - // const errors = error.errors as { - // [name: string]: { _errors: Array<{ code: string; message: string }> } - // } - // console.log(`%cREST Error:`, 'color: #F14C39;') - // Object.entries(errors).forEach((entry) => { - // console.log(` %c${entry[0]}:`, 'color: #12BC79;') - // entry[1]._errors.forEach((e) => { - // console.log( - // ` %c${e.code}: %c${e.message}`, - // 'color: skyblue;', - // 'color: #CECECE;' - // ) - // }) - // }) - // } - if ( [ HttpResponseCode.BadRequest, @@ -497,9 +502,9 @@ export class RESTManager { HttpResponseCode.MethodNotAllowed ].includes(status) ) { - reject(new DiscordAPIError(Deno.inspect(error), error)) + reject(new DiscordAPIError(error)) } else if (status === HttpResponseCode.GatewayUnavailable) { - reject(new DiscordAPIError(Deno.inspect(error), error)) + reject(new DiscordAPIError(error)) } else reject(new DiscordAPIError('Request - Unknown Error')) } diff --git a/src/structures/textChannel.ts b/src/structures/textChannel.ts index 7d89da2..5f05f8d 100644 --- a/src/structures/textChannel.ts +++ b/src/structures/textChannel.ts @@ -145,12 +145,15 @@ export class TextChannel extends Channel { emoji: Emoji | string ): Promise { if (emoji instanceof Emoji) { - emoji = emoji.getEmojiString + emoji = `${emoji.name}:${emoji.id}` + } else if (emoji.length > 4) { + if (!isNaN(Number(emoji))) { + const findEmoji = await this.client.emojis.get(emoji) + if (findEmoji !== undefined) emoji = `${findEmoji.name}:${findEmoji.id}` + else throw new Error(`Emoji not found: ${emoji}`) + } } - if (message instanceof Message) { - message = message.id - } - + if (message instanceof Message) message = message.id const encodedEmoji = encodeURI(emoji) await this.client.rest.put( @@ -165,11 +168,15 @@ export class TextChannel extends Channel { user?: User | Member | string ): Promise { if (emoji instanceof Emoji) { - emoji = emoji.getEmojiString - } - if (message instanceof Message) { - message = message.id + emoji = `${emoji.name}:${emoji.id}` + } else if (emoji.length > 4) { + if (!isNaN(Number(emoji))) { + const findEmoji = await this.client.emojis.get(emoji) + if (findEmoji !== undefined) emoji = `${findEmoji.name}:${findEmoji.id}` + else throw new Error(`Emoji not found: ${emoji}`) + } } + if (message instanceof Message) message = message.id if (user !== undefined) { if (typeof user !== 'string') { user = user.id diff --git a/src/test/index.ts b/src/test/index.ts index b635041..ea0ae6b 100644 --- a/src/test/index.ts +++ b/src/test/index.ts @@ -117,7 +117,8 @@ client.on('messageCreate', async (msg: Message) => { msg.channel.send('Failed...') } } else if (msg.content === '!react') { - msg.addReaction('🤔') + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + msg.addReaction('😂') } else if (msg.content === '!wait_for') { msg.channel.send('Send anything!') const [receivedMsg] = await client.waitFor( diff --git a/src/utils/err_fmt.ts b/src/utils/err_fmt.ts new file mode 100644 index 0000000..6639984 --- /dev/null +++ b/src/utils/err_fmt.ts @@ -0,0 +1,23 @@ +export interface SimplifiedError { + [name: string]: string[] +} + +export function simplifyAPIError(errors: any): SimplifiedError { + const res: SimplifiedError = {} + function fmt(obj: any, acum: string = ''): void { + if (typeof obj._errors === 'object' && Array.isArray(obj._errors)) + res[acum] = obj._errors.map((e: any) => `${e.code}: ${e.message}`) + else { + Object.entries(obj).forEach((obj: [string, any]) => { + const arrayIndex = !isNaN(Number(obj[0])) + if (arrayIndex) obj[0] = `[${obj[0]}]` + if (acum !== '' && !arrayIndex) acum += '.' + fmt(obj[1], (acum += obj[0])) + }) + } + } + Object.entries(errors).forEach((obj: [string, any]) => { + fmt(obj[1], obj[0]) + }) + return res +}