From d78a10ed760b2f5faa68ad13aff6ab8fe98fc134 Mon Sep 17 00:00:00 2001
From: March 7th <71698422+aiko-chan-ai@users.noreply.github.com>
Date: Tue, 12 Apr 2022 20:46:25 +0700
Subject: [PATCH] 1.3.4
Get interaction commands using gateway
---
DOCUMENT.md | 1 +
Document/API.md | 68 +
Document/Message.md | 25 +
package.json | 2 +-
src/client/actions/InteractionCreate.js | 2 +-
.../GUILD_APPLICATION_COMMANDS_UPDATE.js | 10 +
.../handlers/GUILD_MEMBER_LIST_UPDATE.js | 1 +
.../websocket/handlers/INTERACTION_CREATE.js | 4 +-
.../websocket/handlers/INTERACTION_FAILED.js | 6 +
.../websocket/handlers/INTERACTION_SUCCESS.js | 6 +
src/client/websocket/handlers/index.js | 6 +
src/managers/ApplicationCommandManager.js | 5 +-
src/structures/Guild.js | 3019 +++++++++--------
src/util/Constants.js | 2 +
typings/index.d.ts | 170 +-
15 files changed, 1791 insertions(+), 1536 deletions(-)
create mode 100644 Document/API.md
create mode 100644 src/client/websocket/handlers/GUILD_APPLICATION_COMMANDS_UPDATE.js
create mode 100644 src/client/websocket/handlers/INTERACTION_FAILED.js
create mode 100644 src/client/websocket/handlers/INTERACTION_SUCCESS.js
diff --git a/DOCUMENT.md b/DOCUMENT.md
index 55465bf..8ef3476 100644
--- a/DOCUMENT.md
+++ b/DOCUMENT.md
@@ -9,6 +9,7 @@
- [Guild](https://github.com/aiko-chan-ai/discord.js-selfbot-v13/blob/main/Document/Guild.md)
- [Message](https://github.com/aiko-chan-ai/discord.js-selfbot-v13/blob/main/Document/Message.md)
- [User](https://github.com/aiko-chan-ai/discord.js-selfbot-v13/blob/main/Document/User.md)
+- [API](https://github.com/aiko-chan-ai/discord.js-selfbot-v13/blob/main/Document/API.md)
## More features
diff --git a/Document/API.md b/Document/API.md
new file mode 100644
index 00000000..c6fd643
--- /dev/null
+++ b/Document/API.md
@@ -0,0 +1,68 @@
+# Extending Discord.js-selfbot-v13
+> `credit: Discum`
+
+How to add extra API wraps to Discord.js-selfbot-v13?
+# Table of Contents
+- [HTTP APIs](#HTTP-APIs)
+- [Gateway APIs](#Gateway-APIs)
+
+### HTTP APIs:
+
+```js
+URL example:
+'https://discord.com/api/v9/users/@me'
+const url = client.api.users['@me'];
+/* Method: GET | POST | PUT | PATCH | DELETE */
+```
+
+
+###### GET:
+```js
+await client.api.users['@me'].get({ versioned: true });
+/* Request: https://discord.com/api/v9/users/@me */
+await client.api.users['@me'].get({ versioned: false });
+/* Request: https://discord.com/api/users/@me */
+```
+###### POST:
+```js
+await client.api.channels[channel.id].messages.post({ versioned: true, data: {}, files: [] });
+/* Request: https://discord.com/api/v9/channels/{channel.id}/messages */
+```
+###### PUT:
+```js
+await client.api
+ .guilds(guild.id)
+ .bans(user.id)
+ .put({
+ versioned: true,
+ data: {},
+ });
+/* Request: https://discord.com/api/guilds/{guild.id}/bans/{user.id} */
+```
+###### PATCH:
+```js
+await client.api.users['@me'].patch({ versioned: true, data: {} });
+/* Request: https://discord.com/api/v9/users/@me */
+```
+###### DELETE:
+```js
+await client.api.hypesquad.online.delete({ versioned: true });
+/* Request: https://discord.com/api/v9/hypesquad/online */
+```
+### Gateway APIs
+You need to send data to the port and listen for an event. This is quite complicated but if you want to use an existing event, here are the instructions
+
+###### SEND:
+```js
+const { Constants } = require('discord.js-selfbot-v13');
+// Global gateway (example update presence)
+client.ws.broadcast({
+ op: Constants.Opcodes.STATUS_UPDATE,
+ d: {},
+});
+// Guild gateway (example get all members)
+guild.shard.send({
+ op: Constants.Opcodes.REQUEST_GUILD_MEMBERS,
+ d: {},
+});
+```
\ No newline at end of file
diff --git a/Document/Message.md b/Document/Message.md
index aa59b49..459f8be 100644
--- a/Document/Message.md
+++ b/Document/Message.md
@@ -4,6 +4,30 @@
## Interaction
+Fetch Commands data
+
+```js
+/* Save to cache */
+// In guild (Opcode 24)
+await guild.searchInteraction(
+ {
+ limit: 100, // default: 1
+ query: 'ping', // optional
+ type: 'CHAT_INPUT', // default: 'CHAT_INPUT'
+ offset: 0, // default: 0
+ botID: ['botid1', 'botid2'], // optional
+ }
+);
+// Fetch all commands (1 bot) Shouldn't be used
+await bot.applications.fetch(
+ {
+ guildId: 'guild id to search', // optional
+ force: false, // Using cache or createDMs to bot
+ }
+);
+```
+
+
Button Click
```js
@@ -57,6 +81,7 @@ await message.contextMenu(botID, commandName);
> In this way, all Slash commands can be obtained
- I will try to find another way to not need to create DMs with Bot anymore
- Credit: [Here](https://www.reddit.com/r/Discord_selfbots/comments/tczprx/discum_help_creating_a_selfbot_that_can_do_ping/)
+- Update: Now to get more secure interaction commands you need to use guild.searchInteraction() (using gateway)
## MessageEmbed ?
diff --git a/package.json b/package.json
index ac0f646..ddede6a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "discord.js-selfbot-v13",
- "version": "1.3.3",
+ "version": "1.3.4",
"description": "A unofficial discord.js fork for creating selfbots [Based on discord.js v13]",
"main": "./src/index.js",
"types": "./typings/index.d.ts",
diff --git a/src/client/actions/InteractionCreate.js b/src/client/actions/InteractionCreate.js
index 04774a6..94be343 100644
--- a/src/client/actions/InteractionCreate.js
+++ b/src/client/actions/InteractionCreate.js
@@ -60,7 +60,7 @@ class InteractionCreateAction extends Action {
InteractionType = AutocompleteInteraction;
break;
default:
- client.emit(Events.DEBUG, `[INTERACTION] Received interaction with unknown type: ${data.type}`);
+ client.emit(Events.DEBUG, `[INTERACTION] Received [BOT] / Send (Selfbot) interactionID ${data.id} with unknown type: ${data.type}`);
return;
}
diff --git a/src/client/websocket/handlers/GUILD_APPLICATION_COMMANDS_UPDATE.js b/src/client/websocket/handlers/GUILD_APPLICATION_COMMANDS_UPDATE.js
new file mode 100644
index 00000000..e4d64ad
--- /dev/null
+++ b/src/client/websocket/handlers/GUILD_APPLICATION_COMMANDS_UPDATE.js
@@ -0,0 +1,10 @@
+'use strict';
+
+module.exports = (client, { d: data }) => {
+ if (!data.application_commands[0]) return;
+ for (const command of data.application_commands) {
+ const user = client.users.cache.get(command.application_id);
+ if (!user) continue;
+ user.applications._add(command, true);
+ };
+};
\ No newline at end of file
diff --git a/src/client/websocket/handlers/GUILD_MEMBER_LIST_UPDATE.js b/src/client/websocket/handlers/GUILD_MEMBER_LIST_UPDATE.js
index 950678e..80687d2 100644
--- a/src/client/websocket/handlers/GUILD_MEMBER_LIST_UPDATE.js
+++ b/src/client/websocket/handlers/GUILD_MEMBER_LIST_UPDATE.js
@@ -9,6 +9,7 @@ module.exports = (client, { d: data }) => {
const guild = client.guilds.cache.get(data.guild_id);
if (!guild) return;
const members = new Collection();
+ // Get Member from side Discord Channel (online counting if large server)
for (const object of data.ops) {
if (object.op == 'SYNC') {
for (const member_ of object.items) {
diff --git a/src/client/websocket/handlers/INTERACTION_CREATE.js b/src/client/websocket/handlers/INTERACTION_CREATE.js
index 5bf30fc..86913ac 100644
--- a/src/client/websocket/handlers/INTERACTION_CREATE.js
+++ b/src/client/websocket/handlers/INTERACTION_CREATE.js
@@ -1,5 +1,7 @@
'use strict';
+const { Events } = require('../../../util/Constants');
module.exports = (client, packet) => {
- client.actions.InteractionCreate.handle(packet.d);
+ if (client.user.bot) client.actions.InteractionCreate.handle(packet.d);
+ else client.emit(Events.INTERACTION_CREATE, packet.d);
};
diff --git a/src/client/websocket/handlers/INTERACTION_FAILED.js b/src/client/websocket/handlers/INTERACTION_FAILED.js
new file mode 100644
index 00000000..9a9f086
--- /dev/null
+++ b/src/client/websocket/handlers/INTERACTION_FAILED.js
@@ -0,0 +1,6 @@
+'use strict';
+const { Events } = require('../../../util/Constants');
+
+module.exports = (client, { d: data }) => {
+ client.emit(Events.INTERACTION_FAILED, data);
+};
diff --git a/src/client/websocket/handlers/INTERACTION_SUCCESS.js b/src/client/websocket/handlers/INTERACTION_SUCCESS.js
new file mode 100644
index 00000000..5acff20
--- /dev/null
+++ b/src/client/websocket/handlers/INTERACTION_SUCCESS.js
@@ -0,0 +1,6 @@
+'use strict';
+const { Events } = require('../../../util/Constants');
+
+module.exports = (client, { d: data }) => {
+ client.emit(Events.INTERACTION_SUCCESS, data);
+};
\ No newline at end of file
diff --git a/src/client/websocket/handlers/index.js b/src/client/websocket/handlers/index.js
index bdad4f8..c5743de 100644
--- a/src/client/websocket/handlers/index.js
+++ b/src/client/websocket/handlers/index.js
@@ -18,6 +18,10 @@ const handlers = Object.fromEntries([
['GUILD_MEMBER_UPDATE', require('./GUILD_MEMBER_UPDATE')],
['GUILD_MEMBERS_CHUNK', require('./GUILD_MEMBERS_CHUNK')],
['GUILD_MEMBER_LIST_UPDATE', require('./GUILD_MEMBER_LIST_UPDATE.js')],
+ [
+ 'GUILD_APPLICATION_COMMANDS_UPDATE',
+ require('./GUILD_APPLICATION_COMMANDS_UPDATE.js'),
+ ],
['GUILD_INTEGRATIONS_UPDATE', require('./GUILD_INTEGRATIONS_UPDATE')],
['GUILD_ROLE_CREATE', require('./GUILD_ROLE_CREATE')],
['GUILD_ROLE_DELETE', require('./GUILD_ROLE_DELETE')],
@@ -50,6 +54,8 @@ const handlers = Object.fromEntries([
['VOICE_SERVER_UPDATE', require('./VOICE_SERVER_UPDATE')],
['WEBHOOKS_UPDATE', require('./WEBHOOKS_UPDATE')],
['INTERACTION_CREATE', require('./INTERACTION_CREATE')],
+ ['INTERACTION_SUCCESS', require('./INTERACTION_SUCCESS')],
+ ['INTERACTION_FAILED', require('./INTERACTION_FAILED')],
['STAGE_INSTANCE_CREATE', require('./STAGE_INSTANCE_CREATE')],
['STAGE_INSTANCE_UPDATE', require('./STAGE_INSTANCE_UPDATE')],
['STAGE_INSTANCE_DELETE', require('./STAGE_INSTANCE_DELETE')],
diff --git a/src/managers/ApplicationCommandManager.js b/src/managers/ApplicationCommandManager.js
index 6aeeedc..df93e25 100644
--- a/src/managers/ApplicationCommandManager.js
+++ b/src/managers/ApplicationCommandManager.js
@@ -84,7 +84,7 @@ class ApplicationCommandManager extends CachedManager {
* .catch(console.error);
*/
async fetch(id, { guildId, cache = true, force = false } = {}) {
- await this.user.createDM().catch(() => {});
+ // change from user.createDM to opcode (risky action)
if (typeof id === 'object') {
({ guildId, cache = true } = id);
} else if (id) {
@@ -92,10 +92,11 @@ class ApplicationCommandManager extends CachedManager {
const existing = this.cache.get(id);
if (existing) return existing;
}
+ await this.user.createDM().catch(() => {});
const command = await this.commandPath({ id, guildId }).get();
return this._add(command, cache);
}
-
+ await this.user.createDM().catch(() => {});
const data = await this.commandPath({ guildId }).get();
return data.reduce((coll, command) => coll.set(command.id, this._add(command, cache, guildId)), new Collection());
}
diff --git a/src/structures/Guild.js b/src/structures/Guild.js
index 871d44e..52718b1 100644
--- a/src/structures/Guild.js
+++ b/src/structures/Guild.js
@@ -31,6 +31,7 @@ const {
Status,
MFALevels,
PremiumTiers,
+ Opcodes,
} = require('../util/Constants');
const DataResolver = require('../util/DataResolver');
const SystemChannelFlags = require('../util/SystemChannelFlags');
@@ -54,1468 +55,1562 @@ const deletedGuilds = new WeakSet();
* @extends {AnonymousGuild}
*/
class Guild extends AnonymousGuild {
- constructor(client, data) {
- super(client, data, false);
-
- /**
- * A manager of the members belonging to this guild
- * @type {GuildMemberManager}
- */
- this.members = new GuildMemberManager(this);
-
- /**
- * A manager of the channels belonging to this guild
- * @type {GuildChannelManager}
- */
- this.channels = new GuildChannelManager(this);
-
- /**
- * A manager of the bans belonging to this guild
- * @type {GuildBanManager}
- */
- this.bans = new GuildBanManager(this);
-
- /**
- * A manager of the roles belonging to this guild
- * @type {RoleManager}
- */
- this.roles = new RoleManager(this);
-
- /**
- * A manager of the presences belonging to this guild
- * @type {PresenceManager}
- */
- this.presences = new PresenceManager(this.client);
-
- /**
- * A manager of the voice states of this guild
- * @type {VoiceStateManager}
- */
- this.voiceStates = new VoiceStateManager(this);
-
- /**
- * A manager of the stage instances of this guild
- * @type {StageInstanceManager}
- */
- this.stageInstances = new StageInstanceManager(this);
-
- /**
- * A manager of the invites of this guild
- * @type {GuildInviteManager}
- */
- this.invites = new GuildInviteManager(this);
-
- /**
- * A manager of the scheduled events of this guild
- * @type {GuildScheduledEventManager}
- */
- this.scheduledEvents = new GuildScheduledEventManager(this);
-
- if (!data) return;
- if (data.unavailable) {
- /**
- * Whether the guild is available to access. If it is not available, it indicates a server outage
- * @type {boolean}
- */
- this.available = false;
- } else {
- this._patch(data);
- if (!data.channels) this.available = false;
- }
-
- /**
- * The id of the shard this Guild belongs to.
- * @type {number}
- */
- this.shardId = data.shardId;
-
- this.disableDM = false;
- }
-
- /**
- * Whether or not the structure has been deleted
- * @type {boolean}
- * @deprecated This will be removed in the next major version, see https://github.com/discordjs/discord.js/issues/7091
- */
- get deleted() {
- if (!deprecationEmittedForDeleted) {
- deprecationEmittedForDeleted = true;
- process.emitWarning(
- 'Guild#deleted is deprecated, see https://github.com/discordjs/discord.js/issues/7091.',
- 'DeprecationWarning',
- );
- }
-
- return deletedGuilds.has(this);
- }
-
- set deleted(value) {
- if (!deprecationEmittedForDeleted) {
- deprecationEmittedForDeleted = true;
- process.emitWarning(
- 'Guild#deleted is deprecated, see https://github.com/discordjs/discord.js/issues/7091.',
- 'DeprecationWarning',
- );
- }
-
- if (value) deletedGuilds.add(this);
- else deletedGuilds.delete(this);
- }
-
- /**
- * The Shard this Guild belongs to.
- * @type {WebSocketShard}
- * @readonly
- */
- get shard() {
- return this.client.ws.shards.get(this.shardId);
- }
-
- _patch(data) {
- super._patch(data);
- this.id = data.id;
- if ('name' in data) this.name = data.name;
- if ('icon' in data) this.icon = data.icon;
- if ('unavailable' in data) {
- this.available = !data.unavailable;
- } else {
- this.available ??= true;
- }
-
- if ('discovery_splash' in data) {
- /**
- * The hash of the guild discovery splash image
- * @type {?string}
- */
- this.discoverySplash = data.discovery_splash;
- }
-
- if ('member_count' in data) {
- /**
- * The full amount of members in this guild
- * @type {number}
- */
- this.memberCount = data.member_count;
- }
-
- if ('large' in data) {
- /**
- * Whether the guild is "large" (has more than {@link WebsocketOptions large_threshold} members, 50 by default)
- * @type {boolean}
- */
- this.large = Boolean(data.large);
- }
-
- if ('premium_progress_bar_enabled' in data) {
- /**
- * Whether this guild has its premium (boost) progress bar enabled
- * @type {boolean}
- */
- this.premiumProgressBarEnabled = data.premium_progress_bar_enabled;
- }
-
- /**
- * An array of enabled guild features, here are the possible values:
- * * ANIMATED_ICON
- * * BANNER
- * * COMMERCE
- * * COMMUNITY
- * * DISCOVERABLE
- * * FEATURABLE
- * * INVITE_SPLASH
- * * MEMBER_VERIFICATION_GATE_ENABLED
- * * NEWS
- * * PARTNERED
- * * PREVIEW_ENABLED
- * * VANITY_URL
- * * VERIFIED
- * * VIP_REGIONS
- * * WELCOME_SCREEN_ENABLED
- * * TICKETED_EVENTS_ENABLED
- * * MONETIZATION_ENABLED
- * * MORE_STICKERS
- * * THREE_DAY_THREAD_ARCHIVE
- * * SEVEN_DAY_THREAD_ARCHIVE
- * * PRIVATE_THREADS
- * * ROLE_ICONS
- * @typedef {string} Features
- * @see {@link https://discord.com/developers/docs/resources/guild#guild-object-guild-features}
- */
-
- if ('application_id' in data) {
- /**
- * The id of the application that created this guild (if applicable)
- * @type {?Snowflake}
- */
- this.applicationId = data.application_id;
- }
-
- if ('afk_timeout' in data) {
- /**
- * The time in seconds before a user is counted as "away from keyboard"
- * @type {?number}
- */
- this.afkTimeout = data.afk_timeout;
- }
-
- if ('afk_channel_id' in data) {
- /**
- * The id of the voice channel where AFK members are moved
- * @type {?Snowflake}
- */
- this.afkChannelId = data.afk_channel_id;
- }
-
- if ('system_channel_id' in data) {
- /**
- * The system channel's id
- * @type {?Snowflake}
- */
- this.systemChannelId = data.system_channel_id;
- }
-
- if ('premium_tier' in data) {
- /**
- * The premium tier of this guild
- * @type {PremiumTier}
- */
- this.premiumTier = PremiumTiers[data.premium_tier];
- }
-
- if ('premium_subscription_count' in data) {
- /**
- * The total number of boosts for this server
- * @type {?number}
- */
- this.premiumSubscriptionCount = data.premium_subscription_count;
- }
-
- if ('widget_enabled' in data) {
- /**
- * Whether widget images are enabled on this guild
- * @type {?boolean}
- */
- this.widgetEnabled = data.widget_enabled;
- }
-
- if ('widget_channel_id' in data) {
- /**
- * The widget channel's id, if enabled
- * @type {?string}
- */
- this.widgetChannelId = data.widget_channel_id;
- }
-
- if ('explicit_content_filter' in data) {
- /**
- * The explicit content filter level of the guild
- * @type {ExplicitContentFilterLevel}
- */
- this.explicitContentFilter = ExplicitContentFilterLevels[data.explicit_content_filter];
- }
-
- if ('mfa_level' in data) {
- /**
- * The required MFA level for this guild
- * @type {MFALevel}
- */
- this.mfaLevel = MFALevels[data.mfa_level];
- }
-
- if ('joined_at' in data) {
- /**
- * The timestamp the client user joined the guild at
- * @type {number}
- */
- this.joinedTimestamp = new Date(data.joined_at).getTime();
- }
-
- if ('default_message_notifications' in data) {
- /**
- * The default message notification level of the guild
- * @type {DefaultMessageNotificationLevel}
- */
- this.defaultMessageNotifications = DefaultMessageNotificationLevels[data.default_message_notifications];
- }
-
- if ('system_channel_flags' in data) {
- /**
- * The value set for the guild's system channel flags
- * @type {Readonly}
- */
- this.systemChannelFlags = new SystemChannelFlags(data.system_channel_flags).freeze();
- }
-
- if ('max_members' in data) {
- /**
- * The maximum amount of members the guild can have
- * @type {?number}
- */
- this.maximumMembers = data.max_members;
- } else {
- this.maximumMembers ??= null;
- }
-
- if ('max_presences' in data) {
- /**
- * The maximum amount of presences the guild can have
- * You will need to fetch the guild using {@link Guild#fetch} if you want to receive this parameter
- * @type {?number}
- */
- this.maximumPresences = data.max_presences ?? 25_000;
- } else {
- this.maximumPresences ??= null;
- }
-
- if ('approximate_member_count' in data) {
- /**
- * The approximate amount of members the guild has
- * You will need to fetch the guild using {@link Guild#fetch} if you want to receive this parameter
- * @type {?number}
- */
- this.approximateMemberCount = data.approximate_member_count;
- } else {
- this.approximateMemberCount ??= null;
- }
-
- if ('approximate_presence_count' in data) {
- /**
- * The approximate amount of presences the guild has
- * You will need to fetch the guild using {@link Guild#fetch} if you want to receive this parameter
- * @type {?number}
- */
- this.approximatePresenceCount = data.approximate_presence_count;
- } else {
- this.approximatePresenceCount ??= null;
- }
-
- /**
- * The use count of the vanity URL code of the guild, if any
- * You will need to fetch this parameter using {@link Guild#fetchVanityData} if you want to receive it
- * @type {?number}
- */
- this.vanityURLUses ??= null;
-
- if ('rules_channel_id' in data) {
- /**
- * The rules channel's id for the guild
- * @type {?Snowflake}
- */
- this.rulesChannelId = data.rules_channel_id;
- }
-
- if ('public_updates_channel_id' in data) {
- /**
- * The community updates channel's id for the guild
- * @type {?Snowflake}
- */
- this.publicUpdatesChannelId = data.public_updates_channel_id;
- }
-
- if ('preferred_locale' in data) {
- /**
- * The preferred locale of the guild, defaults to `en-US`
- * @type {string}
- * @see {@link https://discord.com/developers/docs/dispatch/field-values#predefined-field-values-accepted-locales}
- */
- this.preferredLocale = data.preferred_locale;
- }
-
- if (data.channels) {
- this.channels.cache.clear();
- for (const rawChannel of data.channels) {
- this.client.channels._add(rawChannel, this);
- }
- }
-
- if (data.threads) {
- for (const rawThread of data.threads) {
- this.client.channels._add(rawThread, this);
- }
- }
-
- if (data.roles) {
- this.roles.cache.clear();
- for (const role of data.roles) this.roles._add(role);
- }
-
- if (data.members) {
- this.members.cache.clear();
- for (const guildUser of data.members) this.members._add(guildUser);
- }
-
- if ('owner_id' in data) {
- /**
- * The user id of this guild's owner
- * @type {Snowflake}
- */
- this.ownerId = data.owner_id;
- }
-
- if (data.presences) {
- for (const presence of data.presences) {
- this.presences._add(Object.assign(presence, { guild: this }));
- }
- }
-
- if (data.stage_instances) {
- this.stageInstances.cache.clear();
- for (const stageInstance of data.stage_instances) {
- this.stageInstances._add(stageInstance);
- }
- }
-
- if (data.guild_scheduled_events) {
- this.scheduledEvents.cache.clear();
- for (const scheduledEvent of data.guild_scheduled_events) {
- this.scheduledEvents._add(scheduledEvent);
- }
- }
-
- if (data.voice_states) {
- this.voiceStates.cache.clear();
- for (const voiceState of data.voice_states) {
- this.voiceStates._add(voiceState);
- }
- }
-
- if (!this.emojis) {
- /**
- * A manager of the emojis belonging to this guild
- * @type {GuildEmojiManager}
- */
- this.emojis = new GuildEmojiManager(this);
- if (data.emojis) for (const emoji of data.emojis) this.emojis._add(emoji);
- } else if (data.emojis) {
- this.client.actions.GuildEmojisUpdate.handle({
- guild_id: this.id,
- emojis: data.emojis,
- });
- }
-
- if (!this.stickers) {
- /**
- * A manager of the stickers belonging to this guild
- * @type {GuildStickerManager}
- */
- this.stickers = new GuildStickerManager(this);
- if (data.stickers) for (const sticker of data.stickers) this.stickers._add(sticker);
- } else if (data.stickers) {
- this.client.actions.GuildStickersUpdate.handle({
- guild_id: this.id,
- stickers: data.stickers,
- });
- }
- }
-
- /**
- * The time the client user joined the guild
- * @type {Date}
- * @readonly
- */
- get joinedAt() {
- return new Date(this.joinedTimestamp);
- }
-
- /**
- * The URL to this guild's discovery splash image.
- * @param {StaticImageURLOptions} [options={}] Options for the Image URL
- * @returns {?string}
- */
- discoverySplashURL({ format, size } = {}) {
- return this.discoverySplash && this.client.rest.cdn.DiscoverySplash(this.id, this.discoverySplash, format, size);
- }
-
- /**
- * Fetches the owner of the guild.
- * If the member object isn't needed, use {@link Guild#ownerId} instead.
- * @param {BaseFetchOptions} [options] The options for fetching the member
- * @returns {Promise}
- */
- fetchOwner(options) {
- return this.members.fetch({ ...options, user: this.ownerId });
- }
-
- /**
- * AFK voice channel for this guild
- * @type {?VoiceChannel}
- * @readonly
- */
- get afkChannel() {
- return this.client.channels.resolve(this.afkChannelId);
- }
-
- /**
- * System channel for this guild
- * @type {?TextChannel}
- * @readonly
- */
- get systemChannel() {
- return this.client.channels.resolve(this.systemChannelId);
- }
-
- /**
- * Widget channel for this guild
- * @type {?TextChannel}
- * @readonly
- */
- get widgetChannel() {
- return this.client.channels.resolve(this.widgetChannelId);
- }
-
- /**
- * Rules channel for this guild
- * @type {?TextChannel}
- * @readonly
- */
- get rulesChannel() {
- return this.client.channels.resolve(this.rulesChannelId);
- }
-
- /**
- * Public updates channel for this guild
- * @type {?TextChannel}
- * @readonly
- */
- get publicUpdatesChannel() {
- return this.client.channels.resolve(this.publicUpdatesChannelId);
- }
-
- /**
- * The client user as a GuildMember of this guild
- * @type {?GuildMember}
- * @readonly
- */
- get me() {
- return (
- this.members.resolve(this.client.user.id) ??
- (this.client.options.partials.includes(PartialTypes.GUILD_MEMBER)
- ? this.members._add({ user: { id: this.client.user.id } }, true)
- : null)
- );
- }
-
- /**
- * The maximum bitrate available for this guild
- * @type {number}
- * @readonly
- */
- get maximumBitrate() {
- if (this.features.includes('VIP_REGIONS')) {
- return 384_000;
- }
-
- switch (PremiumTiers[this.premiumTier]) {
- case PremiumTiers.TIER_1:
- return 128_000;
- case PremiumTiers.TIER_2:
- return 256_000;
- case PremiumTiers.TIER_3:
- return 384_000;
- default:
- return 96_000;
- }
- }
-
- /**
- * Fetches a collection of integrations to this guild.
- * Resolves with a collection mapping integrations by their ids.
- * @returns {Promise>}
- * @example
- * // Fetch integrations
- * guild.fetchIntegrations()
- * .then(integrations => console.log(`Fetched ${integrations.size} integrations`))
- * .catch(console.error);
- */
- async fetchIntegrations() {
- const data = await this.client.api.guilds(this.id).integrations.get();
- return data.reduce(
- (collection, integration) => collection.set(integration.id, new Integration(this.client, integration, this)),
- new Collection(),
- );
- }
-
- /**
- * Fetches a collection of templates from this guild.
- * Resolves with a collection mapping templates by their codes.
- * @returns {Promise>}
- */
- async fetchTemplates() {
- const templates = await this.client.api.guilds(this.id).templates.get();
- return templates.reduce((col, data) => col.set(data.code, new GuildTemplate(this.client, data)), new Collection());
- }
-
- /**
- * Fetches the welcome screen for this guild.
- * @returns {Promise}
- */
- async fetchWelcomeScreen() {
- const data = await this.client.api.guilds(this.id, 'welcome-screen').get();
- return new WelcomeScreen(this, data);
- }
-
- /**
- * Creates a template for the guild.
- * @param {string} name The name for the template
- * @param {string} [description] The description for the template
- * @returns {Promise}
- */
- async createTemplate(name, description) {
- const data = await this.client.api.guilds(this.id).templates.post({ data: { name, description } });
- return new GuildTemplate(this.client, data);
- }
-
- /**
- * Obtains a guild preview for this guild from Discord.
- * @returns {Promise}
- */
- async fetchPreview() {
- const data = await this.client.api.guilds(this.id).preview.get();
- return new GuildPreview(this.client, data);
- }
-
- /**
- * An object containing information about a guild's vanity invite.
- * @typedef {Object} Vanity
- * @property {?string} code Vanity invite code
- * @property {number} uses How many times this invite has been used
- */
-
- /**
- * Fetches the vanity URL invite object to this guild.
- * Resolves with an object containing the vanity URL invite code and the use count
- * @returns {Promise}
- * @example
- * // Fetch invite data
- * guild.fetchVanityData()
- * .then(res => {
- * console.log(`Vanity URL: https://discord.gg/${res.code} with ${res.uses} uses`);
- * })
- * .catch(console.error);
- */
- async fetchVanityData() {
- if (!this.features.includes('VANITY_URL')) {
- throw new Error('VANITY_URL');
- }
- const data = await this.client.api.guilds(this.id, 'vanity-url').get();
- this.vanityURLCode = data.code;
- this.vanityURLUses = data.uses;
-
- return data;
- }
-
- /**
- * Fetches all webhooks for the guild.
- * @returns {Promise>}
- * @example
- * // Fetch webhooks
- * guild.fetchWebhooks()
- * .then(webhooks => console.log(`Fetched ${webhooks.size} webhooks`))
- * .catch(console.error);
- */
- async fetchWebhooks() {
- const apiHooks = await this.client.api.guilds(this.id).webhooks.get();
- const hooks = new Collection();
- for (const hook of apiHooks) hooks.set(hook.id, new Webhook(this.client, hook));
- return hooks;
- }
-
- /**
- * Fetches the guild widget data, requires the widget to be enabled.
- * @returns {Promise}
- * @example
- * // Fetches the guild widget data
- * guild.fetchWidget()
- * .then(widget => console.log(`The widget shows ${widget.channels.size} channels`))
- * .catch(console.error);
- */
- fetchWidget() {
- return this.client.fetchGuildWidget(this.id);
- }
-
- /**
- * Data for the Guild Widget Settings object
- * @typedef {Object} GuildWidgetSettings
- * @property {boolean} enabled Whether the widget is enabled
- * @property {?GuildChannel} channel The widget invite channel
- */
-
- /**
- * The Guild Widget Settings object
- * @typedef {Object} GuildWidgetSettingsData
- * @property {boolean} enabled Whether the widget is enabled
- * @property {?GuildChannelResolvable} channel The widget invite channel
- */
-
- /**
- * Fetches the guild widget settings.
- * @returns {Promise}
- * @example
- * // Fetches the guild widget settings
- * guild.fetchWidgetSettings()
- * .then(widget => console.log(`The widget is ${widget.enabled ? 'enabled' : 'disabled'}`))
- * .catch(console.error);
- */
- async fetchWidgetSettings() {
- const data = await this.client.api.guilds(this.id).widget.get();
- this.widgetEnabled = data.enabled;
- this.widgetChannelId = data.channel_id;
- return {
- enabled: data.enabled,
- channel: data.channel_id ? this.channels.cache.get(data.channel_id) : null,
- };
- }
-
- /**
- * Options used to fetch audit logs.
- * @typedef {Object} GuildAuditLogsFetchOptions
- * @property {Snowflake|GuildAuditLogsEntry} [before] Only return entries before this entry
- * @property {number} [limit] The number of entries to return
- * @property {UserResolvable} [user] Only return entries for actions made by this user
- * @property {AuditLogAction|number} [type] Only return entries for this action type
- */
-
- /**
- * Fetches audit logs for this guild.
- * @param {GuildAuditLogsFetchOptions} [options={}] Options for fetching audit logs
- * @returns {Promise}
- * @example
- * // Output audit log entries
- * guild.fetchAuditLogs()
- * .then(audit => console.log(audit.entries.first()))
- * .catch(console.error);
- */
- async fetchAuditLogs(options = {}) {
- if (options.before && options.before instanceof GuildAuditLogs.Entry) options.before = options.before.id;
- if (typeof options.type === 'string') options.type = GuildAuditLogs.Actions[options.type];
-
- const data = await this.client.api.guilds(this.id)['audit-logs'].get({
- query: {
- before: options.before,
- limit: options.limit,
- user_id: this.client.users.resolveId(options.user),
- action_type: options.type,
- },
- });
- return GuildAuditLogs.build(this, data);
- }
-
- /**
- * The data for editing a guild.
- * @typedef {Object} GuildEditData
- * @property {string} [name] The name of the guild
- * @property {VerificationLevel|number} [verificationLevel] The verification level of the guild
- * @property {ExplicitContentFilterLevel|number} [explicitContentFilter] The level of the explicit content filter
- * @property {VoiceChannelResolvable} [afkChannel] The AFK channel of the guild
- * @property {TextChannelResolvable} [systemChannel] The system channel of the guild
- * @property {number} [afkTimeout] The AFK timeout of the guild
- * @property {?(BufferResolvable|Base64Resolvable)} [icon] The icon of the guild
- * @property {GuildMemberResolvable} [owner] The owner of the guild
- * @property {?(BufferResolvable|Base64Resolvable)} [splash] The invite splash image of the guild
- * @property {?(BufferResolvable|Base64Resolvable)} [discoverySplash] The discovery splash image of the guild
- * @property {?(BufferResolvable|Base64Resolvable)} [banner] The banner of the guild
- * @property {DefaultMessageNotificationLevel|number} [defaultMessageNotifications] The default message notification
- * level of the guild
- * @property {SystemChannelFlagsResolvable} [systemChannelFlags] The system channel flags of the guild
- * @property {TextChannelResolvable} [rulesChannel] The rules channel of the guild
- * @property {TextChannelResolvable} [publicUpdatesChannel] The community updates channel of the guild
- * @property {string} [preferredLocale] The preferred locale of the guild
- * @property {boolean} [premiumProgressBarEnabled] Whether the guild's premium progress bar is enabled
- * @property {string} [description] The discovery description of the guild
- * @property {Features[]} [features] The features of the guild
- */
-
- /**
- * Data that can be resolved to a Text Channel object. This can be:
- * * A TextChannel
- * * A Snowflake
- * @typedef {TextChannel|Snowflake} TextChannelResolvable
- */
-
- /**
- * Data that can be resolved to a Voice Channel object. This can be:
- * * A VoiceChannel
- * * A Snowflake
- * @typedef {VoiceChannel|Snowflake} VoiceChannelResolvable
- */
-
- /**
- * Updates the guild with new information - e.g. a new name.
- * @param {GuildEditData} data The data to update the guild with
- * @param {string} [reason] Reason for editing this guild
- * @returns {Promise}
- * @example
- * // Set the guild name
- * guild.edit({
- * name: 'Discord Guild',
- * })
- * .then(updated => console.log(`New guild name ${updated}`))
- * .catch(console.error);
- */
- async edit(data, reason) {
- const _data = {};
- if (data.name) _data.name = data.name;
- if (typeof data.verificationLevel !== 'undefined') {
- _data.verification_level =
- typeof data.verificationLevel === 'number'
- ? data.verificationLevel
- : VerificationLevels[data.verificationLevel];
- }
- if (typeof data.afkChannel !== 'undefined') {
- _data.afk_channel_id = this.client.channels.resolveId(data.afkChannel);
- }
- if (typeof data.systemChannel !== 'undefined') {
- _data.system_channel_id = this.client.channels.resolveId(data.systemChannel);
- }
- if (data.afkTimeout) _data.afk_timeout = Number(data.afkTimeout);
- if (typeof data.icon !== 'undefined') _data.icon = await DataResolver.resolveImage(data.icon);
- if (data.owner) _data.owner_id = this.client.users.resolveId(data.owner);
- if (typeof data.splash !== 'undefined') _data.splash = await DataResolver.resolveImage(data.splash);
- if (typeof data.discoverySplash !== 'undefined') {
- _data.discovery_splash = await DataResolver.resolveImage(data.discoverySplash);
- }
- if (typeof data.banner !== 'undefined') _data.banner = await DataResolver.resolveImage(data.banner);
- if (typeof data.explicitContentFilter !== 'undefined') {
- _data.explicit_content_filter =
- typeof data.explicitContentFilter === 'number'
- ? data.explicitContentFilter
- : ExplicitContentFilterLevels[data.explicitContentFilter];
- }
- if (typeof data.defaultMessageNotifications !== 'undefined') {
- _data.default_message_notifications =
- typeof data.defaultMessageNotifications === 'number'
- ? data.defaultMessageNotifications
- : DefaultMessageNotificationLevels[data.defaultMessageNotifications];
- }
- if (typeof data.systemChannelFlags !== 'undefined') {
- _data.system_channel_flags = SystemChannelFlags.resolve(data.systemChannelFlags);
- }
- if (typeof data.rulesChannel !== 'undefined') {
- _data.rules_channel_id = this.client.channels.resolveId(data.rulesChannel);
- }
- if (typeof data.publicUpdatesChannel !== 'undefined') {
- _data.public_updates_channel_id = this.client.channels.resolveId(data.publicUpdatesChannel);
- }
- if (typeof data.features !== 'undefined') {
- _data.features = data.features;
- }
- if (typeof data.description !== 'undefined') {
- _data.description = data.description;
- }
- if (data.preferredLocale) _data.preferred_locale = data.preferredLocale;
- if ('premiumProgressBarEnabled' in data) _data.premium_progress_bar_enabled = data.premiumProgressBarEnabled;
- const newData = await this.client.api.guilds(this.id).patch({ data: _data, reason });
- return this.client.actions.GuildUpdate.handle(newData).updated;
- }
-
- /**
- * Welcome channel data
- * @typedef {Object} WelcomeChannelData
- * @property {string} description The description to show for this welcome channel
- * @property {TextChannel|NewsChannel|StoreChannel|Snowflake} channel The channel to link for this welcome channel
- * @property {EmojiIdentifierResolvable} [emoji] The emoji to display for this welcome channel
- */
-
- /**
- * Welcome screen edit data
- * @typedef {Object} WelcomeScreenEditData
- * @property {boolean} [enabled] Whether the welcome screen is enabled
- * @property {string} [description] The description for the welcome screen
- * @property {WelcomeChannelData[]} [welcomeChannels] The welcome channel data for the welcome screen
- */
-
- /**
- * Data that can be resolved to a GuildTextChannel object. This can be:
- * * A TextChannel
- * * A NewsChannel
- * * A Snowflake
- * @typedef {TextChannel|NewsChannel|Snowflake} GuildTextChannelResolvable
- */
-
- /**
- * Data that can be resolved to a GuildVoiceChannel object. This can be:
- * * A VoiceChannel
- * * A StageChannel
- * * A Snowflake
- * @typedef {VoiceChannel|StageChannel|Snowflake} GuildVoiceChannelResolvable
- */
-
- /**
- * Updates the guild's welcome screen
- * @param {WelcomeScreenEditData} data Data to edit the welcome screen with
- * @returns {Promise}
- * @example
- * guild.editWelcomeScreen({
- * description: 'Hello World',
- * enabled: true,
- * welcomeChannels: [
- * {
- * description: 'foobar',
- * channel: '222197033908436994',
- * }
- * ],
- * })
- */
- async editWelcomeScreen(data) {
- const { enabled, description, welcomeChannels } = data;
- const welcome_channels = welcomeChannels?.map(welcomeChannelData => {
- const emoji = this.emojis.resolve(welcomeChannelData.emoji);
- return {
- emoji_id: emoji?.id,
- emoji_name: emoji?.name ?? welcomeChannelData.emoji,
- channel_id: this.channels.resolveId(welcomeChannelData.channel),
- description: welcomeChannelData.description,
- };
- });
-
- const patchData = await this.client.api.guilds(this.id, 'welcome-screen').patch({
- data: {
- welcome_channels,
- description,
- enabled,
- },
- });
- return new WelcomeScreen(this, patchData);
- }
-
- /**
- * Edits the level of the explicit content filter.
- * @param {ExplicitContentFilterLevel|number} explicitContentFilter The new level of the explicit content filter
- * @param {string} [reason] Reason for changing the level of the guild's explicit content filter
- * @returns {Promise}
- */
- setExplicitContentFilter(explicitContentFilter, reason) {
- return this.edit({ explicitContentFilter }, reason);
- }
-
- /* eslint-disable max-len */
- /**
- * Edits the setting of the default message notifications of the guild.
- * @param {DefaultMessageNotificationLevel|number} defaultMessageNotifications The new default message notification level of the guild
- * @param {string} [reason] Reason for changing the setting of the default message notifications
- * @returns {Promise}
- */
- setDefaultMessageNotifications(defaultMessageNotifications, reason) {
- return this.edit({ defaultMessageNotifications }, reason);
- }
- /* eslint-enable max-len */
-
- /**
- * Edits the flags of the default message notifications of the guild.
- * @param {SystemChannelFlagsResolvable} systemChannelFlags The new flags for the default message notifications
- * @param {string} [reason] Reason for changing the flags of the default message notifications
- * @returns {Promise}
- */
- setSystemChannelFlags(systemChannelFlags, reason) {
- return this.edit({ systemChannelFlags }, reason);
- }
-
- /**
- * Edits the name of the guild.
- * @param {string} name The new name of the guild
- * @param {string} [reason] Reason for changing the guild's name
- * @returns {Promise}
- * @example
- * // Edit the guild name
- * guild.setName('Discord Guild')
- * .then(updated => console.log(`Updated guild name to ${updated.name}`))
- * .catch(console.error);
- */
- setName(name, reason) {
- return this.edit({ name }, reason);
- }
-
- /**
- * Edits the verification level of the guild.
- * @param {VerificationLevel|number} verificationLevel The new verification level of the guild
- * @param {string} [reason] Reason for changing the guild's verification level
- * @returns {Promise}
- * @example
- * // Edit the guild verification level
- * guild.setVerificationLevel(1)
- * .then(updated => console.log(`Updated guild verification level to ${guild.verificationLevel}`))
- * .catch(console.error);
- */
- setVerificationLevel(verificationLevel, reason) {
- return this.edit({ verificationLevel }, reason);
- }
-
- /**
- * Edits the AFK channel of the guild.
- * @param {VoiceChannelResolvable} afkChannel The new AFK channel
- * @param {string} [reason] Reason for changing the guild's AFK channel
- * @returns {Promise}
- * @example
- * // Edit the guild AFK channel
- * guild.setAFKChannel(channel)
- * .then(updated => console.log(`Updated guild AFK channel to ${guild.afkChannel.name}`))
- * .catch(console.error);
- */
- setAFKChannel(afkChannel, reason) {
- return this.edit({ afkChannel }, reason);
- }
-
- /**
- * Edits the system channel of the guild.
- * @param {TextChannelResolvable} systemChannel The new system channel
- * @param {string} [reason] Reason for changing the guild's system channel
- * @returns {Promise}
- * @example
- * // Edit the guild system channel
- * guild.setSystemChannel(channel)
- * .then(updated => console.log(`Updated guild system channel to ${guild.systemChannel.name}`))
- * .catch(console.error);
- */
- setSystemChannel(systemChannel, reason) {
- return this.edit({ systemChannel }, reason);
- }
-
- /**
- * Edits the AFK timeout of the guild.
- * @param {number} afkTimeout The time in seconds that a user must be idle to be considered AFK
- * @param {string} [reason] Reason for changing the guild's AFK timeout
- * @returns {Promise}
- * @example
- * // Edit the guild AFK channel
- * guild.setAFKTimeout(60)
- * .then(updated => console.log(`Updated guild AFK timeout to ${guild.afkTimeout}`))
- * .catch(console.error);
- */
- setAFKTimeout(afkTimeout, reason) {
- return this.edit({ afkTimeout }, reason);
- }
-
- /**
- * Sets a new guild icon.
- * @param {?(Base64Resolvable|BufferResolvable)} icon The new icon of the guild
- * @param {string} [reason] Reason for changing the guild's icon
- * @returns {Promise}
- * @example
- * // Edit the guild icon
- * guild.setIcon('./icon.png')
- * .then(updated => console.log('Updated the guild icon'))
- * .catch(console.error);
- */
- setIcon(icon, reason) {
- return this.edit({ icon }, reason);
- }
-
- /**
- * Sets a new owner of the guild.
- * @param {GuildMemberResolvable} owner The new owner of the guild
- * @param {string} [reason] Reason for setting the new owner
- * @returns {Promise}
- * @example
- * // Edit the guild owner
- * guild.setOwner(guild.members.cache.first())
- * .then(guild => guild.fetchOwner())
- * .then(owner => console.log(`Updated the guild owner to ${owner.displayName}`))
- * .catch(console.error);
- */
- setOwner(owner, reason) {
- return this.edit({ owner }, reason);
- }
-
- /**
- * Sets a new guild invite splash image.
- * @param {?(Base64Resolvable|BufferResolvable)} splash The new invite splash image of the guild
- * @param {string} [reason] Reason for changing the guild's invite splash image
- * @returns {Promise}
- * @example
- * // Edit the guild splash
- * guild.setSplash('./splash.png')
- * .then(updated => console.log('Updated the guild splash'))
- * .catch(console.error);
- */
- setSplash(splash, reason) {
- return this.edit({ splash }, reason);
- }
-
- /**
- * Sets a new guild discovery splash image.
- * @param {?(Base64Resolvable|BufferResolvable)} discoverySplash The new discovery splash image of the guild
- * @param {string} [reason] Reason for changing the guild's discovery splash image
- * @returns {Promise}
- * @example
- * // Edit the guild discovery splash
- * guild.setDiscoverySplash('./discoverysplash.png')
- * .then(updated => console.log('Updated the guild discovery splash'))
- * .catch(console.error);
- */
- setDiscoverySplash(discoverySplash, reason) {
- return this.edit({ discoverySplash }, reason);
- }
-
- /**
- * Sets a new guild banner.
- * @param {?(Base64Resolvable|BufferResolvable)} banner The new banner of the guild
- * @param {string} [reason] Reason for changing the guild's banner
- * @returns {Promise}
- * @example
- * guild.setBanner('./banner.png')
- * .then(updated => console.log('Updated the guild banner'))
- * .catch(console.error);
- */
- setBanner(banner, reason) {
- return this.edit({ banner }, reason);
- }
-
- /**
- * Edits the rules channel of the guild.
- * @param {TextChannelResolvable} rulesChannel The new rules channel
- * @param {string} [reason] Reason for changing the guild's rules channel
- * @returns {Promise}
- * @example
- * // Edit the guild rules channel
- * guild.setRulesChannel(channel)
- * .then(updated => console.log(`Updated guild rules channel to ${guild.rulesChannel.name}`))
- * .catch(console.error);
- */
- setRulesChannel(rulesChannel, reason) {
- return this.edit({ rulesChannel }, reason);
- }
- /**
- * Change Guild Position (from * to Folder or Home)
- * @param {number} position Guild Position
- * * **WARNING**: Type = `FOLDER`, newPosition is the guild's index in the Folder.
- * @param {String|Number} type Move to folder or home
- * * `FOLDER`: 1
- * * `HOME`: 2
- * @param {String|Number|void|null} folderID If you want to move to folder
- * @returns {Promise}
- * @example
- * // Move guild to folderID 123456, index 1
- * guild.setPosition(1, 'FOLDER', 123456)
- * .then(guild => console.log(`Guild moved to folderID ${guild.folder.folderId}`));
- */
- async setPosition(position, type, folderID) {
- if (type == 1 || `${type}`.toUpperCase() === 'FOLDER') {
- folderID = folderID || this.folder.folderId;
- if (!['number', 'string'].includes(typeof folderID))
- throw new TypeError(
- 'INVALID_TYPE',
- 'folderID',
- 'String | Number',
- );
- // Get Data from Folder ID
- const folder = await this.client.setting.rawSetting.guild_folders.find(
- (obj) => obj.id == folderID,
- );
- if (!folder) throw new Error('FOLDER_NOT_FOUND');
- if (folder.guild_ids.length - 1 < position || position < 0)
- throw new Error('FOLDER_POSITION_INVALID');
- if (position !== folder.guild_ids.indexOf(this.id)) {
- await this.client.setting.guildChangePosition(
- this.id,
- position,
- 1,
- folderID,
- );
- }
- } else if (type == 2 || `${type}`.toUpperCase() === 'HOME') {
- if (this.client.setting.guild_positions - 1 < position || position < 0)
- throw new Error('FOLDER_POSITION_INVALID');
- if (position !== this.position) {
- await this.client.setting.guildChangePosition(
- this.id,
- position,
- 2,
- null,
- );
- }
- } else {
- throw new TypeError('INVALID_TYPE', 'type', '`Folder`| `Home`');
- }
- return this;
- }
-
- /**
- * Edits the community updates channel of the guild.
- * @param {TextChannelResolvable} publicUpdatesChannel The new community updates channel
- * @param {string} [reason] Reason for changing the guild's community updates channel
- * @returns {Promise}
- * @example
- * // Edit the guild community updates channel
- * guild.setPublicUpdatesChannel(channel)
- * .then(updated => console.log(`Updated guild community updates channel to ${guild.publicUpdatesChannel.name}`))
- * .catch(console.error);
- */
- setPublicUpdatesChannel(publicUpdatesChannel, reason) {
- return this.edit({ publicUpdatesChannel }, reason);
- }
-
- /**
- * Edits the preferred locale of the guild.
- * @param {string} preferredLocale The new preferred locale of the guild
- * @param {string} [reason] Reason for changing the guild's preferred locale
- * @returns {Promise}
- * @example
- * // Edit the guild preferred locale
- * guild.setPreferredLocale('en-US')
- * .then(updated => console.log(`Updated guild preferred locale to ${guild.preferredLocale}`))
- * .catch(console.error);
- */
- setPreferredLocale(preferredLocale, reason) {
- return this.edit({ preferredLocale }, reason);
- }
-
- /**
- * Edits the enabled state of the guild's premium progress bar
- * @param {boolean} [enabled=true] The new enabled state of the guild's premium progress bar
- * @param {string} [reason] Reason for changing the state of the guild's premium progress bar
- * @returns {Promise}
- */
- setPremiumProgressBarEnabled(enabled = true, reason) {
- return this.edit({ premiumProgressBarEnabled: enabled }, reason);
- }
-
- /**
- * Data that can be resolved to give a Category Channel object. This can be:
- * * A CategoryChannel object
- * * A Snowflake
- * @typedef {CategoryChannel|Snowflake} CategoryChannelResolvable
- */
-
- /**
- * The data needed for updating a channel's position.
- * @typedef {Object} ChannelPosition
- * @property {GuildChannel|Snowflake} channel Channel to update
- * @property {number} [position] New position for the channel
- * @property {CategoryChannelResolvable} [parent] Parent channel for this channel
- * @property {boolean} [lockPermissions] If the overwrites should be locked to the parents overwrites
- */
-
- /**
- * Batch-updates the guild's channels' positions.
- * Only one channel's parent can be changed at a time
- * @param {ChannelPosition[]} channelPositions Channel positions to update
- * @returns {Promise}
- * @deprecated Use {@link GuildChannelManager#setPositions} instead
- * @example
- * guild.setChannelPositions([{ channel: channelId, position: newChannelIndex }])
- * .then(guild => console.log(`Updated channel positions for ${guild}`))
- * .catch(console.error);
- */
- setChannelPositions(channelPositions) {
- if (!deprecationEmittedForSetChannelPositions) {
- process.emitWarning(
- 'The Guild#setChannelPositions method is deprecated. Use GuildChannelManager#setPositions instead.',
- 'DeprecationWarning',
- );
-
- deprecationEmittedForSetChannelPositions = true;
- }
-
- return this.channels.setPositions(channelPositions);
- }
-
- /**
- * The data needed for updating a guild role's position
- * @typedef {Object} GuildRolePosition
- * @property {RoleResolvable} role The role's id
- * @property {number} position The position to update
- */
-
- /**
- * Batch-updates the guild's role positions
- * @param {GuildRolePosition[]} rolePositions Role positions to update
- * @returns {Promise}
- * @deprecated Use {@link RoleManager#setPositions} instead
- * @example
- * guild.setRolePositions([{ role: roleId, position: updatedRoleIndex }])
- * .then(guild => console.log(`Role positions updated for ${guild}`))
- * .catch(console.error);
- */
- setRolePositions(rolePositions) {
- if (!deprecationEmittedForSetRolePositions) {
- process.emitWarning(
- 'The Guild#setRolePositions method is deprecated. Use RoleManager#setPositions instead.',
- 'DeprecationWarning',
- );
-
- deprecationEmittedForSetRolePositions = true;
- }
-
- return this.roles.setPositions(rolePositions);
- }
-
- /**
- * Edits the guild's widget settings.
- * @param {GuildWidgetSettingsData} settings The widget settings for the guild
- * @param {string} [reason] Reason for changing the guild's widget settings
- * @returns {Promise}
- */
- async setWidgetSettings(settings, reason) {
- await this.client.api.guilds(this.id).widget.patch({
- data: {
- enabled: settings.enabled,
- channel_id: this.channels.resolveId(settings.channel),
- },
- reason,
- });
- return this;
- }
-
- /**
- * Leaves the guild.
- * @returns {Promise}
- * @example
- * // Leave a guild
- * guild.leave()
- * .then(g => console.log(`Left the guild ${g}`))
- * .catch(console.error);
- */
- async leave() {
- if (this.ownerId === this.client.user.id) throw new Error('GUILD_OWNED');
- await this.client.api.users('@me').guilds(this.id).delete();
- return this.client.actions.GuildDelete.handle({ id: this.id }).guild;
- }
-
- /**
- * Deletes the guild.
- * @returns {Promise}
- * @example
- * // Delete a guild
- * guild.delete()
- * .then(g => console.log(`Deleted the guild ${g}`))
- * .catch(console.error);
- */
- async delete() {
- await this.client.api.guilds(this.id).delete();
- return this.client.actions.GuildDelete.handle({ id: this.id }).guild;
- }
-
- /**
- * Whether this guild equals another guild. It compares all properties, so for most operations
- * it is advisable to just compare `guild.id === guild2.id` as it is much faster and is often
- * what most users need.
- * @param {Guild} guild The guild to compare with
- * @returns {boolean}
- */
- equals(guild) {
- return (
- guild &&
- guild instanceof this.constructor &&
- this.id === guild.id &&
- this.available === guild.available &&
- this.splash === guild.splash &&
- this.discoverySplash === guild.discoverySplash &&
- this.name === guild.name &&
- this.memberCount === guild.memberCount &&
- this.large === guild.large &&
- this.icon === guild.icon &&
- this.ownerId === guild.ownerId &&
- this.verificationLevel === guild.verificationLevel &&
- (this.features === guild.features ||
- (this.features.length === guild.features.length &&
- this.features.every((feat, i) => feat === guild.features[i])))
- );
- }
-
- /**
- * Set Community Feature
- * @param {Boolean} stats True / False to enable / disable Community Feature
- * @param {TextChannelResolvable} publicUpdatesChannel
- * @param {TextChannelResolvable} rulesChannel
- * @param {String} reason
- */
- async setCommunity(stats = true, publicUpdatesChannel = '1', rulesChannel = '1', reason) {
- if (stats) {
- // Check everyone role
- const everyoneRole = this.roles.everyone;
- if (everyoneRole.mentionable) {
- await everyoneRole.setMentionable(false, reason);
- }
- // Setting
- this.edit(
- {
- defaultMessageNotifications: 'ONLY_MENTIONS',
- explicitContentFilter: 'ALL_MEMBERS',
- features: [...this.features, 'COMMUNITY'],
- publicUpdatesChannel,
- rulesChannel,
- verificationLevel:
- VerificationLevels[this.verificationLevel] < 1
- ? 'LOW'
- : this.verificationLevel, // Email
- },
- reason,
- );
- } else {
- this.edit({
- publicUpdatesChannel: null,
- rulesChannel: null,
- features: this.features.filter(f => f !== 'COMMUNITY'),
- preferredLocale: this.preferredLocale,
- description: this.description,
- }, reason);
- }
- }
-
- toJSON() {
- const json = super.toJSON({
- available: false,
- createdTimestamp: true,
- nameAcronym: true,
- presences: false,
- voiceStates: false,
- });
- json.iconURL = this.iconURL();
- json.splashURL = this.splashURL();
- json.discoverySplashURL = this.discoverySplashURL();
- json.bannerURL = this.bannerURL();
- return json;
- }
-
- /**
- * The voice state adapter for this guild that can be used with @discordjs/voice to play audio in voice
- * and stage channels.
- * @type {Function}
- * @readonly
- */
- get voiceAdapterCreator() {
- return methods => {
- this.client.voice.adapters.set(this.id, methods);
- return {
- sendPayload: data => {
- if (this.shard.status !== Status.READY) return false;
- this.shard.send(data);
- return true;
- },
- destroy: () => {
- this.client.voice.adapters.delete(this.id);
- },
- };
- };
- }
-
- /**
- * Creates a collection of this guild's roles, sorted by their position and ids.
- * @returns {Collection}
- * @private
- */
- _sortedRoles() {
- return Util.discordSort(this.roles.cache);
- }
-
- /**
- * Creates a collection of this guild's or a specific category's channels, sorted by their position and ids.
- * @param {GuildChannel} [channel] Category to get the channels of
- * @returns {Collection}
- * @private
- */
- _sortedChannels(channel) {
- const category = channel.type === ChannelTypes.GUILD_CATEGORY;
- return Util.discordSort(
- this.channels.cache.filter(
- c =>
- (['GUILD_TEXT', 'GUILD_NEWS', 'GUILD_STORE'].includes(channel.type)
- ? ['GUILD_TEXT', 'GUILD_NEWS', 'GUILD_STORE'].includes(c.type)
- : c.type === channel.type) &&
- (category || c.parent === channel.parent),
- ),
- );
- }
+ constructor(client, data) {
+ super(client, data, false);
+
+ /**
+ * A manager of the members belonging to this guild
+ * @type {GuildMemberManager}
+ */
+ this.members = new GuildMemberManager(this);
+
+ /**
+ * A manager of the channels belonging to this guild
+ * @type {GuildChannelManager}
+ */
+ this.channels = new GuildChannelManager(this);
+
+ /**
+ * A manager of the bans belonging to this guild
+ * @type {GuildBanManager}
+ */
+ this.bans = new GuildBanManager(this);
+
+ /**
+ * A manager of the roles belonging to this guild
+ * @type {RoleManager}
+ */
+ this.roles = new RoleManager(this);
+
+ /**
+ * A manager of the presences belonging to this guild
+ * @type {PresenceManager}
+ */
+ this.presences = new PresenceManager(this.client);
+
+ /**
+ * A manager of the voice states of this guild
+ * @type {VoiceStateManager}
+ */
+ this.voiceStates = new VoiceStateManager(this);
+
+ /**
+ * A manager of the stage instances of this guild
+ * @type {StageInstanceManager}
+ */
+ this.stageInstances = new StageInstanceManager(this);
+
+ /**
+ * A manager of the invites of this guild
+ * @type {GuildInviteManager}
+ */
+ this.invites = new GuildInviteManager(this);
+
+ /**
+ * A manager of the scheduled events of this guild
+ * @type {GuildScheduledEventManager}
+ */
+ this.scheduledEvents = new GuildScheduledEventManager(this);
+
+ if (!data) return;
+ if (data.unavailable) {
+ /**
+ * Whether the guild is available to access. If it is not available, it indicates a server outage
+ * @type {boolean}
+ */
+ this.available = false;
+ } else {
+ this._patch(data);
+ if (!data.channels) this.available = false;
+ }
+
+ /**
+ * The id of the shard this Guild belongs to.
+ * @type {number}
+ */
+ this.shardId = data.shardId;
+
+ this.disableDM = false;
+ }
+
+ /**
+ * Whether or not the structure has been deleted
+ * @type {boolean}
+ * @deprecated This will be removed in the next major version, see https://github.com/discordjs/discord.js/issues/7091
+ */
+ get deleted() {
+ if (!deprecationEmittedForDeleted) {
+ deprecationEmittedForDeleted = true;
+ process.emitWarning(
+ 'Guild#deleted is deprecated, see https://github.com/discordjs/discord.js/issues/7091.',
+ 'DeprecationWarning',
+ );
+ }
+
+ return deletedGuilds.has(this);
+ }
+
+ set deleted(value) {
+ if (!deprecationEmittedForDeleted) {
+ deprecationEmittedForDeleted = true;
+ process.emitWarning(
+ 'Guild#deleted is deprecated, see https://github.com/discordjs/discord.js/issues/7091.',
+ 'DeprecationWarning',
+ );
+ }
+
+ if (value) deletedGuilds.add(this);
+ else deletedGuilds.delete(this);
+ }
+
+ /**
+ * The Shard this Guild belongs to.
+ * @type {WebSocketShard}
+ * @readonly
+ */
+ get shard() {
+ return this.client.ws.shards.get(this.shardId);
+ }
+
+ _patch(data) {
+ super._patch(data);
+ this.id = data.id;
+ if ('name' in data) this.name = data.name;
+ if ('icon' in data) this.icon = data.icon;
+ if ('unavailable' in data) {
+ this.available = !data.unavailable;
+ } else {
+ this.available ??= true;
+ }
+
+ if ('discovery_splash' in data) {
+ /**
+ * The hash of the guild discovery splash image
+ * @type {?string}
+ */
+ this.discoverySplash = data.discovery_splash;
+ }
+
+ if ('member_count' in data) {
+ /**
+ * The full amount of members in this guild
+ * @type {number}
+ */
+ this.memberCount = data.member_count;
+ }
+
+ if ('large' in data) {
+ /**
+ * Whether the guild is "large" (has more than {@link WebsocketOptions large_threshold} members, 50 by default)
+ * @type {boolean}
+ */
+ this.large = Boolean(data.large);
+ }
+
+ if ('premium_progress_bar_enabled' in data) {
+ /**
+ * Whether this guild has its premium (boost) progress bar enabled
+ * @type {boolean}
+ */
+ this.premiumProgressBarEnabled = data.premium_progress_bar_enabled;
+ }
+
+ /**
+ * An array of enabled guild features, here are the possible values:
+ * * ANIMATED_ICON
+ * * BANNER
+ * * COMMERCE
+ * * COMMUNITY
+ * * DISCOVERABLE
+ * * FEATURABLE
+ * * INVITE_SPLASH
+ * * MEMBER_VERIFICATION_GATE_ENABLED
+ * * NEWS
+ * * PARTNERED
+ * * PREVIEW_ENABLED
+ * * VANITY_URL
+ * * VERIFIED
+ * * VIP_REGIONS
+ * * WELCOME_SCREEN_ENABLED
+ * * TICKETED_EVENTS_ENABLED
+ * * MONETIZATION_ENABLED
+ * * MORE_STICKERS
+ * * THREE_DAY_THREAD_ARCHIVE
+ * * SEVEN_DAY_THREAD_ARCHIVE
+ * * PRIVATE_THREADS
+ * * ROLE_ICONS
+ * @typedef {string} Features
+ * @see {@link https://discord.com/developers/docs/resources/guild#guild-object-guild-features}
+ */
+
+ if ('application_id' in data) {
+ /**
+ * The id of the application that created this guild (if applicable)
+ * @type {?Snowflake}
+ */
+ this.applicationId = data.application_id;
+ }
+
+ if ('afk_timeout' in data) {
+ /**
+ * The time in seconds before a user is counted as "away from keyboard"
+ * @type {?number}
+ */
+ this.afkTimeout = data.afk_timeout;
+ }
+
+ if ('afk_channel_id' in data) {
+ /**
+ * The id of the voice channel where AFK members are moved
+ * @type {?Snowflake}
+ */
+ this.afkChannelId = data.afk_channel_id;
+ }
+
+ if ('system_channel_id' in data) {
+ /**
+ * The system channel's id
+ * @type {?Snowflake}
+ */
+ this.systemChannelId = data.system_channel_id;
+ }
+
+ if ('premium_tier' in data) {
+ /**
+ * The premium tier of this guild
+ * @type {PremiumTier}
+ */
+ this.premiumTier = PremiumTiers[data.premium_tier];
+ }
+
+ if ('premium_subscription_count' in data) {
+ /**
+ * The total number of boosts for this server
+ * @type {?number}
+ */
+ this.premiumSubscriptionCount = data.premium_subscription_count;
+ }
+
+ if ('widget_enabled' in data) {
+ /**
+ * Whether widget images are enabled on this guild
+ * @type {?boolean}
+ */
+ this.widgetEnabled = data.widget_enabled;
+ }
+
+ if ('widget_channel_id' in data) {
+ /**
+ * The widget channel's id, if enabled
+ * @type {?string}
+ */
+ this.widgetChannelId = data.widget_channel_id;
+ }
+
+ if ('explicit_content_filter' in data) {
+ /**
+ * The explicit content filter level of the guild
+ * @type {ExplicitContentFilterLevel}
+ */
+ this.explicitContentFilter =
+ ExplicitContentFilterLevels[data.explicit_content_filter];
+ }
+
+ if ('mfa_level' in data) {
+ /**
+ * The required MFA level for this guild
+ * @type {MFALevel}
+ */
+ this.mfaLevel = MFALevels[data.mfa_level];
+ }
+
+ if ('joined_at' in data) {
+ /**
+ * The timestamp the client user joined the guild at
+ * @type {number}
+ */
+ this.joinedTimestamp = new Date(data.joined_at).getTime();
+ }
+
+ if ('default_message_notifications' in data) {
+ /**
+ * The default message notification level of the guild
+ * @type {DefaultMessageNotificationLevel}
+ */
+ this.defaultMessageNotifications =
+ DefaultMessageNotificationLevels[data.default_message_notifications];
+ }
+
+ if ('system_channel_flags' in data) {
+ /**
+ * The value set for the guild's system channel flags
+ * @type {Readonly}
+ */
+ this.systemChannelFlags = new SystemChannelFlags(
+ data.system_channel_flags,
+ ).freeze();
+ }
+
+ if ('max_members' in data) {
+ /**
+ * The maximum amount of members the guild can have
+ * @type {?number}
+ */
+ this.maximumMembers = data.max_members;
+ } else {
+ this.maximumMembers ??= null;
+ }
+
+ if ('max_presences' in data) {
+ /**
+ * The maximum amount of presences the guild can have
+ * You will need to fetch the guild using {@link Guild#fetch} if you want to receive this parameter
+ * @type {?number}
+ */
+ this.maximumPresences = data.max_presences ?? 25_000;
+ } else {
+ this.maximumPresences ??= null;
+ }
+
+ if ('approximate_member_count' in data) {
+ /**
+ * The approximate amount of members the guild has
+ * You will need to fetch the guild using {@link Guild#fetch} if you want to receive this parameter
+ * @type {?number}
+ */
+ this.approximateMemberCount = data.approximate_member_count;
+ } else {
+ this.approximateMemberCount ??= null;
+ }
+
+ if ('approximate_presence_count' in data) {
+ /**
+ * The approximate amount of presences the guild has
+ * You will need to fetch the guild using {@link Guild#fetch} if you want to receive this parameter
+ * @type {?number}
+ */
+ this.approximatePresenceCount = data.approximate_presence_count;
+ } else {
+ this.approximatePresenceCount ??= null;
+ }
+
+ /**
+ * The use count of the vanity URL code of the guild, if any
+ * You will need to fetch this parameter using {@link Guild#fetchVanityData} if you want to receive it
+ * @type {?number}
+ */
+ this.vanityURLUses ??= null;
+
+ if ('rules_channel_id' in data) {
+ /**
+ * The rules channel's id for the guild
+ * @type {?Snowflake}
+ */
+ this.rulesChannelId = data.rules_channel_id;
+ }
+
+ if ('public_updates_channel_id' in data) {
+ /**
+ * The community updates channel's id for the guild
+ * @type {?Snowflake}
+ */
+ this.publicUpdatesChannelId = data.public_updates_channel_id;
+ }
+
+ if ('preferred_locale' in data) {
+ /**
+ * The preferred locale of the guild, defaults to `en-US`
+ * @type {string}
+ * @see {@link https://discord.com/developers/docs/dispatch/field-values#predefined-field-values-accepted-locales}
+ */
+ this.preferredLocale = data.preferred_locale;
+ }
+
+ if (data.channels) {
+ this.channels.cache.clear();
+ for (const rawChannel of data.channels) {
+ this.client.channels._add(rawChannel, this);
+ }
+ }
+
+ if (data.threads) {
+ for (const rawThread of data.threads) {
+ this.client.channels._add(rawThread, this);
+ }
+ }
+
+ if (data.roles) {
+ this.roles.cache.clear();
+ for (const role of data.roles) this.roles._add(role);
+ }
+
+ if (data.members) {
+ this.members.cache.clear();
+ for (const guildUser of data.members) this.members._add(guildUser);
+ }
+
+ if ('owner_id' in data) {
+ /**
+ * The user id of this guild's owner
+ * @type {Snowflake}
+ */
+ this.ownerId = data.owner_id;
+ }
+
+ if (data.presences) {
+ for (const presence of data.presences) {
+ this.presences._add(Object.assign(presence, { guild: this }));
+ }
+ }
+
+ if (data.stage_instances) {
+ this.stageInstances.cache.clear();
+ for (const stageInstance of data.stage_instances) {
+ this.stageInstances._add(stageInstance);
+ }
+ }
+
+ if (data.guild_scheduled_events) {
+ this.scheduledEvents.cache.clear();
+ for (const scheduledEvent of data.guild_scheduled_events) {
+ this.scheduledEvents._add(scheduledEvent);
+ }
+ }
+
+ if (data.voice_states) {
+ this.voiceStates.cache.clear();
+ for (const voiceState of data.voice_states) {
+ this.voiceStates._add(voiceState);
+ }
+ }
+
+ if (!this.emojis) {
+ /**
+ * A manager of the emojis belonging to this guild
+ * @type {GuildEmojiManager}
+ */
+ this.emojis = new GuildEmojiManager(this);
+ if (data.emojis) for (const emoji of data.emojis) this.emojis._add(emoji);
+ } else if (data.emojis) {
+ this.client.actions.GuildEmojisUpdate.handle({
+ guild_id: this.id,
+ emojis: data.emojis,
+ });
+ }
+
+ if (!this.stickers) {
+ /**
+ * A manager of the stickers belonging to this guild
+ * @type {GuildStickerManager}
+ */
+ this.stickers = new GuildStickerManager(this);
+ if (data.stickers)
+ for (const sticker of data.stickers) this.stickers._add(sticker);
+ } else if (data.stickers) {
+ this.client.actions.GuildStickersUpdate.handle({
+ guild_id: this.id,
+ stickers: data.stickers,
+ });
+ }
+ }
+
+ /**
+ * The time the client user joined the guild
+ * @type {Date}
+ * @readonly
+ */
+ get joinedAt() {
+ return new Date(this.joinedTimestamp);
+ }
+
+ /**
+ * The URL to this guild's discovery splash image.
+ * @param {StaticImageURLOptions} [options={}] Options for the Image URL
+ * @returns {?string}
+ */
+ discoverySplashURL({ format, size } = {}) {
+ return (
+ this.discoverySplash &&
+ this.client.rest.cdn.DiscoverySplash(
+ this.id,
+ this.discoverySplash,
+ format,
+ size,
+ )
+ );
+ }
+
+ /**
+ * Fetches the owner of the guild.
+ * If the member object isn't needed, use {@link Guild#ownerId} instead.
+ * @param {BaseFetchOptions} [options] The options for fetching the member
+ * @returns {Promise}
+ */
+ fetchOwner(options) {
+ return this.members.fetch({ ...options, user: this.ownerId });
+ }
+
+ /**
+ * AFK voice channel for this guild
+ * @type {?VoiceChannel}
+ * @readonly
+ */
+ get afkChannel() {
+ return this.client.channels.resolve(this.afkChannelId);
+ }
+
+ /**
+ * System channel for this guild
+ * @type {?TextChannel}
+ * @readonly
+ */
+ get systemChannel() {
+ return this.client.channels.resolve(this.systemChannelId);
+ }
+
+ /**
+ * Widget channel for this guild
+ * @type {?TextChannel}
+ * @readonly
+ */
+ get widgetChannel() {
+ return this.client.channels.resolve(this.widgetChannelId);
+ }
+
+ /**
+ * Rules channel for this guild
+ * @type {?TextChannel}
+ * @readonly
+ */
+ get rulesChannel() {
+ return this.client.channels.resolve(this.rulesChannelId);
+ }
+
+ /**
+ * Public updates channel for this guild
+ * @type {?TextChannel}
+ * @readonly
+ */
+ get publicUpdatesChannel() {
+ return this.client.channels.resolve(this.publicUpdatesChannelId);
+ }
+
+ /**
+ * The client user as a GuildMember of this guild
+ * @type {?GuildMember}
+ * @readonly
+ */
+ get me() {
+ return (
+ this.members.resolve(this.client.user.id) ??
+ (this.client.options.partials.includes(PartialTypes.GUILD_MEMBER)
+ ? this.members._add({ user: { id: this.client.user.id } }, true)
+ : null)
+ );
+ }
+
+ /**
+ * The maximum bitrate available for this guild
+ * @type {number}
+ * @readonly
+ */
+ get maximumBitrate() {
+ if (this.features.includes('VIP_REGIONS')) {
+ return 384_000;
+ }
+
+ switch (PremiumTiers[this.premiumTier]) {
+ case PremiumTiers.TIER_1:
+ return 128_000;
+ case PremiumTiers.TIER_2:
+ return 256_000;
+ case PremiumTiers.TIER_3:
+ return 384_000;
+ default:
+ return 96_000;
+ }
+ }
+
+ /**
+ * Search slash command / message context
+ * @param {guildSearchInteraction} options
+ * {
+ *
+ * type: 1 | 2 | 3, [CHAT_INPUT | USER | MESSAGE]
+ *
+ * query: string | undefined,
+ *
+ * limit: number | 1,
+ *
+ * offset: number | 0,
+ *
+ * botID: [Snowflake] | undefined,
+ *
+ * }
+ */
+ async searchInteraction(options = {}) {
+ let { query, type, limit, offset, botID } = Object.assign(
+ { query: undefined, type: 1, limit: 1, offset: 0, botID: [] },
+ options,
+ );
+ if (typeof type == 'string') {
+ if (type == 'CHAT_INPUT') type = 1;
+ else if (type == 'USER') type = 2;
+ else if (type == 'MESSAGE') type = 3;
+ }
+ if (type < 1 || type > 3)
+ throw new RangeError('Type must be 1, 2, 3');
+ if (typeof type !== 'number')
+ throw new TypeError('Type must be a number | string');
+ this.shard.send({
+ op: Opcodes.REQUEST_APPLICATION_COMMANDS,
+ d: {
+ guild_id: this.id,
+ applications: false,
+ limit,
+ offset,
+ type,
+ query: query,
+ command_ids: Array.isArray(botID) ? botID : undefined,
+ },
+ });
+ }
+
+ /**
+ * Fetches a collection of integrations to this guild.
+ * Resolves with a collection mapping integrations by their ids.
+ * @returns {Promise>}
+ * @example
+ * // Fetch integrations
+ * guild.fetchIntegrations()
+ * .then(integrations => console.log(`Fetched ${integrations.size} integrations`))
+ * .catch(console.error);
+ */
+ async fetchIntegrations() {
+ const data = await this.client.api.guilds(this.id).integrations.get();
+ return data.reduce(
+ (collection, integration) =>
+ collection.set(
+ integration.id,
+ new Integration(this.client, integration, this),
+ ),
+ new Collection(),
+ );
+ }
+
+ /**
+ * Fetches a collection of templates from this guild.
+ * Resolves with a collection mapping templates by their codes.
+ * @returns {Promise>}
+ */
+ async fetchTemplates() {
+ const templates = await this.client.api.guilds(this.id).templates.get();
+ return templates.reduce(
+ (col, data) => col.set(data.code, new GuildTemplate(this.client, data)),
+ new Collection(),
+ );
+ }
+
+ /**
+ * Fetches the welcome screen for this guild.
+ * @returns {Promise}
+ */
+ async fetchWelcomeScreen() {
+ const data = await this.client.api.guilds(this.id, 'welcome-screen').get();
+ return new WelcomeScreen(this, data);
+ }
+
+ /**
+ * Creates a template for the guild.
+ * @param {string} name The name for the template
+ * @param {string} [description] The description for the template
+ * @returns {Promise}
+ */
+ async createTemplate(name, description) {
+ const data = await this.client.api
+ .guilds(this.id)
+ .templates.post({ data: { name, description } });
+ return new GuildTemplate(this.client, data);
+ }
+
+ /**
+ * Obtains a guild preview for this guild from Discord.
+ * @returns {Promise}
+ */
+ async fetchPreview() {
+ const data = await this.client.api.guilds(this.id).preview.get();
+ return new GuildPreview(this.client, data);
+ }
+
+ /**
+ * An object containing information about a guild's vanity invite.
+ * @typedef {Object} Vanity
+ * @property {?string} code Vanity invite code
+ * @property {number} uses How many times this invite has been used
+ */
+
+ /**
+ * Fetches the vanity URL invite object to this guild.
+ * Resolves with an object containing the vanity URL invite code and the use count
+ * @returns {Promise}
+ * @example
+ * // Fetch invite data
+ * guild.fetchVanityData()
+ * .then(res => {
+ * console.log(`Vanity URL: https://discord.gg/${res.code} with ${res.uses} uses`);
+ * })
+ * .catch(console.error);
+ */
+ async fetchVanityData() {
+ if (!this.features.includes('VANITY_URL')) {
+ throw new Error('VANITY_URL');
+ }
+ const data = await this.client.api.guilds(this.id, 'vanity-url').get();
+ this.vanityURLCode = data.code;
+ this.vanityURLUses = data.uses;
+
+ return data;
+ }
+
+ /**
+ * Fetches all webhooks for the guild.
+ * @returns {Promise>}
+ * @example
+ * // Fetch webhooks
+ * guild.fetchWebhooks()
+ * .then(webhooks => console.log(`Fetched ${webhooks.size} webhooks`))
+ * .catch(console.error);
+ */
+ async fetchWebhooks() {
+ const apiHooks = await this.client.api.guilds(this.id).webhooks.get();
+ const hooks = new Collection();
+ for (const hook of apiHooks)
+ hooks.set(hook.id, new Webhook(this.client, hook));
+ return hooks;
+ }
+
+ /**
+ * Fetches the guild widget data, requires the widget to be enabled.
+ * @returns {Promise}
+ * @example
+ * // Fetches the guild widget data
+ * guild.fetchWidget()
+ * .then(widget => console.log(`The widget shows ${widget.channels.size} channels`))
+ * .catch(console.error);
+ */
+ fetchWidget() {
+ return this.client.fetchGuildWidget(this.id);
+ }
+
+ /**
+ * Data for the Guild Widget Settings object
+ * @typedef {Object} GuildWidgetSettings
+ * @property {boolean} enabled Whether the widget is enabled
+ * @property {?GuildChannel} channel The widget invite channel
+ */
+
+ /**
+ * The Guild Widget Settings object
+ * @typedef {Object} GuildWidgetSettingsData
+ * @property {boolean} enabled Whether the widget is enabled
+ * @property {?GuildChannelResolvable} channel The widget invite channel
+ */
+
+ /**
+ * Fetches the guild widget settings.
+ * @returns {Promise}
+ * @example
+ * // Fetches the guild widget settings
+ * guild.fetchWidgetSettings()
+ * .then(widget => console.log(`The widget is ${widget.enabled ? 'enabled' : 'disabled'}`))
+ * .catch(console.error);
+ */
+ async fetchWidgetSettings() {
+ const data = await this.client.api.guilds(this.id).widget.get();
+ this.widgetEnabled = data.enabled;
+ this.widgetChannelId = data.channel_id;
+ return {
+ enabled: data.enabled,
+ channel: data.channel_id
+ ? this.channels.cache.get(data.channel_id)
+ : null,
+ };
+ }
+
+ /**
+ * Options used to fetch audit logs.
+ * @typedef {Object} GuildAuditLogsFetchOptions
+ * @property {Snowflake|GuildAuditLogsEntry} [before] Only return entries before this entry
+ * @property {number} [limit] The number of entries to return
+ * @property {UserResolvable} [user] Only return entries for actions made by this user
+ * @property {AuditLogAction|number} [type] Only return entries for this action type
+ */
+
+ /**
+ * Fetches audit logs for this guild.
+ * @param {GuildAuditLogsFetchOptions} [options={}] Options for fetching audit logs
+ * @returns {Promise}
+ * @example
+ * // Output audit log entries
+ * guild.fetchAuditLogs()
+ * .then(audit => console.log(audit.entries.first()))
+ * .catch(console.error);
+ */
+ async fetchAuditLogs(options = {}) {
+ if (options.before && options.before instanceof GuildAuditLogs.Entry)
+ options.before = options.before.id;
+ if (typeof options.type === 'string')
+ options.type = GuildAuditLogs.Actions[options.type];
+
+ const data = await this.client.api.guilds(this.id)['audit-logs'].get({
+ query: {
+ before: options.before,
+ limit: options.limit,
+ user_id: this.client.users.resolveId(options.user),
+ action_type: options.type,
+ },
+ });
+ return GuildAuditLogs.build(this, data);
+ }
+
+ /**
+ * The data for editing a guild.
+ * @typedef {Object} GuildEditData
+ * @property {string} [name] The name of the guild
+ * @property {VerificationLevel|number} [verificationLevel] The verification level of the guild
+ * @property {ExplicitContentFilterLevel|number} [explicitContentFilter] The level of the explicit content filter
+ * @property {VoiceChannelResolvable} [afkChannel] The AFK channel of the guild
+ * @property {TextChannelResolvable} [systemChannel] The system channel of the guild
+ * @property {number} [afkTimeout] The AFK timeout of the guild
+ * @property {?(BufferResolvable|Base64Resolvable)} [icon] The icon of the guild
+ * @property {GuildMemberResolvable} [owner] The owner of the guild
+ * @property {?(BufferResolvable|Base64Resolvable)} [splash] The invite splash image of the guild
+ * @property {?(BufferResolvable|Base64Resolvable)} [discoverySplash] The discovery splash image of the guild
+ * @property {?(BufferResolvable|Base64Resolvable)} [banner] The banner of the guild
+ * @property {DefaultMessageNotificationLevel|number} [defaultMessageNotifications] The default message notification
+ * level of the guild
+ * @property {SystemChannelFlagsResolvable} [systemChannelFlags] The system channel flags of the guild
+ * @property {TextChannelResolvable} [rulesChannel] The rules channel of the guild
+ * @property {TextChannelResolvable} [publicUpdatesChannel] The community updates channel of the guild
+ * @property {string} [preferredLocale] The preferred locale of the guild
+ * @property {boolean} [premiumProgressBarEnabled] Whether the guild's premium progress bar is enabled
+ * @property {string} [description] The discovery description of the guild
+ * @property {Features[]} [features] The features of the guild
+ */
+
+ /**
+ * Data that can be resolved to a Text Channel object. This can be:
+ * * A TextChannel
+ * * A Snowflake
+ * @typedef {TextChannel|Snowflake} TextChannelResolvable
+ */
+
+ /**
+ * Data that can be resolved to a Voice Channel object. This can be:
+ * * A VoiceChannel
+ * * A Snowflake
+ * @typedef {VoiceChannel|Snowflake} VoiceChannelResolvable
+ */
+
+ /**
+ * Updates the guild with new information - e.g. a new name.
+ * @param {GuildEditData} data The data to update the guild with
+ * @param {string} [reason] Reason for editing this guild
+ * @returns {Promise}
+ * @example
+ * // Set the guild name
+ * guild.edit({
+ * name: 'Discord Guild',
+ * })
+ * .then(updated => console.log(`New guild name ${updated}`))
+ * .catch(console.error);
+ */
+ async edit(data, reason) {
+ const _data = {};
+ if (data.name) _data.name = data.name;
+ if (typeof data.verificationLevel !== 'undefined') {
+ _data.verification_level =
+ typeof data.verificationLevel === 'number'
+ ? data.verificationLevel
+ : VerificationLevels[data.verificationLevel];
+ }
+ if (typeof data.afkChannel !== 'undefined') {
+ _data.afk_channel_id = this.client.channels.resolveId(data.afkChannel);
+ }
+ if (typeof data.systemChannel !== 'undefined') {
+ _data.system_channel_id = this.client.channels.resolveId(
+ data.systemChannel,
+ );
+ }
+ if (data.afkTimeout) _data.afk_timeout = Number(data.afkTimeout);
+ if (typeof data.icon !== 'undefined')
+ _data.icon = await DataResolver.resolveImage(data.icon);
+ if (data.owner) _data.owner_id = this.client.users.resolveId(data.owner);
+ if (typeof data.splash !== 'undefined')
+ _data.splash = await DataResolver.resolveImage(data.splash);
+ if (typeof data.discoverySplash !== 'undefined') {
+ _data.discovery_splash = await DataResolver.resolveImage(
+ data.discoverySplash,
+ );
+ }
+ if (typeof data.banner !== 'undefined')
+ _data.banner = await DataResolver.resolveImage(data.banner);
+ if (typeof data.explicitContentFilter !== 'undefined') {
+ _data.explicit_content_filter =
+ typeof data.explicitContentFilter === 'number'
+ ? data.explicitContentFilter
+ : ExplicitContentFilterLevels[data.explicitContentFilter];
+ }
+ if (typeof data.defaultMessageNotifications !== 'undefined') {
+ _data.default_message_notifications =
+ typeof data.defaultMessageNotifications === 'number'
+ ? data.defaultMessageNotifications
+ : DefaultMessageNotificationLevels[data.defaultMessageNotifications];
+ }
+ if (typeof data.systemChannelFlags !== 'undefined') {
+ _data.system_channel_flags = SystemChannelFlags.resolve(
+ data.systemChannelFlags,
+ );
+ }
+ if (typeof data.rulesChannel !== 'undefined') {
+ _data.rules_channel_id = this.client.channels.resolveId(
+ data.rulesChannel,
+ );
+ }
+ if (typeof data.publicUpdatesChannel !== 'undefined') {
+ _data.public_updates_channel_id = this.client.channels.resolveId(
+ data.publicUpdatesChannel,
+ );
+ }
+ if (typeof data.features !== 'undefined') {
+ _data.features = data.features;
+ }
+ if (typeof data.description !== 'undefined') {
+ _data.description = data.description;
+ }
+ if (data.preferredLocale) _data.preferred_locale = data.preferredLocale;
+ if ('premiumProgressBarEnabled' in data)
+ _data.premium_progress_bar_enabled = data.premiumProgressBarEnabled;
+ const newData = await this.client.api
+ .guilds(this.id)
+ .patch({ data: _data, reason });
+ return this.client.actions.GuildUpdate.handle(newData).updated;
+ }
+
+ /**
+ * Welcome channel data
+ * @typedef {Object} WelcomeChannelData
+ * @property {string} description The description to show for this welcome channel
+ * @property {TextChannel|NewsChannel|StoreChannel|Snowflake} channel The channel to link for this welcome channel
+ * @property {EmojiIdentifierResolvable} [emoji] The emoji to display for this welcome channel
+ */
+
+ /**
+ * Welcome screen edit data
+ * @typedef {Object} WelcomeScreenEditData
+ * @property {boolean} [enabled] Whether the welcome screen is enabled
+ * @property {string} [description] The description for the welcome screen
+ * @property {WelcomeChannelData[]} [welcomeChannels] The welcome channel data for the welcome screen
+ */
+
+ /**
+ * Data that can be resolved to a GuildTextChannel object. This can be:
+ * * A TextChannel
+ * * A NewsChannel
+ * * A Snowflake
+ * @typedef {TextChannel|NewsChannel|Snowflake} GuildTextChannelResolvable
+ */
+
+ /**
+ * Data that can be resolved to a GuildVoiceChannel object. This can be:
+ * * A VoiceChannel
+ * * A StageChannel
+ * * A Snowflake
+ * @typedef {VoiceChannel|StageChannel|Snowflake} GuildVoiceChannelResolvable
+ */
+
+ /**
+ * Updates the guild's welcome screen
+ * @param {WelcomeScreenEditData} data Data to edit the welcome screen with
+ * @returns {Promise}
+ * @example
+ * guild.editWelcomeScreen({
+ * description: 'Hello World',
+ * enabled: true,
+ * welcomeChannels: [
+ * {
+ * description: 'foobar',
+ * channel: '222197033908436994',
+ * }
+ * ],
+ * })
+ */
+ async editWelcomeScreen(data) {
+ const { enabled, description, welcomeChannels } = data;
+ const welcome_channels = welcomeChannels?.map((welcomeChannelData) => {
+ const emoji = this.emojis.resolve(welcomeChannelData.emoji);
+ return {
+ emoji_id: emoji?.id,
+ emoji_name: emoji?.name ?? welcomeChannelData.emoji,
+ channel_id: this.channels.resolveId(welcomeChannelData.channel),
+ description: welcomeChannelData.description,
+ };
+ });
+
+ const patchData = await this.client.api
+ .guilds(this.id, 'welcome-screen')
+ .patch({
+ data: {
+ welcome_channels,
+ description,
+ enabled,
+ },
+ });
+ return new WelcomeScreen(this, patchData);
+ }
+
+ /**
+ * Edits the level of the explicit content filter.
+ * @param {ExplicitContentFilterLevel|number} explicitContentFilter The new level of the explicit content filter
+ * @param {string} [reason] Reason for changing the level of the guild's explicit content filter
+ * @returns {Promise}
+ */
+ setExplicitContentFilter(explicitContentFilter, reason) {
+ return this.edit({ explicitContentFilter }, reason);
+ }
+
+ /* eslint-disable max-len */
+ /**
+ * Edits the setting of the default message notifications of the guild.
+ * @param {DefaultMessageNotificationLevel|number} defaultMessageNotifications The new default message notification level of the guild
+ * @param {string} [reason] Reason for changing the setting of the default message notifications
+ * @returns {Promise}
+ */
+ setDefaultMessageNotifications(defaultMessageNotifications, reason) {
+ return this.edit({ defaultMessageNotifications }, reason);
+ }
+ /* eslint-enable max-len */
+
+ /**
+ * Edits the flags of the default message notifications of the guild.
+ * @param {SystemChannelFlagsResolvable} systemChannelFlags The new flags for the default message notifications
+ * @param {string} [reason] Reason for changing the flags of the default message notifications
+ * @returns {Promise}
+ */
+ setSystemChannelFlags(systemChannelFlags, reason) {
+ return this.edit({ systemChannelFlags }, reason);
+ }
+
+ /**
+ * Edits the name of the guild.
+ * @param {string} name The new name of the guild
+ * @param {string} [reason] Reason for changing the guild's name
+ * @returns {Promise}
+ * @example
+ * // Edit the guild name
+ * guild.setName('Discord Guild')
+ * .then(updated => console.log(`Updated guild name to ${updated.name}`))
+ * .catch(console.error);
+ */
+ setName(name, reason) {
+ return this.edit({ name }, reason);
+ }
+
+ /**
+ * Edits the verification level of the guild.
+ * @param {VerificationLevel|number} verificationLevel The new verification level of the guild
+ * @param {string} [reason] Reason for changing the guild's verification level
+ * @returns {Promise}
+ * @example
+ * // Edit the guild verification level
+ * guild.setVerificationLevel(1)
+ * .then(updated => console.log(`Updated guild verification level to ${guild.verificationLevel}`))
+ * .catch(console.error);
+ */
+ setVerificationLevel(verificationLevel, reason) {
+ return this.edit({ verificationLevel }, reason);
+ }
+
+ /**
+ * Edits the AFK channel of the guild.
+ * @param {VoiceChannelResolvable} afkChannel The new AFK channel
+ * @param {string} [reason] Reason for changing the guild's AFK channel
+ * @returns {Promise}
+ * @example
+ * // Edit the guild AFK channel
+ * guild.setAFKChannel(channel)
+ * .then(updated => console.log(`Updated guild AFK channel to ${guild.afkChannel.name}`))
+ * .catch(console.error);
+ */
+ setAFKChannel(afkChannel, reason) {
+ return this.edit({ afkChannel }, reason);
+ }
+
+ /**
+ * Edits the system channel of the guild.
+ * @param {TextChannelResolvable} systemChannel The new system channel
+ * @param {string} [reason] Reason for changing the guild's system channel
+ * @returns {Promise}
+ * @example
+ * // Edit the guild system channel
+ * guild.setSystemChannel(channel)
+ * .then(updated => console.log(`Updated guild system channel to ${guild.systemChannel.name}`))
+ * .catch(console.error);
+ */
+ setSystemChannel(systemChannel, reason) {
+ return this.edit({ systemChannel }, reason);
+ }
+
+ /**
+ * Edits the AFK timeout of the guild.
+ * @param {number} afkTimeout The time in seconds that a user must be idle to be considered AFK
+ * @param {string} [reason] Reason for changing the guild's AFK timeout
+ * @returns {Promise}
+ * @example
+ * // Edit the guild AFK channel
+ * guild.setAFKTimeout(60)
+ * .then(updated => console.log(`Updated guild AFK timeout to ${guild.afkTimeout}`))
+ * .catch(console.error);
+ */
+ setAFKTimeout(afkTimeout, reason) {
+ return this.edit({ afkTimeout }, reason);
+ }
+
+ /**
+ * Sets a new guild icon.
+ * @param {?(Base64Resolvable|BufferResolvable)} icon The new icon of the guild
+ * @param {string} [reason] Reason for changing the guild's icon
+ * @returns {Promise}
+ * @example
+ * // Edit the guild icon
+ * guild.setIcon('./icon.png')
+ * .then(updated => console.log('Updated the guild icon'))
+ * .catch(console.error);
+ */
+ setIcon(icon, reason) {
+ return this.edit({ icon }, reason);
+ }
+
+ /**
+ * Sets a new owner of the guild.
+ * @param {GuildMemberResolvable} owner The new owner of the guild
+ * @param {string} [reason] Reason for setting the new owner
+ * @returns {Promise}
+ * @example
+ * // Edit the guild owner
+ * guild.setOwner(guild.members.cache.first())
+ * .then(guild => guild.fetchOwner())
+ * .then(owner => console.log(`Updated the guild owner to ${owner.displayName}`))
+ * .catch(console.error);
+ */
+ setOwner(owner, reason) {
+ return this.edit({ owner }, reason);
+ }
+
+ /**
+ * Sets a new guild invite splash image.
+ * @param {?(Base64Resolvable|BufferResolvable)} splash The new invite splash image of the guild
+ * @param {string} [reason] Reason for changing the guild's invite splash image
+ * @returns {Promise}
+ * @example
+ * // Edit the guild splash
+ * guild.setSplash('./splash.png')
+ * .then(updated => console.log('Updated the guild splash'))
+ * .catch(console.error);
+ */
+ setSplash(splash, reason) {
+ return this.edit({ splash }, reason);
+ }
+
+ /**
+ * Sets a new guild discovery splash image.
+ * @param {?(Base64Resolvable|BufferResolvable)} discoverySplash The new discovery splash image of the guild
+ * @param {string} [reason] Reason for changing the guild's discovery splash image
+ * @returns {Promise}
+ * @example
+ * // Edit the guild discovery splash
+ * guild.setDiscoverySplash('./discoverysplash.png')
+ * .then(updated => console.log('Updated the guild discovery splash'))
+ * .catch(console.error);
+ */
+ setDiscoverySplash(discoverySplash, reason) {
+ return this.edit({ discoverySplash }, reason);
+ }
+
+ /**
+ * Sets a new guild banner.
+ * @param {?(Base64Resolvable|BufferResolvable)} banner The new banner of the guild
+ * @param {string} [reason] Reason for changing the guild's banner
+ * @returns {Promise}
+ * @example
+ * guild.setBanner('./banner.png')
+ * .then(updated => console.log('Updated the guild banner'))
+ * .catch(console.error);
+ */
+ setBanner(banner, reason) {
+ return this.edit({ banner }, reason);
+ }
+
+ /**
+ * Edits the rules channel of the guild.
+ * @param {TextChannelResolvable} rulesChannel The new rules channel
+ * @param {string} [reason] Reason for changing the guild's rules channel
+ * @returns {Promise}
+ * @example
+ * // Edit the guild rules channel
+ * guild.setRulesChannel(channel)
+ * .then(updated => console.log(`Updated guild rules channel to ${guild.rulesChannel.name}`))
+ * .catch(console.error);
+ */
+ setRulesChannel(rulesChannel, reason) {
+ return this.edit({ rulesChannel }, reason);
+ }
+ /**
+ * Change Guild Position (from * to Folder or Home)
+ * @param {number} position Guild Position
+ * * **WARNING**: Type = `FOLDER`, newPosition is the guild's index in the Folder.
+ * @param {String|Number} type Move to folder or home
+ * * `FOLDER`: 1
+ * * `HOME`: 2
+ * @param {String|Number|void|null} folderID If you want to move to folder
+ * @returns {Promise}
+ * @example
+ * // Move guild to folderID 123456, index 1
+ * guild.setPosition(1, 'FOLDER', 123456)
+ * .then(guild => console.log(`Guild moved to folderID ${guild.folder.folderId}`));
+ */
+ async setPosition(position, type, folderID) {
+ if (type == 1 || `${type}`.toUpperCase() === 'FOLDER') {
+ folderID = folderID || this.folder.folderId;
+ if (!['number', 'string'].includes(typeof folderID))
+ throw new TypeError('INVALID_TYPE', 'folderID', 'String | Number');
+ // Get Data from Folder ID
+ const folder = await this.client.setting.rawSetting.guild_folders.find(
+ (obj) => obj.id == folderID,
+ );
+ if (!folder) throw new Error('FOLDER_NOT_FOUND');
+ if (folder.guild_ids.length - 1 < position || position < 0)
+ throw new Error('FOLDER_POSITION_INVALID');
+ if (position !== folder.guild_ids.indexOf(this.id)) {
+ await this.client.setting.guildChangePosition(
+ this.id,
+ position,
+ 1,
+ folderID,
+ );
+ }
+ } else if (type == 2 || `${type}`.toUpperCase() === 'HOME') {
+ if (this.client.setting.guild_positions - 1 < position || position < 0)
+ throw new Error('FOLDER_POSITION_INVALID');
+ if (position !== this.position) {
+ await this.client.setting.guildChangePosition(
+ this.id,
+ position,
+ 2,
+ null,
+ );
+ }
+ } else {
+ throw new TypeError('INVALID_TYPE', 'type', '`Folder`| `Home`');
+ }
+ return this;
+ }
+
+ /**
+ * Edits the community updates channel of the guild.
+ * @param {TextChannelResolvable} publicUpdatesChannel The new community updates channel
+ * @param {string} [reason] Reason for changing the guild's community updates channel
+ * @returns {Promise}
+ * @example
+ * // Edit the guild community updates channel
+ * guild.setPublicUpdatesChannel(channel)
+ * .then(updated => console.log(`Updated guild community updates channel to ${guild.publicUpdatesChannel.name}`))
+ * .catch(console.error);
+ */
+ setPublicUpdatesChannel(publicUpdatesChannel, reason) {
+ return this.edit({ publicUpdatesChannel }, reason);
+ }
+
+ /**
+ * Edits the preferred locale of the guild.
+ * @param {string} preferredLocale The new preferred locale of the guild
+ * @param {string} [reason] Reason for changing the guild's preferred locale
+ * @returns {Promise}
+ * @example
+ * // Edit the guild preferred locale
+ * guild.setPreferredLocale('en-US')
+ * .then(updated => console.log(`Updated guild preferred locale to ${guild.preferredLocale}`))
+ * .catch(console.error);
+ */
+ setPreferredLocale(preferredLocale, reason) {
+ return this.edit({ preferredLocale }, reason);
+ }
+
+ /**
+ * Edits the enabled state of the guild's premium progress bar
+ * @param {boolean} [enabled=true] The new enabled state of the guild's premium progress bar
+ * @param {string} [reason] Reason for changing the state of the guild's premium progress bar
+ * @returns {Promise}
+ */
+ setPremiumProgressBarEnabled(enabled = true, reason) {
+ return this.edit({ premiumProgressBarEnabled: enabled }, reason);
+ }
+
+ /**
+ * Data that can be resolved to give a Category Channel object. This can be:
+ * * A CategoryChannel object
+ * * A Snowflake
+ * @typedef {CategoryChannel|Snowflake} CategoryChannelResolvable
+ */
+
+ /**
+ * The data needed for updating a channel's position.
+ * @typedef {Object} ChannelPosition
+ * @property {GuildChannel|Snowflake} channel Channel to update
+ * @property {number} [position] New position for the channel
+ * @property {CategoryChannelResolvable} [parent] Parent channel for this channel
+ * @property {boolean} [lockPermissions] If the overwrites should be locked to the parents overwrites
+ */
+
+ /**
+ * Batch-updates the guild's channels' positions.
+ * Only one channel's parent can be changed at a time
+ * @param {ChannelPosition[]} channelPositions Channel positions to update
+ * @returns {Promise}
+ * @deprecated Use {@link GuildChannelManager#setPositions} instead
+ * @example
+ * guild.setChannelPositions([{ channel: channelId, position: newChannelIndex }])
+ * .then(guild => console.log(`Updated channel positions for ${guild}`))
+ * .catch(console.error);
+ */
+ setChannelPositions(channelPositions) {
+ if (!deprecationEmittedForSetChannelPositions) {
+ process.emitWarning(
+ 'The Guild#setChannelPositions method is deprecated. Use GuildChannelManager#setPositions instead.',
+ 'DeprecationWarning',
+ );
+
+ deprecationEmittedForSetChannelPositions = true;
+ }
+
+ return this.channels.setPositions(channelPositions);
+ }
+
+ /**
+ * The data needed for updating a guild role's position
+ * @typedef {Object} GuildRolePosition
+ * @property {RoleResolvable} role The role's id
+ * @property {number} position The position to update
+ */
+
+ /**
+ * Batch-updates the guild's role positions
+ * @param {GuildRolePosition[]} rolePositions Role positions to update
+ * @returns {Promise}
+ * @deprecated Use {@link RoleManager#setPositions} instead
+ * @example
+ * guild.setRolePositions([{ role: roleId, position: updatedRoleIndex }])
+ * .then(guild => console.log(`Role positions updated for ${guild}`))
+ * .catch(console.error);
+ */
+ setRolePositions(rolePositions) {
+ if (!deprecationEmittedForSetRolePositions) {
+ process.emitWarning(
+ 'The Guild#setRolePositions method is deprecated. Use RoleManager#setPositions instead.',
+ 'DeprecationWarning',
+ );
+
+ deprecationEmittedForSetRolePositions = true;
+ }
+
+ return this.roles.setPositions(rolePositions);
+ }
+
+ /**
+ * Edits the guild's widget settings.
+ * @param {GuildWidgetSettingsData} settings The widget settings for the guild
+ * @param {string} [reason] Reason for changing the guild's widget settings
+ * @returns {Promise}
+ */
+ async setWidgetSettings(settings, reason) {
+ await this.client.api.guilds(this.id).widget.patch({
+ data: {
+ enabled: settings.enabled,
+ channel_id: this.channels.resolveId(settings.channel),
+ },
+ reason,
+ });
+ return this;
+ }
+
+ /**
+ * Leaves the guild.
+ * @returns {Promise}
+ * @example
+ * // Leave a guild
+ * guild.leave()
+ * .then(g => console.log(`Left the guild ${g}`))
+ * .catch(console.error);
+ */
+ async leave() {
+ if (this.ownerId === this.client.user.id) throw new Error('GUILD_OWNED');
+ await this.client.api.users('@me').guilds(this.id).delete();
+ return this.client.actions.GuildDelete.handle({ id: this.id }).guild;
+ }
+
+ /**
+ * Deletes the guild.
+ * @returns {Promise}
+ * @example
+ * // Delete a guild
+ * guild.delete()
+ * .then(g => console.log(`Deleted the guild ${g}`))
+ * .catch(console.error);
+ */
+ async delete() {
+ await this.client.api.guilds(this.id).delete();
+ return this.client.actions.GuildDelete.handle({ id: this.id }).guild;
+ }
+
+ /**
+ * Whether this guild equals another guild. It compares all properties, so for most operations
+ * it is advisable to just compare `guild.id === guild2.id` as it is much faster and is often
+ * what most users need.
+ * @param {Guild} guild The guild to compare with
+ * @returns {boolean}
+ */
+ equals(guild) {
+ return (
+ guild &&
+ guild instanceof this.constructor &&
+ this.id === guild.id &&
+ this.available === guild.available &&
+ this.splash === guild.splash &&
+ this.discoverySplash === guild.discoverySplash &&
+ this.name === guild.name &&
+ this.memberCount === guild.memberCount &&
+ this.large === guild.large &&
+ this.icon === guild.icon &&
+ this.ownerId === guild.ownerId &&
+ this.verificationLevel === guild.verificationLevel &&
+ (this.features === guild.features ||
+ (this.features.length === guild.features.length &&
+ this.features.every((feat, i) => feat === guild.features[i])))
+ );
+ }
+
+ /**
+ * Set Community Feature
+ * @param {Boolean} stats True / False to enable / disable Community Feature
+ * @param {TextChannelResolvable} publicUpdatesChannel
+ * @param {TextChannelResolvable} rulesChannel
+ * @param {String} reason
+ */
+ async setCommunity(
+ stats = true,
+ publicUpdatesChannel = '1',
+ rulesChannel = '1',
+ reason,
+ ) {
+ if (stats) {
+ // Check everyone role
+ const everyoneRole = this.roles.everyone;
+ if (everyoneRole.mentionable) {
+ await everyoneRole.setMentionable(false, reason);
+ }
+ // Setting
+ this.edit(
+ {
+ defaultMessageNotifications: 'ONLY_MENTIONS',
+ explicitContentFilter: 'ALL_MEMBERS',
+ features: [...this.features, 'COMMUNITY'],
+ publicUpdatesChannel,
+ rulesChannel,
+ verificationLevel:
+ VerificationLevels[this.verificationLevel] < 1
+ ? 'LOW'
+ : this.verificationLevel, // Email
+ },
+ reason,
+ );
+ } else {
+ this.edit(
+ {
+ publicUpdatesChannel: null,
+ rulesChannel: null,
+ features: this.features.filter((f) => f !== 'COMMUNITY'),
+ preferredLocale: this.preferredLocale,
+ description: this.description,
+ },
+ reason,
+ );
+ }
+ }
+
+ toJSON() {
+ const json = super.toJSON({
+ available: false,
+ createdTimestamp: true,
+ nameAcronym: true,
+ presences: false,
+ voiceStates: false,
+ });
+ json.iconURL = this.iconURL();
+ json.splashURL = this.splashURL();
+ json.discoverySplashURL = this.discoverySplashURL();
+ json.bannerURL = this.bannerURL();
+ return json;
+ }
+
+ /**
+ * The voice state adapter for this guild that can be used with @discordjs/voice to play audio in voice
+ * and stage channels.
+ * @type {Function}
+ * @readonly
+ */
+ get voiceAdapterCreator() {
+ return (methods) => {
+ this.client.voice.adapters.set(this.id, methods);
+ return {
+ sendPayload: (data) => {
+ if (this.shard.status !== Status.READY) return false;
+ this.shard.send(data);
+ return true;
+ },
+ destroy: () => {
+ this.client.voice.adapters.delete(this.id);
+ },
+ };
+ };
+ }
+
+ /**
+ * Creates a collection of this guild's roles, sorted by their position and ids.
+ * @returns {Collection}
+ * @private
+ */
+ _sortedRoles() {
+ return Util.discordSort(this.roles.cache);
+ }
+
+ /**
+ * Creates a collection of this guild's or a specific category's channels, sorted by their position and ids.
+ * @param {GuildChannel} [channel] Category to get the channels of
+ * @returns {Collection}
+ * @private
+ */
+ _sortedChannels(channel) {
+ const category = channel.type === ChannelTypes.GUILD_CATEGORY;
+ return Util.discordSort(
+ this.channels.cache.filter(
+ (c) =>
+ (['GUILD_TEXT', 'GUILD_NEWS', 'GUILD_STORE'].includes(channel.type)
+ ? ['GUILD_TEXT', 'GUILD_NEWS', 'GUILD_STORE'].includes(c.type)
+ : c.type === channel.type) &&
+ (category || c.parent === channel.parent),
+ ),
+ );
+ }
}
exports.Guild = Guild;
diff --git a/src/util/Constants.js b/src/util/Constants.js
index 42448f6..3c94256 100644
--- a/src/util/Constants.js
+++ b/src/util/Constants.js
@@ -347,6 +347,8 @@ exports.Events = {
TYPING_START: 'typingStart',
WEBHOOKS_UPDATE: 'webhookUpdate',
INTERACTION_CREATE: 'interactionCreate',
+ INTERACTION_SUCCESS: 'interactionSuccess',
+ INTERACTION_FAILED: 'interactionFailed',
ERROR: 'error',
WARN: 'warn',
DEBUG: 'debug',
diff --git a/typings/index.d.ts b/typings/index.d.ts
index e79d132..b5898e7 100644
--- a/typings/index.d.ts
+++ b/typings/index.d.ts
@@ -146,6 +146,7 @@ import {
RawWidgetData,
RawWidgetMemberData,
} from './rawDataTypes';
+import { RelationshipType } from '../src/util/Constants';
//#region Classes
@@ -975,6 +976,7 @@ export class Guild extends AnonymousGuild {
public fetchAuditLogs(
options?: GuildAuditLogsFetchOptions,
): Promise>;
+ public searchInteraction(options?: guildSearchInteraction): Promise;
public fetchIntegrations(): Promise>;
public fetchOwner(options?: BaseFetchOptions): Promise;
public fetchPreview(): Promise;
@@ -3886,6 +3888,14 @@ export interface BaseFetchOptions {
force?: boolean;
}
+export interface guildSearchInteraction {
+ type?: ApplicationCommandTypes,
+ query?: String | void,
+ limit?: Number,
+ offset?: Number,
+ botID?: Array,
+}
+
export interface BaseMessageComponentOptions {
type?: MessageComponentType | MessageComponentTypes;
}
@@ -4052,6 +4062,11 @@ export interface ClientEvents extends BaseClientEvents {
data: { count: number; index: number; nonce: string | undefined },
];
guildMemberUpdate: [oldMember: GuildMember | PartialGuildMember, newMember: GuildMember];
+ guildMemberListUpdate: [
+ members: Collection,
+ guild: Guild,
+ data: {}, // see: https://luna.gitlab.io/discord-unofficial-docs/lazy_guilds.html
+ ]
guildUpdate: [oldGuild: Guild, newGuild: Guild];
inviteCreate: [invite: Invite];
inviteDelete: [invite: Invite];
@@ -4089,7 +4104,9 @@ export interface ClientEvents extends BaseClientEvents {
webhookUpdate: [channel: TextChannel | NewsChannel];
/** @deprecated Use interactionCreate instead */
interaction: [interaction: Interaction];
- interactionCreate: [interaction: Interaction];
+ interactionCreate: [interaction: Interaction | { nonce: Snowflake, id: Snowflake }];
+ interactionSuccess: [interaction: { nonce: Snowflake, id: Snowflake }];
+ interactionFailed: [interaction: { nonce: Snowflake, id: Snowflake }];
shardDisconnect: [closeEvent: CloseEvent, shardId: number];
shardError: [error: Error, shardId: number];
shardReady: [shardId: number, unavailableGuilds: Set | undefined];
@@ -4106,6 +4123,16 @@ export interface ClientEvents extends BaseClientEvents {
guildScheduledEventDelete: [guildScheduledEvent: GuildScheduledEvent];
guildScheduledEventUserAdd: [guildScheduledEvent: GuildScheduledEvent, user: User];
guildScheduledEventUserRemove: [guildScheduledEvent: GuildScheduledEvent, user: User];
+ relationshipAdd: [
+ id: Snowflake,
+ type: RelationshipType,
+ user: User,
+ ]
+ relationshipRemove: [
+ id: Snowflake,
+ type: RelationshipType,
+ user: User,
+ ]
}
export interface ClientFetchInviteOptions {
@@ -4285,74 +4312,79 @@ export interface ConstantsEvents {
/** @deprecated See [this issue](https://github.com/discord/discord-api-docs/issues/3690) for more information. */
APPLICATION_COMMAND_DELETE: 'applicationCommandDelete';
/** @deprecated See [this issue](https://github.com/discord/discord-api-docs/issues/3690) for more information. */
- APPLICATION_COMMAND_UPDATE: 'applicationCommandUpdate';
- GUILD_CREATE: 'guildCreate';
- GUILD_DELETE: 'guildDelete';
- GUILD_UPDATE: 'guildUpdate';
- INVITE_CREATE: 'inviteCreate';
- INVITE_DELETE: 'inviteDelete';
- GUILD_UNAVAILABLE: 'guildUnavailable';
- GUILD_MEMBER_ADD: 'guildMemberAdd';
- GUILD_MEMBER_REMOVE: 'guildMemberRemove';
- GUILD_MEMBER_UPDATE: 'guildMemberUpdate';
- GUILD_MEMBER_AVAILABLE: 'guildMemberAvailable';
- GUILD_MEMBERS_CHUNK: 'guildMembersChunk';
- GUILD_INTEGRATIONS_UPDATE: 'guildIntegrationsUpdate';
- GUILD_ROLE_CREATE: 'roleCreate';
- GUILD_ROLE_DELETE: 'roleDelete';
- GUILD_ROLE_UPDATE: 'roleUpdate';
- GUILD_EMOJI_CREATE: 'emojiCreate';
- GUILD_EMOJI_DELETE: 'emojiDelete';
- GUILD_EMOJI_UPDATE: 'emojiUpdate';
- GUILD_BAN_ADD: 'guildBanAdd';
- GUILD_BAN_REMOVE: 'guildBanRemove';
- CHANNEL_CREATE: 'channelCreate';
- CHANNEL_DELETE: 'channelDelete';
- CHANNEL_UPDATE: 'channelUpdate';
- CHANNEL_PINS_UPDATE: 'channelPinsUpdate';
- MESSAGE_CREATE: 'messageCreate';
- MESSAGE_DELETE: 'messageDelete';
- MESSAGE_UPDATE: 'messageUpdate';
- MESSAGE_BULK_DELETE: 'messageDeleteBulk';
- MESSAGE_REACTION_ADD: 'messageReactionAdd';
- MESSAGE_REACTION_REMOVE: 'messageReactionRemove';
- MESSAGE_REACTION_REMOVE_ALL: 'messageReactionRemoveAll';
- MESSAGE_REACTION_REMOVE_EMOJI: 'messageReactionRemoveEmoji';
- THREAD_CREATE: 'threadCreate';
- THREAD_DELETE: 'threadDelete';
- THREAD_UPDATE: 'threadUpdate';
- THREAD_LIST_SYNC: 'threadListSync';
- THREAD_MEMBER_UPDATE: 'threadMemberUpdate';
- THREAD_MEMBERS_UPDATE: 'threadMembersUpdate';
- USER_UPDATE: 'userUpdate';
- PRESENCE_UPDATE: 'presenceUpdate';
- VOICE_SERVER_UPDATE: 'voiceServerUpdate';
- VOICE_STATE_UPDATE: 'voiceStateUpdate';
- TYPING_START: 'typingStart';
- WEBHOOKS_UPDATE: 'webhookUpdate';
- INTERACTION_CREATE: 'interactionCreate';
- ERROR: 'error';
- WARN: 'warn';
- DEBUG: 'debug';
- CACHE_SWEEP: 'cacheSweep';
- SHARD_DISCONNECT: 'shardDisconnect';
- SHARD_ERROR: 'shardError';
- SHARD_RECONNECTING: 'shardReconnecting';
- SHARD_READY: 'shardReady';
- SHARD_RESUME: 'shardResume';
- INVALIDATED: 'invalidated';
- RAW: 'raw';
- STAGE_INSTANCE_CREATE: 'stageInstanceCreate';
- STAGE_INSTANCE_UPDATE: 'stageInstanceUpdate';
- STAGE_INSTANCE_DELETE: 'stageInstanceDelete';
- GUILD_STICKER_CREATE: 'stickerCreate';
- GUILD_STICKER_DELETE: 'stickerDelete';
- GUILD_STICKER_UPDATE: 'stickerUpdate';
- GUILD_SCHEDULED_EVENT_CREATE: 'guildScheduledEventCreate';
- GUILD_SCHEDULED_EVENT_UPDATE: 'guildScheduledEventUpdate';
- GUILD_SCHEDULED_EVENT_DELETE: 'guildScheduledEventDelete';
- GUILD_SCHEDULED_EVENT_USER_ADD: 'guildScheduledEventUserAdd';
- GUILD_SCHEDULED_EVENT_USER_REMOVE: 'guildScheduledEventUserRemove';
+ APPLICATION_COMMAND_UPDATE: 'applicationCommandUpdate',
+ GUILD_CREATE: 'guildCreate',
+ GUILD_DELETE: 'guildDelete',
+ GUILD_UPDATE: 'guildUpdate',
+ GUILD_UNAVAILABLE: 'guildUnavailable',
+ GUILD_MEMBER_ADD: 'guildMemberAdd',
+ GUILD_MEMBER_REMOVE: 'guildMemberRemove',
+ GUILD_MEMBER_UPDATE: 'guildMemberUpdate',
+ GUILD_MEMBER_AVAILABLE: 'guildMemberAvailable',
+ GUILD_MEMBERS_CHUNK: 'guildMembersChunk',
+ GUILD_MEMBER_LIST_UPDATE: 'guildMemberListUpdate',
+ GUILD_INTEGRATIONS_UPDATE: 'guildIntegrationsUpdate',
+ GUILD_ROLE_CREATE: 'roleCreate',
+ GUILD_ROLE_DELETE: 'roleDelete',
+ INVITE_CREATE: 'inviteCreate',
+ INVITE_DELETE: 'inviteDelete',
+ GUILD_ROLE_UPDATE: 'roleUpdate',
+ GUILD_EMOJI_CREATE: 'emojiCreate',
+ GUILD_EMOJI_DELETE: 'emojiDelete',
+ GUILD_EMOJI_UPDATE: 'emojiUpdate',
+ GUILD_BAN_ADD: 'guildBanAdd',
+ GUILD_BAN_REMOVE: 'guildBanRemove',
+ CHANNEL_CREATE: 'channelCreate',
+ CHANNEL_DELETE: 'channelDelete',
+ CHANNEL_UPDATE: 'channelUpdate',
+ CHANNEL_PINS_UPDATE: 'channelPinsUpdate',
+ MESSAGE_CREATE: 'messageCreate',
+ MESSAGE_DELETE: 'messageDelete',
+ MESSAGE_UPDATE: 'messageUpdate',
+ MESSAGE_BULK_DELETE: 'messageDeleteBulk',
+ MESSAGE_REACTION_ADD: 'messageReactionAdd',
+ MESSAGE_REACTION_REMOVE: 'messageReactionRemove',
+ MESSAGE_REACTION_REMOVE_ALL: 'messageReactionRemoveAll',
+ MESSAGE_REACTION_REMOVE_EMOJI: 'messageReactionRemoveEmoji',
+ THREAD_CREATE: 'threadCreate',
+ THREAD_DELETE: 'threadDelete',
+ THREAD_UPDATE: 'threadUpdate',
+ THREAD_LIST_SYNC: 'threadListSync',
+ THREAD_MEMBER_UPDATE: 'threadMemberUpdate',
+ THREAD_MEMBERS_UPDATE: 'threadMembersUpdate',
+ USER_UPDATE: 'userUpdate',
+ PRESENCE_UPDATE: 'presenceUpdate',
+ VOICE_SERVER_UPDATE: 'voiceServerUpdate',
+ VOICE_STATE_UPDATE: 'voiceStateUpdate',
+ TYPING_START: 'typingStart',
+ WEBHOOKS_UPDATE: 'webhookUpdate',
+ INTERACTION_CREATE: 'interactionCreate',
+ INTERACTION_SUCCESS: 'interactionSuccess',
+ INTERACTION_FAILED: 'interactionFailed',
+ ERROR: 'error',
+ WARN: 'warn',
+ DEBUG: 'debug',
+ CACHE_SWEEP: 'cacheSweep',
+ SHARD_DISCONNECT: 'shardDisconnect',
+ SHARD_ERROR: 'shardError',
+ SHARD_RECONNECTING: 'shardReconnecting',
+ SHARD_READY: 'shardReady',
+ SHARD_RESUME: 'shardResume',
+ INVALIDATED: 'invalidated',
+ RAW: 'raw',
+ STAGE_INSTANCE_CREATE: 'stageInstanceCreate',
+ STAGE_INSTANCE_UPDATE: 'stageInstanceUpdate',
+ STAGE_INSTANCE_DELETE: 'stageInstanceDelete',
+ GUILD_STICKER_CREATE: 'stickerCreate',
+ GUILD_STICKER_DELETE: 'stickerDelete',
+ GUILD_STICKER_UPDATE: 'stickerUpdate',
+ GUILD_SCHEDULED_EVENT_CREATE: 'guildScheduledEventCreate',
+ GUILD_SCHEDULED_EVENT_UPDATE: 'guildScheduledEventUpdate',
+ GUILD_SCHEDULED_EVENT_DELETE: 'guildScheduledEventDelete',
+ GUILD_SCHEDULED_EVENT_USER_ADD: 'guildScheduledEventUserAdd',
+ GUILD_SCHEDULED_EVENT_USER_REMOVE: 'guildScheduledEventUserRemove',
+ RELATIONSHIP_ADD: 'relationshipAdd',
+ RELATIONSHIP_REMOVE: 'relationshipRemove',
}
export interface ConstantsOpcodes {