From 86f82715ca8fe5b608eb28b794ec8b46a0a25019 Mon Sep 17 00:00:00 2001 From: DjDeveloperr Date: Tue, 17 Nov 2020 08:46:32 +0530 Subject: [PATCH 1/2] feat(Message|TextChannel): inline replies --- src/structures/message.ts | 6 ++--- src/structures/textChannel.ts | 43 ++++++++++++++++++++++------------- src/types/channel.ts | 3 ++- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/structures/message.ts b/src/structures/message.ts index 0eaaa43..71c26ab 100644 --- a/src/structures/message.ts +++ b/src/structures/message.ts @@ -16,7 +16,6 @@ import { Embed } from './embed.ts' import { CHANNEL_MESSAGE } from '../types/endpoint.ts' import { MessageMentions } from './messageMentions.ts' import { TextChannel } from './textChannel.ts' -import { DMChannel } from './dmChannel.ts' import { Guild } from './guild.ts' type AllMessageOptions = MessageOption | Embed @@ -110,10 +109,9 @@ export class Message extends Base { return this.channel.editMessage(this.id, text, option) } + /** These will **not** work in all servers, as this feature is coming slowly. */ async reply(text?: string | AllMessageOptions, option?: AllMessageOptions): Promise { - // TODO: Use inline replies once they're out - if (this.channel instanceof DMChannel) return this.channel.send(text, option) - return this.channel.send(`${this.author.mention}, ${text}`, option) + return this.channel.send(text, Object.assign(option, { reply: this })) } async delete (): Promise { diff --git a/src/structures/textChannel.ts b/src/structures/textChannel.ts index b6eb107..44cb3e9 100644 --- a/src/structures/textChannel.ts +++ b/src/structures/textChannel.ts @@ -1,6 +1,6 @@ import { MessagesManager } from "../../mod.ts" import { Client } from '../models/client.ts' -import { GuildTextChannelPayload, MessageOption, Overwrite, TextChannelPayload } from '../types/channel.ts' +import { GuildTextChannelPayload, MessageOption, MessageReference, Overwrite, TextChannelPayload } from '../types/channel.ts' import { CHANNEL_MESSAGE, CHANNEL_MESSAGES } from '../types/endpoint.ts' import { Channel } from './channel.ts' import { Embed } from './embed.ts' @@ -14,20 +14,20 @@ export class TextChannel extends Channel { lastPinTimestamp?: string messages: MessagesManager - constructor (client: Client, data: TextChannelPayload) { + constructor(client: Client, data: TextChannelPayload) { super(client, data) this.messages = new MessagesManager(this.client, this) this.lastMessageID = data.last_message_id this.lastPinTimestamp = data.last_pin_timestamp } - protected readFromData (data: TextChannelPayload): void { + protected readFromData(data: TextChannelPayload): void { super.readFromData(data) this.lastMessageID = data.last_message_id ?? this.lastMessageID this.lastPinTimestamp = data.last_pin_timestamp ?? this.lastPinTimestamp } - async send (text?: string | AllMessageOptions, option?: AllMessageOptions): Promise { + async send(text?: string | AllMessageOptions, option?: AllMessageOptions): Promise { if (typeof text === "object") { option = text text = undefined @@ -38,21 +38,32 @@ export class TextChannel extends Channel { if (option instanceof Embed) option = { embed: option } - - const resp = await this.client.rest.post(CHANNEL_MESSAGES(this.id), { - content: text, - embed: option?.embed, - file: option?.file, - tts: option?.tts, - allowed_mentions: option?.allowedMention - }) + + const payload: any = { + content: text, + embed: option?.embed, + file: option?.file, + tts: option?.tts, + allowed_mentions: option?.allowedMention + } + + if (option?.reply !== undefined) { + const reference: MessageReference = { + message_id: option.reply.id, + channel_id: option.reply.channel.id, + guild_id: option.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 } - async editMessage ( + async editMessage( message: Message | string, text?: string, option?: MessageOption @@ -96,7 +107,7 @@ export class GuildTextChannel extends TextChannel { topic?: string guild: Guild - get mention (): string { + get mention(): string { return `<#${this.id}>` } @@ -104,7 +115,7 @@ export class GuildTextChannel extends TextChannel { return this.mention } - constructor (client: Client, data: GuildTextChannelPayload, guild: Guild) { + constructor(client: Client, data: GuildTextChannelPayload, guild: Guild) { super(client, data) this.guildID = data.guild_id this.name = data.name @@ -117,7 +128,7 @@ export class GuildTextChannel extends TextChannel { this.rateLimit = data.rate_limit_per_user } - protected readFromData (data: GuildTextChannelPayload): void { + protected readFromData(data: GuildTextChannelPayload): void { super.readFromData(data) this.guildID = data.guild_id ?? this.guildID this.name = data.name ?? this.name diff --git a/src/types/channel.ts b/src/types/channel.ts index 58ba24d..509ea94 100644 --- a/src/types/channel.ts +++ b/src/types/channel.ts @@ -106,7 +106,8 @@ export interface MessageOption { parse: ['everyone', 'users', 'roles'] roles: string[] users: string[] - } + }, + reply?: Message } export interface ChannelMention { From 25a5025802830d47ce4e4269e653436af3d18585 Mon Sep 17 00:00:00 2001 From: DjDeveloperr Date: Tue, 17 Nov 2020 09:05:25 +0530 Subject: [PATCH 2/2] fix(Message): Fix inline replies; feat(RESTManager): handle status codes correctly --- src/models/rest.ts | 15 +++++++++------ src/structures/message.ts | 2 +- src/structures/textChannel.ts | 10 +++++----- src/types/channel.ts | 3 +-- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/models/rest.ts b/src/models/rest.ts index 603b8ce..417d2fe 100644 --- a/src/models/rest.ts +++ b/src/models/rest.ts @@ -24,6 +24,10 @@ export interface RequestHeaders { [name: string]: string } +export class DiscordAPIError extends Error { + name = 'DiscordAPIError' +} + export interface QueuedItem { bucket?: string | null url: string @@ -263,7 +267,7 @@ export class RESTManager { if (text === 'undefined') text = undefined if (status === HttpResponseCode.Unauthorized) - throw new Error(`Request was not successful (Unauthorized). Invalid Token.\n${text}`) + throw new DiscordAPIError(`Request was not successful (Unauthorized). Invalid Token.\n${text}`) // At this point we know it is error let error = { url: response.url, status, method: data.method, body: data.body } @@ -275,10 +279,10 @@ export class RESTManager { HttpResponseCode.Forbidden, HttpResponseCode.MethodNotAllowed ].includes(status)) { - throw new Error(Deno.inspect(error)) + throw new DiscordAPIError(Deno.inspect(error)) } else if (status === HttpResponseCode.GatewayUnavailable) { - throw new Error(Deno.inspect(error)) - } else throw new Error('Request - Unknown Error') + throw new DiscordAPIError(Deno.inspect(error)) + } else throw new DiscordAPIError('Request - Unknown Error') } async make( @@ -327,8 +331,7 @@ export class RESTManager { if (response.status === 204) return resolve(undefined) const json: any = await response.json() - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.handleStatusCode(response, json, requestData) + await this.handleStatusCode(response, json, requestData) if ( json.retry_after !== undefined || diff --git a/src/structures/message.ts b/src/structures/message.ts index 71c26ab..95bbb40 100644 --- a/src/structures/message.ts +++ b/src/structures/message.ts @@ -111,7 +111,7 @@ export class Message extends Base { /** These will **not** work in all servers, as this feature is coming slowly. */ async reply(text?: string | AllMessageOptions, option?: AllMessageOptions): Promise { - return this.channel.send(text, Object.assign(option, { reply: this })) + return this.channel.send(text, option, this) } async delete (): Promise { diff --git a/src/structures/textChannel.ts b/src/structures/textChannel.ts index 44cb3e9..9ab87dd 100644 --- a/src/structures/textChannel.ts +++ b/src/structures/textChannel.ts @@ -27,7 +27,7 @@ export class TextChannel extends Channel { this.lastPinTimestamp = data.last_pin_timestamp ?? this.lastPinTimestamp } - async send(text?: string | AllMessageOptions, option?: AllMessageOptions): Promise { + async send(text?: string | AllMessageOptions, option?: AllMessageOptions, reply?: Message): Promise { if (typeof text === "object") { option = text text = undefined @@ -47,11 +47,11 @@ export class TextChannel extends Channel { allowed_mentions: option?.allowedMention } - if (option?.reply !== undefined) { + if (reply !== undefined) { const reference: MessageReference = { - message_id: option.reply.id, - channel_id: option.reply.channel.id, - guild_id: option.reply.guild?.id, + message_id: reply.id, + channel_id: reply.channel.id, + guild_id: reply.guild?.id, } payload.message_reference = reference } diff --git a/src/types/channel.ts b/src/types/channel.ts index 509ea94..58ba24d 100644 --- a/src/types/channel.ts +++ b/src/types/channel.ts @@ -106,8 +106,7 @@ export interface MessageOption { parse: ['everyone', 'users', 'roles'] roles: string[] users: string[] - }, - reply?: Message + } } export interface ChannelMention {