oceanic.js
Version:
A NodeJS library for interfacing with Discord.
1,113 lines • 92.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const Routes = tslib_1.__importStar(require("../util/Routes"));
const Invite_1 = tslib_1.__importDefault(require("../structures/Invite"));
const StageInstance_1 = tslib_1.__importDefault(require("../structures/StageInstance"));
const Constants_1 = require("../Constants");
const QueryBuilder_1 = tslib_1.__importDefault(require("../util/QueryBuilder"));
/** Various methods for interacting with channels. Located at {@link Client#rest | Client#rest}{@link RESTManager#channels | .channels}. */
class Channels {
_manager;
constructor(manager) {
this._manager = manager;
}
/**
* Add a user to a group channel.
* @param groupID The ID of the group to add the user to.
* @param options The options for adding the recipient.
* @caching This method **does not** cache its result.
*/
async addGroupRecipient(groupID, options) {
options = this._manager.client.util._freeze(options);
await this._manager.authRequest({
method: "PUT",
path: Routes.GROUP_RECIPIENT(groupID, options.userID),
json: {
access_token: options.accessToken,
nick: options.nick
}
});
}
/**
* Add a member to a thread.
* @param channelID The ID of the thread to add them to.
* @param userID The ID of the user to add to the thread.
* @caching This method **does not** cache its result.
*/
async addThreadMember(channelID, userID) {
await this._manager.authRequest({
method: "PUT",
path: Routes.CHANNEL_THREAD_MEMBER(channelID, userID)
});
}
/**
* Create a direct message. This will not create a new channel if you have already started a dm with the user.
* @param recipient The ID of the recipient of the direct message.
* @caching This method **does** cache its result.
* @caches {@link Client#privateChannels | Client#privateChannels}
*/
async createDM(recipient) {
let cache;
if ((cache = this._manager.client.privateChannels.find(ch => ch.recipient.id === recipient))) {
return cache;
}
return this._manager.authRequest({
method: "POST",
path: Routes.OAUTH_CHANNELS,
json: { recipient_id: recipient }
}).then(data => this._manager.client.privateChannels.update(data));
}
/**
* Create a group dm.
* @param options The options for creating the group dm.
* @caching This method **does** cache its result.
* @caches {@link Client#groupChannels | Client#groupChannels}
*/
async createGroupDM(options) {
options = this._manager.client.util._freeze(options);
return this._manager.authRequest({
method: "POST",
path: Routes.OAUTH_CHANNELS,
json: {
access_tokens: options.accessTokens,
nicks: options.nicks
}
}).then(data => this._manager.client.groupChannels.update(data));
}
/**
* Create an invite for a channel. If the guild is not a `COMMUNITY` server, invites can only be made to last 30 days.
* @param channelID The ID of the channel to create an invite for.
* @param options The options for creating the invite.
* @caching This method **does not** cache its result.
*/
async createInvite(channelID, options) {
options = this._manager.client.util._freeze(options);
return this._manager.authRequest({
method: "POST",
path: Routes.CHANNEL_INVITES(channelID),
json: {
max_age: options.maxAge,
max_uses: options.maxUses,
target_application_id: options.targetApplicationID,
target_type: options.targetType,
target_user_id: options.targetUserID,
temporary: options.temporary,
unique: options.unique
},
reason: options.reason
}).then(data => new Invite_1.default(data, this._manager.client));
}
/**
* Create a message in a channel.
* @param channelID The ID of the channel to create the message in.
* @param options The options for creating the message.
* @caching This method **may** cache its result. The result will not be cached if the channel is not cached.
* @caches {@link TextableChannel#messages | TextableChannel#messages}<br>{@link ThreadChannel#messages | ThreadChannel#messages}<br>{@link PrivateChannel#messages | PrivateChannel#messages}
*/
async createMessage(channelID, options) {
options = this._manager.client.util._freeze(options);
return this._manager.authRequest({
method: "POST",
path: Routes.CHANNEL_MESSAGES(channelID),
json: {
allowed_mentions: this._manager.client.util.formatAllowedMentions(options.allowedMentions),
attachments: options.attachments,
components: options.components ? this._manager.client.util.componentsToRaw(options.components) : undefined,
content: options.content,
embeds: options.embeds ? this._manager.client.util.embedsToRaw(options.embeds) : undefined,
enforce_nonce: options.enforceNonce,
flags: options.flags,
sticker_ids: options.stickerIDs,
message_reference: options.messageReference ? {
channel_id: options.messageReference.channelID,
fail_if_not_exists: options.messageReference.failIfNotExists,
guild_id: options.messageReference.guildID,
message_id: options.messageReference.messageID
} : undefined,
nonce: options.nonce,
poll: options.poll ? {
allow_multiselect: options.poll.allowMultiselect,
answers: options.poll.answers.map(a => ({
poll_media: a.pollMedia
})),
duration: options.poll.duration,
layout_type: options.poll.layoutType,
question: options.poll.question
} : undefined,
tts: options.tts
},
files: options.files
}).then(data => this._manager.client.util.updateMessage(data));
}
/**
* Add a reaction to a message.
* @param channelID The ID of the channel the message is in.
* @param messageID The ID of the message to add a reaction to.
* @param emoji The reaction to add to the message. `name:id` for custom emojis, and the unicode codepoint for default emojis.
* @caching This method **does not** cache its result.
*/
async createReaction(channelID, messageID, emoji) {
await this._manager.authRequest({
method: "PUT",
path: Routes.CHANNEL_REACTION_USER(channelID, messageID, emoji, "@me")
});
}
/**
* Create a stage instance.
* @param channelID The ID of the channel to create the stage instance on.
* @param options The options for creating the stage instance.
* @caching This method **does not** cache its result.
*/
async createStageInstance(channelID, options) {
options = this._manager.client.util._freeze(options);
return this._manager.authRequest({
method: "POST",
path: Routes.STAGE_INSTANCES,
json: {
channel_id: channelID,
topic: options.topic,
privacy_level: options.privacyLevel,
send_start_notification: options.sendStartNotification
},
reason: options.reason
}).then(data => new StageInstance_1.default(data, this._manager.client));
}
/**
* Crosspost a message in an announcement channel.
* @param channelID The ID of the channel to crosspost the message in.
* @param messageID The ID of the message to crosspost.
* @caching This method **may** cache its result. The result will not be cached if the channel is not cached.
* @caches {@link TextableChannel#messages | TextableChannel#messages}<br>{@link ThreadChannel#messages | ThreadChannel#messages}<br>{@link PrivateChannel#messages | PrivateChannel#messages}
*/
async crosspostMessage(channelID, messageID) {
return this._manager.authRequest({
method: "POST",
path: Routes.CHANNEL_MESSAGES_CROSSPOST(channelID, messageID)
}).then(data => this._manager.client.util.updateMessage(data));
}
/**
* Delete or close a channel.
* @param channelID The ID of the channel to delete or close.
* @param reason The reason to be displayed in the audit log.
* @caching This method **does not** cache its result.
*/
async delete(channelID, reason) {
await this._manager.authRequest({
method: "DELETE",
path: Routes.CHANNEL(channelID),
reason
});
}
/**
* Delete an invite.
* @param code The code of the invite to delete.
* @param reason The reason for deleting the invite.
* @caching This method **does not** cache its result.
*/
async deleteInvite(code, reason) {
return this._manager.authRequest({
method: "DELETE",
path: Routes.INVITE(code),
reason
}).then(data => new Invite_1.default(data, this._manager.client));
}
/**
* Delete a message.
* @param channelID The ID of the channel to delete the message in.
* @param messageID The ID of the message to delete.
* @param reason The reason for deleting the message.
* @caching This method **does not** cache its result.
*/
async deleteMessage(channelID, messageID, reason) {
await this._manager.authRequest({
method: "DELETE",
path: Routes.CHANNEL_MESSAGE(channelID, messageID),
reason
});
}
/**
* Bulk delete messages.
* @param channelID The ID of the channel to delete the messages in.
* @param messageIDs The IDs of the messages to delete. Any duplicates or messages older than two weeks will cause an error.
* @param reason The reason for deleting the messages.
* @caching This method **does not** cache its result.
*/
async deleteMessages(channelID, messageIDs, reason) {
const chunks = [];
messageIDs = Array.from(messageIDs);
const amountOfMessages = messageIDs.length;
while (messageIDs.length !== 0) {
chunks.push(messageIDs.splice(0, 100));
}
let done = 0;
for (const chunk of chunks.values()) {
if (chunks.length > 1) {
const left = amountOfMessages - done;
this._manager.client.emit("debug", `Deleting ${left} messages in ${channelID}`);
}
if (chunk.length === 1) {
this._manager.client.emit("debug", "deleteMessages created a chunk with only 1 element, using deleteMessage instead.");
await this.deleteMessage(channelID, chunk[0], reason);
continue;
}
await this._manager.authRequest({
method: "POST",
path: Routes.CHANNEL_BULK_DELETE_MESSAGES(channelID),
json: { messages: chunk },
reason
});
done += chunk.length;
}
return amountOfMessages;
}
/**
* Delete a permission overwrite.
* @param channelID The ID of the channel to delete the permission overwrite in.
* @param overwriteID The ID of the permission overwrite to delete.
* @param reason The reason for deleting the permission overwrite.
* @caching This method **does not** cache its result.
*/
async deletePermission(channelID, overwriteID, reason) {
await this._manager.authRequest({
method: "DELETE",
path: Routes.CHANNEL_PERMISSION(channelID, overwriteID),
reason
});
}
/**
* Remove a reaction from a message.
* @param channelID The ID of the channel the message is in.
* @param messageID The ID of the message to remove a reaction from.
* @param emoji The reaction to remove from the message. `name:id` for custom emojis, and the unicode codepoint for default emojis.
* @param user The user to remove the reaction from, `@me` for the current user (default).
* @caching This method **does not** cache its result.
*/
async deleteReaction(channelID, messageID, emoji, user = "@me") {
await this._manager.authRequest({
method: "DELETE",
path: Routes.CHANNEL_REACTION_USER(channelID, messageID, emoji, user)
});
}
/**
* Remove all, or a specific emoji's reactions from a message.
* @param channelID The ID of the channel the message is in.
* @param messageID The ID of the message to remove reactions from.
* @param emoji The reaction to remove from the message. `name:id` for custom emojis, and the unicode codepoint for default emojis. Omit to remove all reactions.
* @caching This method **does not** cache its result.
*/
async deleteReactions(channelID, messageID, emoji) {
await this._manager.authRequest({
method: "DELETE",
path: emoji ? Routes.CHANNEL_REACTION(channelID, messageID, emoji) : Routes.CHANNEL_REACTIONS(channelID, messageID)
});
}
/**
* Delete a stage instance.
* @param channelID The ID of the channel to delete the stage instance on.
* @param reason The reason for deleting the stage instance.
* @caching This method **does not** cache its result.
*/
async deleteStageInstance(channelID, reason) {
await this._manager.authRequest({
method: "DELETE",
path: Routes.STAGE_INSTANCE(channelID),
reason
});
}
/**
* Edit a channel.
* @param channelID The ID of the channel to edit.
* @param options The options for editing the channel.
* @caching This method **may** cache its result. If a guild channel, the result will not be cached if the guild is not cached.
* @caches {@link Guild#channels | Guild#channels}<br>{@link Guild#threads | Guild#threads}<br>{@link Client#groupChannels | Client#groupChannels}
*/
async edit(channelID, options) {
options = this._manager.client.util._freeze(options);
let icon;
if (options.icon) {
try {
icon = this._manager.client.util.convertImage(options.icon);
}
catch (err) {
throw new TypeError("Invalid icon provided. Ensure you are providing a valid, fully-qualified base64 url.", { cause: err });
}
}
return this._manager.authRequest({
method: "PATCH",
path: Routes.CHANNEL(channelID),
json: {
applied_tags: options.appliedTags,
archived: options.archived,
auto_archive_duration: options.autoArchiveDuration,
available_tags: options.availableTags?.map(tag => ({
emoji_id: tag.emoji?.id,
emoji_name: tag.emoji?.name,
moderated: tag.moderated,
name: tag.name,
id: tag.id
})),
bitrate: options.bitrate,
default_auto_archive_duration: options.defaultAutoArchiveDuration,
default_forum_layout: options.defaultForumLayout,
default_reaction_emoji: options.defaultReactionEmoji ? { emoji_id: options.defaultReactionEmoji.id, emoji_name: options.defaultReactionEmoji.name } : options.defaultReactionEmoji,
default_sort_order: options.defaultSortOrder,
default_thread_rate_limit_per_user: options.defaultThreadRateLimitPerUser,
flags: options.flags,
icon,
invitable: options.invitable,
locked: options.locked,
name: options.name,
nsfw: options.nsfw,
parent_id: options.parentID,
permission_overwrites: options.permissionOverwrites,
position: options.position,
rate_limit_per_user: options.rateLimitPerUser,
rtc_region: options.rtcRegion,
topic: options.topic,
type: options.type,
user_limit: options.userLimit,
video_quality_mode: options.videoQualityMode
},
reason: options.reason
}).then(data => this._manager.client.util.updateChannel(data));
}
/**
* Edit a message.
* @param channelID The ID of the channel the message is in.
* @param messageID The ID of the message to edit.
* @param options The options for editing the message.
* @caching This method **may** cache its result. The result will not be cached if the channel is not cached.
* @caches {@link TextableChannel#messages | TextableChannel#messages}<br>{@link ThreadChannel#messages | ThreadChannel#messages}<br>{@link PrivateChannel#messages | PrivateChannel#messages}
*/
async editMessage(channelID, messageID, options) {
options = this._manager.client.util._freeze(options);
return this._manager.authRequest({
method: "PATCH",
path: Routes.CHANNEL_MESSAGE(channelID, messageID),
json: {
allowed_mentions: options.content !== undefined || options.allowedMentions || ((options.flags ?? 0) & Constants_1.MessageFlags.IS_COMPONENTS_V2) !== 0
? this._manager.client.util.formatAllowedMentions(options.allowedMentions)
: undefined,
attachments: options.attachments,
components: options.components ? this._manager.client.util.componentsToRaw(options.components) : undefined,
content: options.content,
embeds: options.embeds ? this._manager.client.util.embedsToRaw(options.embeds) : undefined,
flags: options.flags
},
files: options.files ?? undefined
}).then(data => this._manager.client.util.updateMessage(data));
}
/**
* Edit a permission overwrite.
* @param channelID The ID of the channel to edit the permission overwrite for.
* @param overwriteID The ID of the permission overwrite to edit.
* @param options The options for editing the permission overwrite.
* @caching This method **does not** cache its result.
*/
async editPermission(channelID, overwriteID, options) {
options = this._manager.client.util._freeze(options);
await this._manager.authRequest({
method: "PUT",
path: Routes.CHANNEL_PERMISSION(channelID, overwriteID),
json: {
allow: options.allow,
deny: options.deny,
type: options.type
},
reason: options.reason
});
}
/**
* Edit a stage instance.
* @param channelID The ID of the channel to edit the stage instance on.
* @param options The options for editing the stage instance.
* @caching This method **does not** cache its result.
*/
async editStageInstance(channelID, options) {
options = this._manager.client.util._freeze(options);
return this._manager.authRequest({
method: "PATCH",
path: Routes.STAGE_INSTANCE(channelID),
json: {
channel_id: channelID,
topic: options.topic,
privacy_level: options.privacyLevel
},
reason: options.reason
}).then(data => new StageInstance_1.default(data, this._manager.client));
}
/**
* End a poll now.
* @param channelID The ID of the channel the poll is in.
* @param messageID The ID of the message the poll is on.
* @caching This method **does not** cache its result.
*/
async expirePoll(channelID, messageID) {
await this._manager.authRequest({
method: "POST",
path: Routes.POLL_EXPIRE(channelID, messageID)
});
}
/**
* Follow an announcement channel.
* @param channelID The ID of the channel to follow announcements from.
* @param webhookChannelID The ID of the channel crossposted messages should be sent to. The client must have the `MANAGE_WEBHOOKS` permission in this channel.
* @param reason The reason for following the announcement channel.
* @caching This method **does not** cache its result.
*/
async followAnnouncement(channelID, webhookChannelID, reason) {
return this._manager.authRequest({
method: "POST",
reason,
path: Routes.CHANNEL_FOLLOWERS(channelID),
json: { webhook_channel_id: webhookChannelID }
}).then(data => ({
channelID: data.channel_id,
webhookID: data.webhook_id
}));
}
/**
* Get a channel.
* @param channelID The ID of the channel to get.
* @caching This method **may** cache its result. The result will not be cached if the guild is not cached.
* @caches {@link Guild#channels | Guild#channels}<br>{@link Guild#threads | Guild#threads}<br>{@link Client#privateChannels | Client#privateChannels}<br>{@link Client#groupChannels | Client#groupChannels}
*/
async get(channelID) {
return this._manager.authRequest({
method: "GET",
path: Routes.CHANNEL(channelID)
}).then(data => this._manager.client.util.updateChannel(data));
}
async getInvite(code, options) {
options = this._manager.client.util._freeze(options);
const query = new QueryBuilder_1.default();
query.setIfPresent("guild_scheduled_event_id", options?.guildScheduledEventID);
query.setIfPresent("with_counts", options?.withCounts);
query.setIfPresent("with_expiration", options?.withExpiration);
return this._manager.authRequest({
method: "GET",
path: Routes.INVITE(code),
query
}).then(data => new Invite_1.default(data, this._manager.client));
}
/**
* Get the invites of a channel.
* @param channelID The ID of the channel to get the invites of.
* @caching This method **does not** cache its result.
*/
async getInvites(channelID) {
return this._manager.authRequest({
method: "GET",
path: Routes.CHANNEL_INVITES(channelID)
}).then(data => data.map(invite => new Invite_1.default(invite, this._manager.client)));
}
/**
* Get the private archived threads the current user has joined in a channel.
* @param channelID The ID of the channel to get the archived threads from.
* @param options The options for getting the archived threads.
* @caching This method **does not** cache its result.
*/
async getJoinedPrivateArchivedThreads(channelID, options) {
options = this._manager.client.util._freeze(options);
return this._manager.authRequest({
method: "GET",
path: Routes.CHANNEL_PRIVATE_ARCHIVED_THREADS(channelID),
json: {
before: options?.before,
limit: options?.limit
}
}).then(data => ({
hasMore: data.has_more,
members: data.members.map(m => ({
flags: m.flags,
id: m.id,
joinTimestamp: new Date(m.join_timestamp),
userID: m.user_id
})),
threads: data.threads.map(d => this._manager.client.util.updateThread(d))
}));
}
/**
* Get a message in a channel.
* @param channelID The ID of the channel the message is in
* @param messageID The ID of the message to get.
* @caching This method **may** cache its result. The result will not be cached if the channel is not cached.
* @caches {@link TextableChannel#messages | TextableChannel#messages}<br>{@link ThreadChannel#messages | ThreadChannel#messages}<br>{@link PrivateChannel#messages | PrivateChannel#messages}
*/
async getMessage(channelID, messageID) {
return this._manager.authRequest({
method: "GET",
path: Routes.CHANNEL_MESSAGE(channelID, messageID)
}).then(data => this._manager.client.util.updateMessage(data));
}
/**
* Get messages in a channel.
* @param channelID The ID of the channel to get messages from.
* @param options The options for getting messages. `before`, `after`, and `around `All are mutually exclusive.
* @caching This method **may** cache its result. The result will not be cached if the channel is not cached.
* @caches {@link TextableChannel#messages | TextableChannel#messages}<br>{@link ThreadChannel#messages | ThreadChannel#messages}<br>{@link PrivateChannel#messages | PrivateChannel#messages}
*/
async getMessages(channelID, options) {
options = this._manager.client.util._freeze(options);
const query = new QueryBuilder_1.default();
let chosenOption;
if (options?.around !== undefined) {
query.set("around", options.around);
chosenOption = "around";
// eslint-disable-next-line unicorn/no-negated-condition
}
else if (options?.after !== undefined) {
query.set("after", options.after);
chosenOption = "after";
}
else {
query.setIfPresent("before", options?.before);
chosenOption = "before";
}
if (chosenOption === "around" || (options?.limit && options.limit <= 100)) {
const filter = options?.filter?.bind(this) ?? (() => true);
if (options?.limit !== undefined) {
query.set("limit", Math.min(options.limit, 100));
}
const messages = await this._manager.authRequest({
method: "GET",
path: Routes.CHANNEL_MESSAGES(channelID),
query
}).then(data => data.map(d => this._manager.client.util.updateMessage(d)));
for (const message of Array.from(messages)) {
const f = filter(message);
if (f === false) {
messages.splice(messages.indexOf(message), 1);
}
if (f === "break") {
messages.splice(messages.indexOf(message));
break;
}
}
return messages;
}
const results = [];
const it = this.getMessagesIterator(channelID, options);
for await (const messages of it) {
const limit = messages.length < 100 ? messages.length : it.limit + 100;
this._manager.client.emit("debug", `Getting ${limit} more message${limit === 1 ? "" : "s"} for ${channelID}: ${it.lastMessage ?? ""}`);
results.push(...messages);
}
return results;
}
/**
* Get an async iterator for getting messages in a channel.
* @param channelID The ID of the channel to get messages from.
* @param options The options for getting messages. `before`, `after`, and `around `All are mutually exclusive.
* @caching This method **may** cache its result. The result will not be cached if the channel is not cached.
* @caches {@link TextableChannel#messages | TextableChannel#messages}<br>{@link ThreadChannel#messages | ThreadChannel#messages}<br>{@link PrivateChannel#messages | PrivateChannel#messages}
*/
getMessagesIterator(channelID, options) {
options = this._manager.client.util._freeze(options);
const filter = options?.filter?.bind(this) ?? (() => true);
const chosenOption = options?.after === undefined ? "before" : "after";
// arrow functions cannot be generator functions
// eslint-disable-next-line unicorn/no-this-assignment
const self = this;
const it = {
lastMessage: chosenOption === "after" ? options?.after : options?.before,
limit: options?.limit ?? 100,
async *[Symbol.asyncIterator]() {
loop: while (it.limit > 0) {
const messages = await self.getMessages(channelID, {
limit: Math.min(it.limit, 100),
[chosenOption]: it.lastMessage
});
const originalCount = messages.length;
it.limit -= messages.length;
for (const message of Array.from(messages)) {
const f = filter(message);
if (f === false) {
messages.splice(messages.indexOf(message), 1);
}
if (f === "break") {
messages.splice(messages.indexOf(message));
yield messages;
break loop;
}
}
it.lastMessage = messages.at(-1)?.id;
yield messages;
if (originalCount < 100 || it.limit <= 0) {
break loop;
}
}
}
};
return it;
}
/**
* Get the pinned messages in a channel.
* @param channelID The ID of the channel to get the pinned messages from.
* @caching This method **may** cache its result. The result will not be cached if the channel is not cached.
* @caches {@link TextableChannel#messages | TextableChannel#messages}<br>{@link ThreadChannel#messages | ThreadChannel#messages}<br>{@link PrivateChannel#messages | PrivateChannel#messages}
*/
async getPinnedMessages(channelID) {
return this._manager.authRequest({
method: "GET",
path: Routes.CHANNEL_PINS(channelID)
}).then(data => data.map(d => this._manager.client.util.updateMessage(d)));
}
/**
* Get the users that voted on a poll answer.
* @param channelID The ID of the channel the poll is in.
* @param messageID The ID of the message the poll is on.
* @param answerID The ID of the poll answer to get voters for.
* @param options The options for getting the voters.
* @caching This method **does** cache its result.
* @caches {@link Client#users | Client#users}
*/
async getPollAnswerUsers(channelID, messageID, answerID, options) {
options = this._manager.client.util._freeze(options);
const query = new QueryBuilder_1.default();
query.setIfPresent("before", options?.after);
query.setIfPresent("limit", options?.limit);
return this._manager.authRequest({
method: "GET",
path: Routes.POLL_ANSWER_USERS(channelID, messageID, answerID),
query
}).then(data => {
const users = data.users.map(user => this._manager.client.users.update(user));
const message = this._manager.client.getChannel(channelID)?.messages.get(messageID);
if (message?.poll) {
this._manager.client.util.replacePollAnswer(message.poll, answerID, users.length, users.map(u => u.id));
}
return users;
});
}
/**
* Get the private archived threads in a channel.
* @param channelID The ID of the channel to get the archived threads from.
* @param options The options for getting the archived threads.
* @caching This method **may** cache its result. The result will not be cached if the guild is not cached.
* @caches {@link Guild#threads | Guild#threads}
*/
async getPrivateArchivedThreads(channelID, options) {
options = this._manager.client.util._freeze(options);
const query = new QueryBuilder_1.default();
query.setIfPresent("before", options?.before);
query.setIfPresent("limit", options?.limit);
return this._manager.authRequest({
method: "GET",
path: Routes.CHANNEL_PRIVATE_ARCHIVED_THREADS(channelID),
query
}).then(data => ({
hasMore: data.has_more,
members: data.members.map(m => ({
flags: m.flags,
id: m.id,
joinTimestamp: new Date(m.join_timestamp),
userID: m.user_id
})),
threads: data.threads.map(d => this._manager.client.util.updateThread(d))
}));
}
/**
* Get the private joined archived threads in a channel.
* @param channelID The ID of the channel to get the archived threads from.
* @param options The options for getting the archived threads.
* @caching This method **may** cache its result. The result will not be cached if the guild is not cached.
* @caches {@link Guild#threads | Guild#threads}
*/
async getPrivateJoinedArchivedThreads(channelID, options) {
options = this._manager.client.util._freeze(options);
const query = new QueryBuilder_1.default();
query.setIfPresent("before", options?.before);
query.setIfPresent("limit", options?.limit);
return this._manager.authRequest({
method: "GET",
path: Routes.CHANNEL_JOINED_PRIVATE_ARCHIVED_THREADS(channelID),
query
}).then(data => ({
hasMore: data.has_more,
members: data.members.map(m => ({
flags: m.flags,
id: m.id,
joinTimestamp: new Date(m.join_timestamp),
userID: m.user_id
})),
threads: data.threads.map(d => this._manager.client.util.updateThread(d))
}));
}
/**
* Get the public archived threads in a channel.
* @param channelID The ID of the channel to get the archived threads from.
* @param options The options for getting the archived threads.
* @caching This method **may** cache its result. The result will not be cached if the guild is not cached.
* @caches {@link Guild#threads | Guild#threads}
*/
async getPublicArchivedThreads(channelID, options) {
options = this._manager.client.util._freeze(options);
const query = new QueryBuilder_1.default();
query.setIfPresent("before", options?.before);
query.setIfPresent("limit", options?.limit);
return this._manager.authRequest({
method: "GET",
path: Routes.CHANNEL_PUBLIC_ARCHIVED_THREADS(channelID),
query
}).then(data => ({
hasMore: data.has_more,
members: data.members.map(m => ({
flags: m.flags,
id: m.id,
joinTimestamp: new Date(m.join_timestamp),
userID: m.user_id
})),
threads: data.threads.map(d => this._manager.client.util.updateThread(d))
}));
}
/**
* Get the users who reacted with a specific emoji on a message.
* @param channelID The ID of the channel the message is in.
* @param messageID The ID of the message to get reactions from.
* @param emoji The reaction to remove from the message. `name:id` for custom emojis, and the unicode codepoint for default emojis.
* @param options The options for getting the reactions.
* @caching This method **does not** cache its result.
*/
async getReactions(channelID, messageID, emoji, options) {
options = this._manager.client.util._freeze(options);
const _getReactions = async (_options) => {
const query = new QueryBuilder_1.default();
query.setIfPresent("after", _options?.after);
query.setIfPresent("limit", _options?.limit);
query.setIfPresent("type", options?.type);
return this._manager.authRequest({
method: "GET",
path: Routes.CHANNEL_REACTION(channelID, messageID, emoji),
query
}).then(data => data.map(d => this._manager.client.users.update(d)));
};
const limit = options?.limit ?? 100;
let after = options?.after;
let reactions = [];
while (reactions.length < limit) {
const limitLeft = limit - reactions.length;
const limitToFetch = Math.min(limitLeft, 100);
this._manager.client.emit("debug", `Getting ${limitLeft} more ${emoji} reactions for message ${messageID} on ${channelID}: ${after ?? ""}`);
const reactionsChunk = await _getReactions({
after,
limit: limitToFetch
});
if (reactionsChunk.length === 0) {
break;
}
reactions = reactions.concat(reactionsChunk);
after = reactionsChunk.at(-1).id;
if (reactionsChunk.length < 100) {
break;
}
}
return reactions;
}
/**
* Get the stage instance associated with a channel.
* @param channelID The ID of the channel to get the stage instance on.
* @caching This method **does not** cache its result.
*/
async getStageInstance(channelID) {
return this._manager.authRequest({
method: "GET",
path: Routes.STAGE_INSTANCE(channelID)
}).then(data => new StageInstance_1.default(data, this._manager.client));
}
/**
* Get a thread member.
* @param channelID The ID of the thread.
* @param userID The ID of the user to get the thread member of.
* @caching This method **does not** cache its result.
*/
async getThreadMember(channelID, userID) {
return this._manager.authRequest({
method: "GET",
path: Routes.CHANNEL_THREAD_MEMBER(channelID, userID)
}).then(data => ({
flags: data.flags,
id: data.id,
joinTimestamp: new Date(data.join_timestamp),
userID: data.user_id
}));
}
/**
* Get the members of a thread.
* @param channelID The ID of the thread.
* @param options The options for getting the thread members.
* @caching This method **does not** cache its result.
*/
async getThreadMembers(channelID, options) {
options = this._manager.client.util._freeze(options);
const query = new QueryBuilder_1.default();
query.setIfPresent("after", options?.after);
query.setIfPresent("limit", options?.limit);
query.setIfPresent("with_member", options?.withMember);
return this._manager.authRequest({
method: "GET",
path: Routes.CHANNEL_THREAD_MEMBERS(channelID),
query
}).then(data => data.map(d => {
// eslint-disable-next-line @typescript-eslint/dot-notation
const guild = this._manager.client.getChannel(channelID)?.["_cachedGuild"];
const member = guild && options?.withMember ? guild.members.update(d.member, guild.id) : undefined;
return {
flags: d.flags,
id: d.id,
joinTimestamp: new Date(d.join_timestamp),
member,
userID: d.user_id
};
}));
}
/** @deprecated Get the list of usable voice regions. Moved to `misc`. */
async getVoiceRegions() {
return this._manager.authRequest({
method: "GET",
path: Routes.VOICE_REGIONS
});
}
/**
* Join a thread.
* @param channelID The ID of the thread to join.
* @caching This method **does not** cache its result.
*/
async joinThread(channelID) {
await this._manager.authRequest({
method: "PUT",
path: Routes.CHANNEL_THREAD_MEMBER(channelID, "@me")
});
}
/**
* Leave a thread.
* @param channelID The ID of the thread to leave.
* @caching This method **does not** cache its result.
*/
async leaveThread(channelID) {
await this._manager.authRequest({
method: "DELETE",
path: Routes.CHANNEL_THREAD_MEMBER(channelID, "@me")
});
}
/**
* Pin a message in a channel.
* @param channelID The ID of the channel to pin the message in.
* @param messageID The ID of the message to pin.
* @param reason The reason for pinning the message.
* @caching This method **does not** cache its result.
*/
async pinMessage(channelID, messageID, reason) {
await this._manager.authRequest({
method: "PUT",
path: Routes.CHANNEL_PINNED_MESSAGE(channelID, messageID),
reason
});
}
/**
* Purge an amount of messages from a channel.
* @param channelID The ID of the channel to purge.
* @param options The options to purge. `before`, `after`, and `around `All are mutually exclusive.
* @caching This method **does not** cache its result.
*/
async purgeMessages(channelID, options) {
options = this._manager.client.util._freeze(options);
const filter = (message) => {
if (message.timestamp.getTime() < Date.now() - 1209600000) {
return "break";
}
return options?.filter?.(message) ?? true;
};
let chosenOption;
if (options.after) {
chosenOption = "after";
}
else if (options.around) {
chosenOption = "around";
}
else {
chosenOption = "before";
}
if (chosenOption === "around" || options.limit <= 100) {
const messages = await this.getMessages(channelID, {
limit: options.limit,
[chosenOption]: options[chosenOption]
});
for (const message of Array.from(messages)) {
const f = filter(message);
if (f === false) {
messages.splice(messages.indexOf(message), 1);
}
if (f === "break") {
messages.splice(messages.indexOf(message));
break;
}
}
return this.deleteMessages(channelID, messages.map(message => message.id), options.reason);
}
const it = this.getMessagesIterator(channelID, {
after: options.after,
before: options.before,
limit: options.limit,
filter
});
let deleted = 0;
for await (const messages of it) {
deleted += await this.deleteMessages(channelID, messages.map(message => message.id), options.reason);
}
return deleted;
}
/**
* Remove a user from the group channel.
* @param groupID The ID of the group to remove the user from.
* @param userID The ID of the user to remove.
* @caching This method **does not** cache its result.
*/
async removeGroupRecipient(groupID, userID) {
await this._manager.authRequest({
method: "DELETE",
path: Routes.GROUP_RECIPIENT(groupID, userID)
});
}
/**
* Remove a member from a thread.
* @param channelID The ID of the thread to remove them from.
* @param userID The ID of the user to remove from the thread.
* @caching This method **does not** cache its result.
*/
async removeThreadMember(channelID, userID) {
await this._manager.authRequest({
method: "DELETE",
path: Routes.CHANNEL_THREAD_MEMBER(channelID, userID)
});
}
/**
* Send a sound from the soundboard to the channel where the user is connected.
* @param channelID The ID of the channel to send the soundboard sound to.
* @param soundID The ID of the soundboard sound to send.
* @param sourceGuildID The ID of the guild the soundboard sound is from.
* @caching This method **does not** cache its result.
*/
async sendSoundboardSound(channelID, options) {
options = this._manager.client.util._freeze(options);
await this._manager.authRequest({
method: "POST",
path: Routes.SEND_SOUNDBOARD_SOUND(channelID),
json: { sound_id: options.soundID, source_guild_id: options.sourceGuildID }
});
}
/**
* Show a typing indicator in a channel. How long users see this varies from client to client.
* @param channelID The ID of the channel to show the typing indicator in.
* @caching This method **does not** cache its result.
*/
async sendTyping(channelID) {
await this._manager.authRequest({
method: "POST",
path: Routes.CHANNEL_TYPING(channelID)
});
}
/**
* Set a voice status in a channel.
* @param channelID The ID of the channel to set the voice status in.
* @param status The voice status to set.
*/
async setVoiceStatus(channelID, status) {
await this._manager.authRequest({
method: "PUT",
path: Routes.VOICE_STATUS(channelID),
json: { status }
});
}
/**
* Create a thread from an existing message.
* @param channelID The ID of the channel to create the thread in.
* @param messageID The ID of the message to create the thread from.
* @param options The options for starting the thread.
* @caching This method **may** cache its result. The result will not be cached if the guild is not cached.
* @caches {@link Guild#threads | Guild#threads}
*/
async startThreadFromMessage(channelID, messageID, options) {
options = this._manager.client.util._freeze(options);
return this._manager.authRequest({
method: "POST",
path: Routes.CHANNEL_MESSAGE_THREADS(channelID, messageID),
json: {
auto_archive_duration: options.autoArchiveDuration,
name: options.name,
rate_limit_per_user: options.rateLimitPerUser
},
reason: options.reason
}).then(data => this._manager.client.util.updateThread(data));
}
/**
* Create a thread in a thread only channel (forum & media).
* @param channelID The ID of the channel to start the thread in.
* @param options The options for starting the thread.
* @caching This method **may** cache its result. The result will not be cached if the guild is not cached.
* @caches {@link Guild#threads | Guild#threads}
*/
async startThreadInThreadOnlyChannel(channelID, options) {
options = this._manager.client.util._freeze(options);
return this._manager.authRequest({
method: "POST",
path: Routes.CHANNEL_THREADS(channelID),
json: {
auto_archive_duration: options.autoArchiveDuration,
message: {
allowed_mentions: this._manager.client.util.formatAllowedMentions(options.message.allowedMentions),
attachments: options.message.attachments,
components: options.message.components ? this._manager.client.util.componentsToRaw(options.message.components) : undefined,
content: options.message.content,
embeds: options.message.embeds ? this._manager.client.util.embedsToRaw(options.message.embeds) : undefined,
flags: options.message.flags,
sticker_ids: options.message.stickerIDs
},
name: options.name,
rate_limit_per_user: options.rateLimitPerUser,
applied_tags: options.appliedTags
},
reason: options.reason,
files: options.message.files
}).then(data => this._manager.client.util.updateThread(data));
}
/**
* Create a thread without an existing message.
* @param channelID The ID of the channel to start the thread in.
* @param options The options for starting the thread.
* @caching This method **may** cache its result. The result will not be cached if the guild is not cached.
* @caches {@link Guild#threads | Guild#threads}
*/
async startThreadWithoutMessage(channelID, options) {
options = this._manager.client.util._freeze(options);
return this._manager.authRequest({
method: "POST",
path: Routes.CHANNEL_THREADS(channelID),
json: {
auto_archive_duration: options.autoArchiveDuration,
invitable: options.invitable,
name: options.name,
rate_limit_per_user: options.rateLimitPerUser,
type: options.type
},
reason: options.reason
}).then(data => this._manager.client.util.updateThread(data));
}
/**
* Unpin a message in a channel.
* @param channelID The ID of the channel to unpin the message in.
* @param messageID The ID of the message to unpin.
* @param reason The reason for unpinning the message.
* @caching This method **does not** cache its result.
*/
async unpinMessage(channelID, messageID, reason) {
await this._manager.authRequest({
method: "DELETE",
path: Routes.CHANNEL_PINNED_MESSAGE(channelID, messageID),
reason
});
}
}
exports.default = Channels;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ2hhbm5lbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cm