feat(Interactions): add InteractionWebhook for better internals (#5712)

This commit is contained in:
ckohen
2021-06-05 16:41:23 -07:00
committed by GitHub
parent 1d57754d46
commit dec191aa1e
9 changed files with 120 additions and 36 deletions

View File

@@ -24,6 +24,19 @@ class WebhookClient extends BaseClient {
this.id = id;
Object.defineProperty(this, 'token', { value: token, writable: true, configurable: true });
}
// These are here only for documentation purposes - they are implemented by Webhook
/* eslint-disable no-empty-function */
send() {}
sendSlackMessage() {}
fetchMessage() {}
edit() {}
editMessage() {}
delete() {}
deleteMessage() {}
get createdTimestamp() {}
get createdAt() {}
get url() {}
}
Webhook.applyToClass(WebhookClient);

View File

@@ -91,6 +91,7 @@ module.exports = {
Integration: require('./structures/Integration'),
IntegrationApplication: require('./structures/IntegrationApplication'),
Interaction: require('./structures/Interaction'),
InteractionWebhook: require('./structures/InteractionWebhook'),
Invite: require('./structures/Invite'),
Message: require('./structures/Message'),
MessageActionRow: require('./structures/MessageActionRow'),

View File

@@ -81,7 +81,8 @@ class APIMessage {
*/
get isInteraction() {
const Interaction = require('./Interaction');
return this.target instanceof Interaction;
const InteractionWebhook = require('./InteractionWebhook');
return this.target instanceof Interaction || this.target instanceof InteractionWebhook;
}
/**
@@ -372,10 +373,15 @@ class APIMessage {
*/
static create(target, content, options, extra = {}) {
const Interaction = require('./Interaction');
const InteractionWebhook = require('./InteractionWebhook');
const Webhook = require('./Webhook');
const WebhookClient = require('../client/WebhookClient');
const isWebhook = target instanceof Interaction || target instanceof Webhook || target instanceof WebhookClient;
const isWebhook =
target instanceof Interaction ||
target instanceof InteractionWebhook ||
target instanceof Webhook ||
target instanceof WebhookClient;
const transformed = this.transformOptions(content, options, extra, isWebhook);
return new this(target, transformed);
}
@@ -385,7 +391,7 @@ module.exports = APIMessage;
/**
* A target for a message.
* @typedef {TextChannel|DMChannel|User|GuildMember|Webhook|WebhookClient|Interaction} MessageTarget
* @typedef {TextChannel|DMChannel|User|GuildMember|Webhook|WebhookClient|Interaction|InteractionWebhook} MessageTarget
*/
/**

View File

@@ -1,8 +1,8 @@
'use strict';
const Interaction = require('./Interaction');
const InteractionWebhook = require('./InteractionWebhook');
const InteractionResponses = require('./interfaces/InteractionResponses');
const WebhookClient = require('../client/WebhookClient');
const Collection = require('../util/Collection');
const { ApplicationCommandOptionTypes } = require('../util/Constants');
@@ -53,10 +53,10 @@ class CommandInteraction extends Interaction {
this.replied = false;
/**
* An associated webhook client, can be used to create deferred replies
* @type {WebhookClient}
* An associated interaction webhook, can be used to further interact with this interaction
* @type {InteractionWebhook}
*/
this.webhook = new WebhookClient(this.applicationID, this.token, this.client.options);
this.webhook = new InteractionWebhook(this.client, this.applicationID, this.token);
}
/**

View File

@@ -0,0 +1,44 @@
'use strict';
const Webhook = require('./Webhook');
/**
* Represents a webhook for an Interaction
* @implements {Webhook}
*/
class InteractionWebhook {
/**
* @param {Client} client The instantiating client
* @param {Snowflake} id ID of the application
* @param {string} token Token of the interaction
*/
constructor(client, id, token) {
/**
* The client that instantiated the interaction webhook
* @name InteractionWebhook#client
* @type {Client}
* @readonly
*/
Object.defineProperty(this, 'client', { value: client });
this.id = id;
Object.defineProperty(this, 'token', { value: token, writable: true, configurable: true });
}
// These are here only for documentation purposes - they are implemented by Webhook
/* eslint-disable no-empty-function, valid-jsdoc */
/**
* Sends a message with this webhook.
* @param {string|APIMessage|MessageAdditions} content The content for the reply
* @param {InteractionReplyOptions} [options] Additional options for the reply
* @returns {Promise<Message|Object>}
*/
send() {}
fetchMessage() {}
editMessage() {}
deleteMessage() {}
get url() {}
}
Webhook.applyToClass(InteractionWebhook, ['sendSlackMessage', 'edit', 'delete', 'createdTimestamp', 'createdAt']);
module.exports = InteractionWebhook;

View File

@@ -1,8 +1,8 @@
'use strict';
const Interaction = require('./Interaction');
const InteractionWebhook = require('./InteractionWebhook');
const InteractionResponses = require('./interfaces/InteractionResponses');
const WebhookClient = require('../client/WebhookClient');
const { MessageComponentTypes } = require('../util/Constants');
/**
@@ -45,10 +45,10 @@ class MessageComponentInteraction extends Interaction {
this.replied = false;
/**
* An associated webhook client, can be used to create deferred replies
* @type {WebhookClient}
* An associated interaction webhook, can be used to further interact with this interaction
* @type {InteractionWebhook}
*/
this.webhook = new WebhookClient(this.applicationID, this.token, this.client.options);
this.webhook = new InteractionWebhook(this.client, this.applicationID, this.token);
}
/**

View File

@@ -325,7 +325,7 @@ class Webhook {
return this.client.rest.cdn.Avatar(this.id, this.avatar, format, size);
}
static applyToClass(structure) {
static applyToClass(structure, ignore = []) {
for (const prop of [
'send',
'sendSlackMessage',
@@ -338,6 +338,7 @@ class Webhook {
'createdAt',
'url',
]) {
if (ignore.includes(prop)) continue;
Object.defineProperty(structure.prototype, prop, Object.getOwnPropertyDescriptor(Webhook.prototype, prop));
}
}

View File

@@ -93,9 +93,8 @@ class InteractionResponses {
* .then(reply => console.log(`Replied with ${reply.content}`))
* .catch(console.error);
*/
async fetchReply() {
const raw = await this.webhook.fetchMessage('@original');
return this.channel?.messages.add(raw) ?? raw;
fetchReply() {
return this.webhook.fetchMessage('@original');
}
/**
@@ -110,9 +109,8 @@ class InteractionResponses {
* .then(console.log)
* .catch(console.error);
*/
async editReply(content, options) {
const raw = await this.webhook.editMessage('@original', content, options);
return this.channel?.messages.add(raw) ?? raw;
editReply(content, options) {
return this.webhook.editMessage('@original', content, options);
}
/**
@@ -135,16 +133,8 @@ class InteractionResponses {
* @param {InteractionReplyOptions} [options] Additional options for the reply
* @returns {Promise<Message|Object>}
*/
async followUp(content, options) {
const apiMessage = content instanceof APIMessage ? content : APIMessage.create(this, content, options);
const { data, files } = await apiMessage.resolveData().resolveFiles();
const raw = await this.client.api.webhooks(this.applicationID, this.token).post({
data,
files,
});
return this.channel?.messages.add(raw) ?? raw;
followUp(content, options) {
return this.webhook.send(content, options);
}
/**

45
typings/index.d.ts vendored
View File

@@ -467,7 +467,7 @@ declare module 'discord.js' {
public deferred: boolean;
public options: Collection<string, CommandInteractionOption>;
public replied: boolean;
public webhook: WebhookClient;
public webhook: InteractionWebhook;
public defer(options?: InteractionDeferOptions): Promise<void>;
public deleteReply(): Promise<void>;
public editReply(
@@ -1139,6 +1139,30 @@ declare module 'discord.js' {
public isMessageComponent(): this is MessageComponentInteraction;
}
export class InteractionWebhook extends PartialWebhookMixin() {
constructor(client: Client, id: Snowflake, token: string);
public token: string;
public send(
content: string | (InteractionReplyOptions & { split?: false }) | MessageAdditions,
): Promise<Message | RawMessage>;
public send(options: InteractionReplyOptions & { split: true | SplitOptions }): Promise<(Message | RawMessage)[]>;
public send(
options: InteractionReplyOptions | APIMessage,
): Promise<Message | RawMessage | (Message | RawMessage)[]>;
public send(
content: string | null,
options: (InteractionReplyOptions & { split?: false }) | MessageAdditions,
): Promise<Message | RawMessage>;
public send(
content: string | null,
options: InteractionReplyOptions & { split: true | SplitOptions },
): Promise<(Message | RawMessage)[]>;
public send(
content: string | null,
options: InteractionReplyOptions,
): Promise<Message | RawMessage | (Message | RawMessage)[]>;
}
export class Invite extends Base {
constructor(client: Client, data: unknown);
public channel: GuildChannel | PartialGroupDMChannel;
@@ -1333,7 +1357,7 @@ declare module 'discord.js' {
public deferred: boolean;
public message: Message | RawMessage;
public replied: boolean;
public webhook: WebhookClient;
public webhook: InteractionWebhook;
public defer(options?: InteractionDeferOptions): Promise<void>;
public deferUpdate(): Promise<void>;
public deleteReply(): Promise<void>;
@@ -2498,18 +2522,15 @@ declare module 'discord.js' {
stopTyping(force?: boolean): void;
}
function PartialWebhookMixin<T>(Base?: Constructable<T>): Constructable<T & PartialWebhookFields>;
function WebhookMixin<T>(Base?: Constructable<T>): Constructable<T & WebhookFields>;
function VolumeMixin<T>(base: Constructable<T>): Constructable<T & VolumeInterface>;
interface WebhookFields {
interface PartialWebhookFields {
id: Snowflake;
readonly createdAt: Date;
readonly createdTimestamp: number;
readonly url: string;
delete(reason?: string): Promise<void>;
deleteMessage(message: MessageResolvable | '@original'): Promise<void>;
edit(options: WebhookEditData): Promise<Webhook>;
editMessage(
message: MessageResolvable | '@original',
content: string | null | APIMessage | MessageAdditions,
@@ -2537,7 +2558,14 @@ declare module 'discord.js' {
content: string | null,
options: WebhookMessageOptions,
): Promise<Message | RawMessage | (Message | RawMessage)[]>;
sendSlackMessage(body: unknown): Promise<boolean>;
}
interface WebhookFields extends PartialWebhookFields {
readonly createdAt: Date;
readonly createdTimestamp: number;
delete(reason?: string): Promise<void>;
edit(options: WebhookEditData): Promise<Webhook>;
sendSlackMessage(body: object): Promise<boolean>;
}
//#endregion
@@ -3532,6 +3560,7 @@ declare module 'discord.js' {
type MessageTarget =
| Interaction
| InteractionWebhook
| TextChannel
| NewsChannel
| DMChannel