slash-create
Version:
Create and sync Discord slash commands!
332 lines (331 loc) • 15.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MessageInteractionContext = void 0;
const constants_1 = require("../../constants");
const util_1 = require("../../util");
const message_1 = require("../message");
const baseInteraction_1 = require("./baseInteraction");
/** Represents a interaction context that handles messages. */
class MessageInteractionContext extends baseInteraction_1.BaseInteractionContext {
/**
* @param creator The instantiating creator.
* @param data The interaction data.
* @param respond The response function for the interaction.
* @param serverContext The context of the server.
*/
constructor(creator, data, respond, serverContext) {
super(creator, data, serverContext);
/** Whether the initial response was sent. */
this.initiallyResponded = false;
/** Whether there is a deferred message available. */
this.deferred = false;
this._respond = respond;
}
/**
* Fetches a message.
* @param messageID The ID of the message, defaults to the original message
*/
async fetch(messageID = '@original') {
const data = await this.creator.api.fetchInteractionMessage(this.creator.options.applicationID, this.interactionToken, messageID);
if (messageID === '@original')
this.messageID = data.id;
return new message_1.Message(data, this.creator, this);
}
/**
* Sends a message, if it already made an initial response, this will create a follow-up message.
* If the context has created a deferred message, it will edit that deferred message,
* and future calls to this function create follow ups.
* This will return `true` or a {@link InitialCallbackResponse} if it's an initial response, otherwise a {@link Message} will be returned.
* Note that when making a follow-up message, the `ephemeral` option is ignored.
* @param content The content of the message
* @returns `true` or a {@link InitialCallbackResponse} if the initial response passed, otherwise a {@link Message} of the follow-up message.
*/
async send(content) {
if (this.expired)
throw new Error('This interaction has expired');
const options = typeof content === 'string' ? { content } : content;
if (typeof options !== 'object')
throw new Error('Message options is not an object.');
if (!options.content && !options.embeds && !options.files && !options.poll && !options.components)
throw new Error('No valid options were given.');
if (options.ephemeral && !options.flags)
options.flags = constants_1.MessageFlags.EPHEMERAL;
const allowedMentions = options.allowedMentions
? (0, util_1.formatAllowedMentions)(options.allowedMentions, this.creator.allowedMentions)
: this.creator.allowedMentions;
if (!this.initiallyResponded) {
this.initiallyResponded = true;
clearTimeout(this._timeout);
const response = await this._respond({
status: 200,
body: {
type: constants_1.InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
data: {
tts: options.tts,
content: options.content,
embeds: options.embeds,
flags: options.flags,
allowed_mentions: allowedMentions,
components: options.components,
attachments: options.attachments,
poll: options.poll
}
},
files: options.files
});
return response ? (0, util_1.convertCallbackResponse)(response, this) : true;
}
else if (this.initiallyResponded && this.deferred)
return this.editOriginal(content);
else
return this.sendFollowUp(options);
}
/**
* Sends a follow-up message.
* @param content The content of the message
*/
async sendFollowUp(content) {
if (this.expired)
throw new Error('This interaction has expired');
const options = typeof content === 'string' ? { content } : content;
if (typeof options !== 'object')
throw new Error('Message options is not an object.');
if (!options.content && !options.embeds && !options.files && !options.poll && !options.components)
throw new Error('No valid options were given.');
if (options.ephemeral && !options.flags)
options.flags = constants_1.MessageFlags.EPHEMERAL;
const allowedMentions = options.allowedMentions
? (0, util_1.formatAllowedMentions)(options.allowedMentions, this.creator.allowedMentions)
: this.creator.allowedMentions;
const data = await this.creator.api.followUpMessage(this.creator.options.applicationID, this.interactionToken, {
tts: options.tts,
content: options.content,
embeds: options.embeds,
allowed_mentions: allowedMentions,
components: options.components,
flags: options.flags,
attachments: options.attachments,
poll: options.poll
}, options.files);
return new message_1.Message(data, this.creator, this);
}
/**
* Edits a message.
* @param messageID The message's ID
* @param content The content of the message
*/
async edit(messageID, content) {
if (this.expired)
throw new Error('This interaction has expired');
const options = typeof content === 'string' ? { content } : content;
if (typeof options !== 'object')
throw new Error('Message options is not an object.');
if (!options.content &&
!options.embeds &&
!options.components &&
!options.files &&
!options.attachments &&
!options.poll)
throw new Error('No valid options were given.');
const allowedMentions = options.allowedMentions
? (0, util_1.formatAllowedMentions)(options.allowedMentions, this.creator.allowedMentions)
: this.creator.allowedMentions;
const data = await this.creator.api.updateInteractionMessage(this.creator.options.applicationID, this.interactionToken, messageID, {
content: options.content,
embeds: options.embeds,
allowed_mentions: allowedMentions,
components: options.components,
flags: options.flags,
attachments: options.attachments,
poll: options.poll
}, options.files);
return new message_1.Message(data, this.creator, this);
}
/**
* Edits the original message.
* Note: This will error with ephemeral messages or deferred ephemeral messages.
* @param content The content of the message
* @param options The message options
*/
async editOriginal(content) {
this.deferred = false;
const message = await this.edit('@original', content);
this.messageID = message.id;
return message;
}
/**
* Deletes a message. If the message ID was not defined, the original message is used.
* @param messageID The message's ID
*/
async delete(messageID) {
if (this.expired)
throw new Error('This interaction has expired');
await this.creator.api.deleteInteractionMessage(this.creator.options.applicationID, this.interactionToken, messageID);
if (!messageID || messageID === '@original' || messageID === this.messageID)
this.messageID = undefined;
}
/**
* Creates a deferred message. To users, this will show as
* "Bot is thinking..." until the deferred message is edited.
* @param ephemeralOrFlags If its a number, the message flags to use, if a boolean, whether to make the deferred message ephemeral.
* @returns Whether the deferred message passed or the callback response if available
*/
async defer(ephemeralOrFlags = 0) {
const flags = typeof ephemeralOrFlags === 'boolean' ? (ephemeralOrFlags ? constants_1.MessageFlags.EPHEMERAL : 0) : ephemeralOrFlags;
if (!this.initiallyResponded && !this.deferred) {
this.initiallyResponded = true;
this.deferred = true;
clearTimeout(this._timeout);
const response = await this._respond({
status: 200,
body: {
type: constants_1.InteractionResponseType.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE,
data: {
flags
}
}
});
return response ? (0, util_1.convertCallbackResponse)(response, this) : true;
}
return false;
}
/**
* Creates a message that prompts the user for a premium subscription.
* @returns Whether the message passed or the callback response if available
* @deprecated Use `ComponentButtonPremium` instead.
*/
async promptPremium() {
if (!this.initiallyResponded && !this.deferred) {
this.initiallyResponded = true;
this.deferred = true;
clearTimeout(this._timeout);
const response = await this._respond({
status: 200,
body: {
type: constants_1.InteractionResponseType.PREMIUM_REQUIRED,
data: {}
}
});
return response ? (0, util_1.convertCallbackResponse)(response, this) : true;
}
return false;
}
/**
* Launches the activity this app is associated with.
* @returns Whether the message passed or the callback response if available
*/
async launchActivity() {
if (!this.initiallyResponded && !this.deferred) {
this.initiallyResponded = true;
this.deferred = true;
clearTimeout(this._timeout);
const response = await this._respond({
status: 200,
body: {
type: constants_1.InteractionResponseType.LAUNCH_ACTIVITY,
data: {}
}
});
return response ? (0, util_1.convertCallbackResponse)(response, this) : true;
}
return false;
}
/**
* Registers a component callback from the initial message.
* This unregisters automatically when the context expires.
* @param custom_id The custom ID of the component to register
* @param callback The callback to use on interaction
* @param expiration The expiration time of the callback in milliseconds. Use null for no expiration (Although, in this case, global components might be more consistent).
* @param onExpired A function to be called when the component expires.
*/
registerComponent(custom_id, callback, expiration = 1000 * 60 * 15, onExpired) {
if (!this.initiallyResponded || this.deferred)
throw new Error('You must send a message before registering components');
if (!this.messageID)
throw new Error('Fetch your original message or use deferred messages before registering components');
this.creator._componentCallbacks.set(`${this.messageID}-${custom_id}`, {
callback,
expires: expiration != null ? Date.now() + expiration : undefined,
onExpired
});
if (expiration != null && this.creator.options.componentTimeouts)
setTimeout(() => {
if (this.creator._componentCallbacks.has(`${this.messageID}-${custom_id}`)) {
if (onExpired)
onExpired();
this.creator._componentCallbacks.delete(`${this.messageID}-${custom_id}`);
}
}, expiration);
}
/**
* Registers a component callback from a message.
* This unregisters automatically when the context expires.
* @param message_id The message ID of the component to register
* @param custom_id The custom ID of the component to register
* @param callback The callback to use on interaction
* @param expiration The expiration time of the callback in milliseconds. Use null for no expiration (Although, in this case, global components might be more consistent).
* @param onExpired A function to be called when the component expires.
*/
registerComponentFrom(message_id, custom_id, callback, expiration = 1000 * 60 * 15, onExpired) {
this.creator._componentCallbacks.set(`${message_id}-${custom_id}`, {
callback,
expires: expiration != null ? Date.now() + expiration : undefined,
onExpired
});
if (expiration != null && this.creator.options.componentTimeouts)
setTimeout(() => {
if (this.creator._componentCallbacks.has(`${message_id}-${custom_id}`)) {
if (onExpired)
onExpired();
this.creator._componentCallbacks.delete(`${message_id}-${custom_id}`);
}
}, expiration);
}
/**
* Unregisters a component callback.
* @param custom_id The custom ID of the component to unregister
* @param message_id The message ID of the component to unregister, defaults to initial message ID if any
*/
unregisterComponent(custom_id, message_id) {
if (!message_id) {
if (!this.messageID)
throw new Error('The initial message ID was not provided by the context!');
else
message_id = this.messageID;
}
return this.creator._componentCallbacks.delete(`${message_id}-${custom_id}`);
}
/**
* Registers a wildcard component callback on a message.
* This unregisters automatically when the context expires.
* @param message_id The message ID of the component to register
* @param callback The callback to use on interaction
* @param expiration The expiration time of the callback in milliseconds. Use null for no expiration (Although, in this case, global components might be more consistent).
* @param onExpired A function to be called when the component expires.
*/
registerWildcardComponent(message_id, callback, expiration = 1000 * 60 * 15, onExpired) {
if (this.expired)
throw new Error('This interaction has expired');
this.creator._componentCallbacks.set(`${message_id}-*`, {
callback,
expires: expiration != null ? this.invokedAt + expiration : undefined,
onExpired
});
if (expiration != null && this.creator.options.componentTimeouts)
setTimeout(() => {
if (this.creator._componentCallbacks.has(`${message_id}-*`)) {
if (onExpired)
onExpired();
this.creator._componentCallbacks.delete(`${message_id}-*`);
}
}, expiration);
}
/**
* Unregisters a component callback.
* @param message_id The message ID of the component to unregister, defaults to the invoking message ID.
*/
unregisterWildcardComponent(message_id) {
return this.creator._componentCallbacks.delete(`${message_id}-*`);
}
}
exports.MessageInteractionContext = MessageInteractionContext;