mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-09 16:13:31 +01:00
Partials (#3070)
* Remove GroupDMChannels they sparked no joy * Start partials for message deletion * MessageUpdate partials * Add partials as an opt-in client option * Add fetch() to Message * Message.author should never be undefined * Fix channels being the wrong type * Allow fetching channels * Refactor and add reaction add partials * Reaction remove partials * Check for emoji first * fix message fetching janky * User partials in audit logs * refactor overwrite code * guild member partials * partials as a whitelist * document GuildMember#fetch * fix: check whether a structure is a partial, not whether cache is true * typings: Updated for latest commit (#3075) * partials: fix messageUpdate behaviour (now "old" message can be partial) * partials: add warnings and docs * partials: add partials to index.yml * partials: tighten "partial" definitions * partials: fix embed-only messages counting as partials
This commit is contained in:
@@ -12,6 +12,8 @@
|
||||
path: voice.md
|
||||
- name: Web builds
|
||||
path: web.md
|
||||
- name: Partials
|
||||
path: partials.md
|
||||
- name: Examples
|
||||
files:
|
||||
- name: Ping
|
||||
|
||||
61
docs/topics/partials.md
Normal file
61
docs/topics/partials.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# Partials
|
||||
|
||||
Partials allow you to receive events that contain uncached instances, providing structures that contain very minimal
|
||||
data. For example, if you were to receive a `messageDelete` event with an uncached message, normally Discord.js would
|
||||
discard the event. With partials, you're able to receive the event, with a Message object that contains just an ID.
|
||||
|
||||
## Opting in
|
||||
|
||||
Partials are opt-in, and you can enable them in the Client options by specifying [PartialTypes](../typedef/PartialType):
|
||||
|
||||
```js
|
||||
// Accept partial messages and DM channels when emitting events
|
||||
new Client({ partials: ['MESSAGE', 'CHANNEL'] });
|
||||
```
|
||||
|
||||
## Usage & warnings
|
||||
|
||||
<warn>The only guaranteed data a partial structure can store is its ID. All other properties/methods should be
|
||||
considered invalid/defunct while accessing a partial structure.</warn>
|
||||
|
||||
After opting-in with the above, you begin to allow partial messages and channels in your caches, so it's important
|
||||
to check whether they're safe to access whenever you encounter them, whether it be in events or through normal cache
|
||||
usage.
|
||||
|
||||
All instance of structures that you opted-in for will have a `partial` property. As you'd expect, this value is `true`
|
||||
when the instance is partial. Partial structures are only guaranteed to contain an ID, any other properties and methods
|
||||
no longer carry their normal type guarantees.
|
||||
|
||||
This means you have to take time to consider possible parts of your program that might need checks put in place to
|
||||
prevent accessing partial data:
|
||||
|
||||
```js
|
||||
client.on('messageDelete', message => {
|
||||
console.log(`${message.id} was deleted!`);
|
||||
// Partial messages do not contain any content so skip them
|
||||
if (!message.partial) {
|
||||
console.log(`It had content: "${message.content}"`);
|
||||
}
|
||||
})
|
||||
|
||||
// You can also try to upgrade partials to full instances:
|
||||
client.on('messageReactionAdd', async (reaction, user) => {
|
||||
// If a message gains a reaction and it is uncached, fetch and cache the message
|
||||
// You should account for any errors while fetching, it could return API errors if the resource is missing
|
||||
if (reaction.message.partial) await reaction.message.fetch();
|
||||
// Now the message has been cached and is fully available:
|
||||
console.log(`${reaction.message.author}'s message "${reaction.message.content}" gained a reaction!`);
|
||||
});
|
||||
```
|
||||
|
||||
<info>If a message is deleted and both the message and channel are uncached, you must enable both 'MESSAGE' and
|
||||
'CHANNEL' in the client options to receive the messageDelete event.</info>
|
||||
|
||||
## Why?
|
||||
|
||||
This allows developers to listen to events that contain uncached data, which is useful if you're running a moderation
|
||||
bot or any bot that relies on still receiving updates to resources you don't have cached -- message reactions are a
|
||||
good example.
|
||||
|
||||
Currently, the only type of channel that can be uncached is a DM channel, there is no reason why guild channels should
|
||||
not be cached.
|
||||
@@ -434,6 +434,9 @@ class Client extends BaseClient {
|
||||
if (typeof options.disableEveryone !== 'boolean') {
|
||||
throw new TypeError('CLIENT_INVALID_OPTION', 'disableEveryone', 'a boolean');
|
||||
}
|
||||
if (!(options.partials instanceof Array)) {
|
||||
throw new TypeError('CLIENT_INVALID_OPTION', 'partials', 'an Array');
|
||||
}
|
||||
if (typeof options.restWsBridgeTimeout !== 'number' || isNaN(options.restWsBridgeTimeout)) {
|
||||
throw new TypeError('CLIENT_INVALID_OPTION', 'restWsBridgeTimeout', 'a number');
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
const { PartialTypes } = require('../../util/Constants');
|
||||
|
||||
/*
|
||||
|
||||
ABOUT ACTIONS
|
||||
@@ -20,6 +22,27 @@ class GenericAction {
|
||||
handle(data) {
|
||||
return data;
|
||||
}
|
||||
|
||||
getChannel(data) {
|
||||
const id = data.channel_id || data.id;
|
||||
return data.channel || (this.client.options.partials.includes(PartialTypes.CHANNEL) ?
|
||||
this.client.channels.add({
|
||||
id,
|
||||
guild_id: data.guild_id,
|
||||
}) :
|
||||
this.client.channels.get(id));
|
||||
}
|
||||
|
||||
getMessage(data, channel) {
|
||||
const id = data.message_id || data.id;
|
||||
return data.message || (this.client.options.partials.includes(PartialTypes.MESSAGE) ?
|
||||
channel.messages.add({
|
||||
id,
|
||||
channel_id: channel.id,
|
||||
guild_id: data.guild_id || (channel.guild ? channel.guild.id : null),
|
||||
}) :
|
||||
channel.messages.get(id));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GenericAction;
|
||||
|
||||
@@ -12,7 +12,7 @@ class ChannelCreateAction extends Action {
|
||||
/**
|
||||
* Emitted whenever a channel is created.
|
||||
* @event Client#channelCreate
|
||||
* @param {DMChannel|GroupDMChannel|GuildChannel} channel The channel that was created
|
||||
* @param {DMChannel|GuildChannel} channel The channel that was created
|
||||
*/
|
||||
client.emit(Events.CHANNEL_CREATE, channel);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ class ChannelDeleteAction extends Action {
|
||||
/**
|
||||
* Emitted whenever a channel is deleted.
|
||||
* @event Client#channelDelete
|
||||
* @param {DMChannel|GroupDMChannel|GuildChannel} channel The channel that was deleted
|
||||
* @param {DMChannel|GuildChannel} channel The channel that was deleted
|
||||
*/
|
||||
client.emit(Events.CHANNEL_DELETE, channel);
|
||||
}
|
||||
|
||||
@@ -6,11 +6,10 @@ const { Events } = require('../../util/Constants');
|
||||
class MessageDeleteAction extends Action {
|
||||
handle(data) {
|
||||
const client = this.client;
|
||||
const channel = client.channels.get(data.channel_id);
|
||||
const channel = this.getChannel(data);
|
||||
let message;
|
||||
|
||||
if (channel) {
|
||||
message = channel.messages.get(data.id);
|
||||
message = this.getMessage(data, channel);
|
||||
if (message) {
|
||||
channel.messages.delete(message.id);
|
||||
message.deleted = true;
|
||||
|
||||
@@ -11,15 +11,19 @@ const Action = require('./Action');
|
||||
|
||||
class MessageReactionAdd extends Action {
|
||||
handle(data) {
|
||||
if (!data.emoji) return false;
|
||||
|
||||
const user = data.user || this.client.users.get(data.user_id);
|
||||
if (!user) return false;
|
||||
|
||||
// Verify channel
|
||||
const channel = data.channel || this.client.channels.get(data.channel_id);
|
||||
const channel = this.getChannel(data);
|
||||
if (!channel || channel.type === 'voice') return false;
|
||||
|
||||
// Verify message
|
||||
const message = data.message || channel.messages.get(data.message_id);
|
||||
const message = this.getMessage(data, channel);
|
||||
if (!message) return false;
|
||||
if (!data.emoji) return false;
|
||||
|
||||
// Verify reaction
|
||||
const reaction = message.reactions.add({
|
||||
emoji: data.emoji,
|
||||
|
||||
@@ -12,15 +12,19 @@ const { Events } = require('../../util/Constants');
|
||||
|
||||
class MessageReactionRemove extends Action {
|
||||
handle(data) {
|
||||
if (!data.emoji) return false;
|
||||
|
||||
const user = this.client.users.get(data.user_id);
|
||||
if (!user) return false;
|
||||
|
||||
// Verify channel
|
||||
const channel = this.client.channels.get(data.channel_id);
|
||||
const channel = this.getChannel(data);
|
||||
if (!channel || channel.type === 'voice') return false;
|
||||
|
||||
// Verify message
|
||||
const message = channel.messages.get(data.message_id);
|
||||
const message = this.getMessage(data, channel);
|
||||
if (!message) return false;
|
||||
if (!data.emoji) return false;
|
||||
|
||||
// Verify reaction
|
||||
const emojiID = data.emoji.id || decodeURIComponent(data.emoji.name);
|
||||
const reaction = message.reactions.get(emojiID);
|
||||
|
||||
@@ -5,10 +5,12 @@ const { Events } = require('../../util/Constants');
|
||||
|
||||
class MessageReactionRemoveAll extends Action {
|
||||
handle(data) {
|
||||
const channel = this.client.channels.get(data.channel_id);
|
||||
// Verify channel
|
||||
const channel = this.getChannel(data);
|
||||
if (!channel || channel.type === 'voice') return false;
|
||||
|
||||
const message = channel.messages.get(data.message_id);
|
||||
// Verify message
|
||||
const message = this.getMessage(data, channel);
|
||||
if (!message) return false;
|
||||
|
||||
message.reactions.clear();
|
||||
|
||||
@@ -4,11 +4,10 @@ const Action = require('./Action');
|
||||
|
||||
class MessageUpdateAction extends Action {
|
||||
handle(data) {
|
||||
const client = this.client;
|
||||
|
||||
const channel = client.channels.get(data.channel_id);
|
||||
const channel = this.getChannel(data);
|
||||
if (channel) {
|
||||
const message = channel.messages.get(data.id);
|
||||
const { id, channel_id, guild_id, author, timestamp, type } = data;
|
||||
const message = this.getMessage({ id, channel_id, guild_id, author, timestamp, type }, channel);
|
||||
if (message) {
|
||||
message.patch(data);
|
||||
return {
|
||||
|
||||
@@ -14,7 +14,7 @@ module.exports = (client, { d: data }) => {
|
||||
* Emitted whenever the pins of a channel are updated. Due to the nature of the WebSocket event,
|
||||
* not much information can be provided easily here - you need to manually check the pins yourself.
|
||||
* @event Client#channelPinsUpdate
|
||||
* @param {DMChannel|GroupDMChannel|TextChannel} channel The channel that the pins update occured in
|
||||
* @param {DMChannel|TextChannel} channel The channel that the pins update occured in
|
||||
* @param {Date} time The time of the pins update
|
||||
*/
|
||||
client.emit(Events.CHANNEL_PINS_UPDATE, channel, time);
|
||||
|
||||
@@ -8,8 +8,8 @@ module.exports = (client, packet) => {
|
||||
/**
|
||||
* Emitted whenever a channel is updated - e.g. name change, topic change.
|
||||
* @event Client#channelUpdate
|
||||
* @param {DMChannel|GroupDMChannel|GuildChannel} oldChannel The channel before the update
|
||||
* @param {DMChannel|GroupDMChannel|GuildChannel} newChannel The channel after the update
|
||||
* @param {DMChannel|GuildChannel} oldChannel The channel before the update
|
||||
* @param {DMChannel|GuildChannel} newChannel The channel after the update
|
||||
*/
|
||||
client.emit(Events.CHANNEL_UPDATE, old, updated);
|
||||
}
|
||||
|
||||
@@ -65,7 +65,6 @@ module.exports = {
|
||||
Collector: require('./structures/interfaces/Collector'),
|
||||
DMChannel: require('./structures/DMChannel'),
|
||||
Emoji: require('./structures/Emoji'),
|
||||
GroupDMChannel: require('./structures/GroupDMChannel'),
|
||||
Guild: require('./structures/Guild'),
|
||||
GuildAuditLogs: require('./structures/GuildAuditLogs'),
|
||||
GuildChannel: require('./structures/GuildChannel'),
|
||||
|
||||
@@ -5,7 +5,7 @@ const Channel = require('../structures/Channel');
|
||||
const { Events } = require('../util/Constants');
|
||||
|
||||
const kLru = Symbol('LRU');
|
||||
const lruable = ['group', 'dm'];
|
||||
const lruable = ['dm'];
|
||||
|
||||
/**
|
||||
* Stores channels.
|
||||
@@ -54,6 +54,7 @@ class ChannelStore extends DataStore {
|
||||
|
||||
add(data, guild, cache = true) {
|
||||
const existing = this.get(data.id);
|
||||
if (existing && existing.partial && cache) existing._patch(data);
|
||||
if (existing) return existing;
|
||||
|
||||
const channel = Channel.create(this.client, data, guild);
|
||||
@@ -85,11 +86,12 @@ class ChannelStore extends DataStore {
|
||||
* .then(channel => console.log(channel.name))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
fetch(id, cache = true) {
|
||||
async fetch(id, cache = true) {
|
||||
const existing = this.get(id);
|
||||
if (existing) return Promise.resolve(existing);
|
||||
if (existing && !existing.partial) return existing;
|
||||
|
||||
return this.client.api.channels(id).get().then(data => this.add(data, null, cache));
|
||||
const data = await this.client.api.channels(id).get();
|
||||
return this.add(data, null, cache);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,6 +18,7 @@ class DataStore extends Collection {
|
||||
|
||||
add(data, cache = true, { id, extras = [] } = {}) {
|
||||
const existing = this.get(id || data.id);
|
||||
if (existing && existing.partial && cache && existing._patch) existing._patch(data);
|
||||
if (existing) return existing;
|
||||
|
||||
const entry = this.holds ? new this.holds(this.client, data, ...extras) : data;
|
||||
|
||||
@@ -180,7 +180,7 @@ class GuildMemberStore extends DataStore {
|
||||
|
||||
_fetchSingle({ user, cache }) {
|
||||
const existing = this.get(user);
|
||||
if (existing && existing.joinedTimestamp) return Promise.resolve(existing);
|
||||
if (existing && !existing.partial) return Promise.resolve(existing);
|
||||
return this.client.api.guilds(this.guild.id).members(user).get()
|
||||
.then(data => this.add(data, cache));
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ class MessageStore extends DataStore {
|
||||
* <info>The returned Collection does not contain reaction users of the messages if they were not cached.
|
||||
* Those need to be fetched separately in such a case.</info>
|
||||
* @param {Snowflake|ChannelLogsQueryOptions} [message] The ID of the message to fetch, or query parameters.
|
||||
* @param {boolean} [cache=true] Whether to cache the message(s)
|
||||
* @returns {Promise<Message>|Promise<Collection<Snowflake, Message>>}
|
||||
* @example
|
||||
* // Get message
|
||||
@@ -57,8 +58,8 @@ class MessageStore extends DataStore {
|
||||
* .then(messages => console.log(`${messages.filter(m => m.author.id === '84484653687267328').size} messages`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
fetch(message) {
|
||||
return typeof message === 'string' ? this._fetchId(message) : this._fetchMany(message);
|
||||
fetch(message, cache = true) {
|
||||
return typeof message === 'string' ? this._fetchId(message, cache) : this._fetchMany(message, cache);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,15 +81,17 @@ class MessageStore extends DataStore {
|
||||
});
|
||||
}
|
||||
|
||||
async _fetchId(messageID) {
|
||||
async _fetchId(messageID, cache) {
|
||||
const existing = this.get(messageID);
|
||||
if (existing && !existing.partial) return existing;
|
||||
const data = await this.client.api.channels[this.channel.id].messages[messageID].get();
|
||||
return this.add(data);
|
||||
return this.add(data, cache);
|
||||
}
|
||||
|
||||
async _fetchMany(options = {}) {
|
||||
async _fetchMany(options = {}, cache) {
|
||||
const data = await this.client.api.channels[this.channel.id].messages.get({ query: options });
|
||||
const messages = new Collection();
|
||||
for (const message of data) messages.set(message.id, this.add(message));
|
||||
for (const message of data) messages.set(message.id, this.add(message, cache));
|
||||
return messages;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,11 +51,11 @@ class UserStore extends DataStore {
|
||||
* @param {boolean} [cache=true] Whether to cache the new user object if it isn't already
|
||||
* @returns {Promise<User>}
|
||||
*/
|
||||
fetch(id, cache = true) {
|
||||
async fetch(id, cache = true) {
|
||||
const existing = this.get(id);
|
||||
if (existing) return Promise.resolve(existing);
|
||||
|
||||
return this.client.api.users(id).get().then(data => this.add(data, cache));
|
||||
if (existing && !existing.partial) return existing;
|
||||
const data = await this.client.api.users(id).get();
|
||||
return this.add(data, cache);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -330,7 +330,7 @@ module.exports = APIMessage;
|
||||
|
||||
/**
|
||||
* A target for a message.
|
||||
* @typedef {TextChannel|DMChannel|GroupDMChannel|User|GuildMember|Webhook|WebhookClient} MessageTarget
|
||||
* @typedef {TextChannel|DMChannel|User|GuildMember|Webhook|WebhookClient} MessageTarget
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,7 +16,6 @@ class Channel extends Base {
|
||||
/**
|
||||
* The type of the channel, either:
|
||||
* * `dm` - a DM channel
|
||||
* * `group` - a Group DM channel
|
||||
* * `text` - a guild text channel
|
||||
* * `voice` - a guild voice channel
|
||||
* * `category` - a guild category channel
|
||||
@@ -84,15 +83,20 @@ class Channel extends Base {
|
||||
return this.client.api.channels(this.id).delete().then(() => this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches this channel.
|
||||
* @returns {Promise<Channel>}
|
||||
*/
|
||||
fetch() {
|
||||
return this.client.channels.fetch(this.id, true);
|
||||
}
|
||||
|
||||
static create(client, data, guild) {
|
||||
const Structures = require('../util/Structures');
|
||||
let channel;
|
||||
if (data.type === ChannelTypes.DM) {
|
||||
if (data.type === ChannelTypes.DM || (data.type !== ChannelTypes.GROUP && !data.guild_id && !guild)) {
|
||||
const DMChannel = Structures.get('DMChannel');
|
||||
channel = new DMChannel(client, data);
|
||||
} else if (data.type === ChannelTypes.GROUP) {
|
||||
const GroupDMChannel = Structures.get('GroupDMChannel');
|
||||
channel = new GroupDMChannel(client, data);
|
||||
} else {
|
||||
guild = guild || client.guilds.get(data.guild_id);
|
||||
if (guild) {
|
||||
|
||||
@@ -164,42 +164,6 @@ class ClientUser extends Structures.get('User') {
|
||||
setAFK(afk) {
|
||||
return this.setPresence({ afk });
|
||||
}
|
||||
|
||||
/**
|
||||
* An object containing either a user or access token, and an optional nickname.
|
||||
* @typedef {Object} GroupDMRecipientOptions
|
||||
* @property {UserResolvable} [user] User to add to the Group DM
|
||||
* @property {string} [accessToken] Access token to use to add a user to the Group DM
|
||||
* (only available if a bot is creating the DM)
|
||||
* @property {string} [nick] Permanent nickname (only available if a bot is creating the DM)
|
||||
* @property {string} [id] If no user resolvable is provided and you want to assign nicknames
|
||||
* you must provide user ids instead
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a Group DM.
|
||||
* @param {GroupDMRecipientOptions[]} recipients The recipients
|
||||
* @returns {Promise<GroupDMChannel>}
|
||||
* @example
|
||||
* // Create a Group DM with a token provided from OAuth
|
||||
* client.user.createGroupDM([{
|
||||
* user: '66564597481480192',
|
||||
* accessToken: token
|
||||
* }])
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
*/
|
||||
createGroupDM(recipients) {
|
||||
const data = this.bot ? {
|
||||
access_tokens: recipients.map(u => u.accessToken),
|
||||
nicks: recipients.reduce((o, r) => {
|
||||
if (r.nick) o[r.user ? r.user.id : r.id] = r.nick;
|
||||
return o;
|
||||
}, {}),
|
||||
} : { recipients: recipients.map(u => this.client.users.resolveID(u.user || u.id)) };
|
||||
return this.client.api.users('@me').channels.post({ data })
|
||||
.then(res => this.client.channels.add(res));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ClientUser;
|
||||
|
||||
@@ -12,6 +12,8 @@ const MessageStore = require('../stores/MessageStore');
|
||||
class DMChannel extends Channel {
|
||||
constructor(client, data) {
|
||||
super(client, data);
|
||||
// Override the channel type so partials have a known type
|
||||
this.type = 'dm';
|
||||
/**
|
||||
* A collection containing the messages sent to this channel
|
||||
* @type {MessageStore<Snowflake, Message>}
|
||||
@@ -23,11 +25,13 @@ class DMChannel extends Channel {
|
||||
_patch(data) {
|
||||
super._patch(data);
|
||||
|
||||
/**
|
||||
* The recipient on the other end of the DM
|
||||
* @type {User}
|
||||
*/
|
||||
this.recipient = this.client.users.add(data.recipients[0]);
|
||||
if (data.recipients) {
|
||||
/**
|
||||
* The recipient on the other end of the DM
|
||||
* @type {User}
|
||||
*/
|
||||
this.recipient = this.client.users.add(data.recipients[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* The ID of the last message in the channel, if one was sent
|
||||
@@ -42,6 +46,14 @@ class DMChannel extends Channel {
|
||||
this.lastPinTimestamp = data.last_pin_timestamp ? new Date(data.last_pin_timestamp).getTime() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this DMChannel is a partial
|
||||
* @type {boolean}
|
||||
*/
|
||||
get partial() {
|
||||
return !this.recipient;
|
||||
}
|
||||
|
||||
/**
|
||||
* When concatenated with a string, this automatically returns the recipient's mention instead of the
|
||||
* DMChannel object.
|
||||
|
||||
@@ -1,245 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const Channel = require('./Channel');
|
||||
const TextBasedChannel = require('./interfaces/TextBasedChannel');
|
||||
const Collection = require('../util/Collection');
|
||||
const DataResolver = require('../util/DataResolver');
|
||||
const MessageStore = require('../stores/MessageStore');
|
||||
|
||||
/*
|
||||
{ type: 3,
|
||||
recipients:
|
||||
[ { username: 'Charlie',
|
||||
id: '123',
|
||||
discriminator: '6631',
|
||||
avatar: '123' },
|
||||
{ username: 'Ben',
|
||||
id: '123',
|
||||
discriminator: '2055',
|
||||
avatar: '123' },
|
||||
{ username: 'Adam',
|
||||
id: '123',
|
||||
discriminator: '2406',
|
||||
avatar: '123' } ],
|
||||
owner_id: '123',
|
||||
name: null,
|
||||
last_message_id: '123',
|
||||
id: '123',
|
||||
icon: null }
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a Group DM on Discord.
|
||||
* @extends {Channel}
|
||||
* @implements {TextBasedChannel}
|
||||
*/
|
||||
class GroupDMChannel extends Channel {
|
||||
constructor(client, data) {
|
||||
super(client, data);
|
||||
/**
|
||||
* A collection containing the messages sent to this channel
|
||||
* @type {MessageStore<Snowflake, Message>}
|
||||
*/
|
||||
this.messages = new MessageStore(this);
|
||||
this._typing = new Map();
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
super._patch(data);
|
||||
|
||||
/**
|
||||
* The name of this Group DM, can be null if one isn't set
|
||||
* @type {string}
|
||||
*/
|
||||
this.name = data.name;
|
||||
|
||||
/**
|
||||
* A hash of this Group DM icon
|
||||
* @type {?string}
|
||||
*/
|
||||
this.icon = data.icon;
|
||||
|
||||
/**
|
||||
* The user ID of this Group DM's owner
|
||||
* @type {Snowflake}
|
||||
*/
|
||||
this.ownerID = data.owner_id;
|
||||
|
||||
/**
|
||||
* If the DM is managed by an application
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.managed = data.managed;
|
||||
|
||||
/**
|
||||
* Application ID of the application that made this Group DM, if applicable
|
||||
* @type {?Snowflake}
|
||||
*/
|
||||
this.applicationID = data.application_id;
|
||||
|
||||
if (data.nicks) {
|
||||
/**
|
||||
* Nicknames for group members
|
||||
* @type {?Collection<Snowflake, string>}
|
||||
*/
|
||||
this.nicks = new Collection(data.nicks.map(n => [n.id, n.nick]));
|
||||
}
|
||||
|
||||
if (!this.recipients) {
|
||||
/**
|
||||
* A collection of the recipients of this DM, mapped by their ID
|
||||
* @type {Collection<Snowflake, User>}
|
||||
*/
|
||||
this.recipients = new Collection();
|
||||
}
|
||||
|
||||
if (data.recipients) {
|
||||
for (const recipient of data.recipients) {
|
||||
const user = this.client.users.add(recipient);
|
||||
this.recipients.set(user.id, user);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The ID of the last message in the channel, if one was sent
|
||||
* @type {?Snowflake}
|
||||
*/
|
||||
this.lastMessageID = data.last_message_id;
|
||||
|
||||
/**
|
||||
* The timestamp when the last pinned message was pinned, if there was one
|
||||
* @type {?number}
|
||||
*/
|
||||
this.lastPinTimestamp = data.last_pin_timestamp ? new Date(data.last_pin_timestamp).getTime() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The owner of this Group DM
|
||||
* @type {?User}
|
||||
* @readonly
|
||||
*/
|
||||
get owner() {
|
||||
return this.client.users.get(this.ownerID) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the URL to this Group DM's icon.
|
||||
* @param {ImageURLOptions} [options={}] Options for the Image URL
|
||||
* @returns {?string}
|
||||
*/
|
||||
iconURL({ format, size } = {}) {
|
||||
if (!this.icon) return null;
|
||||
return this.client.rest.cdn.GDMIcon(this.id, this.icon, format, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this channel equals another channel. It compares all properties, so for most operations
|
||||
* it is advisable to just compare `channel.id === channel2.id` as it is much faster and is often
|
||||
* what most users need.
|
||||
* @param {GroupDMChannel} channel Channel to compare with
|
||||
* @returns {boolean}
|
||||
*/
|
||||
equals(channel) {
|
||||
const equal = channel &&
|
||||
this.id === channel.id &&
|
||||
this.name === channel.name &&
|
||||
this.icon === channel.icon &&
|
||||
this.ownerID === channel.ownerID;
|
||||
|
||||
if (equal) {
|
||||
return this.recipients.equals(channel.recipients);
|
||||
}
|
||||
|
||||
return equal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits this Group DM.
|
||||
* @param {Object} data New data for this Group DM
|
||||
* @param {string} [reason] Reason for editing this Group DM
|
||||
* @returns {Promise<GroupDMChannel>}
|
||||
*/
|
||||
edit(data, reason) {
|
||||
return this.client.api.channels[this.id].patch({
|
||||
data: {
|
||||
icon: data.icon,
|
||||
name: data.name === null ? null : data.name || this.name,
|
||||
},
|
||||
reason,
|
||||
}).then(() => this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new icon for this Group DM.
|
||||
* @param {Base64Resolvable|BufferResolvable} icon The new icon of this Group DM
|
||||
* @returns {Promise<GroupDMChannel>}
|
||||
*/
|
||||
async setIcon(icon) {
|
||||
return this.edit({ icon: await DataResolver.resolveImage(icon) });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new name for this Group DM.
|
||||
* @param {string} name New name for this Group DM
|
||||
* @returns {Promise<GroupDMChannel>}
|
||||
*/
|
||||
setName(name) {
|
||||
return this.edit({ name });
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a user to this Group DM.
|
||||
* @param {Object} options Options for this method
|
||||
* @param {UserResolvable} options.user User to add to this Group DM
|
||||
* @param {string} [options.accessToken] Access token to use to add the user to this Group DM
|
||||
* @param {string} [options.nick] Permanent nickname to give the user
|
||||
* @returns {Promise<GroupDMChannel>}
|
||||
*/
|
||||
addUser({ user, accessToken, nick }) {
|
||||
const id = this.client.users.resolveID(user);
|
||||
return this.client.api.channels[this.id].recipients[id].put({ nick, access_token: accessToken })
|
||||
.then(() => this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a user from this Group DM.
|
||||
* @param {UserResolvable} user User to remove
|
||||
* @returns {Promise<GroupDMChannel>}
|
||||
*/
|
||||
removeUser(user) {
|
||||
const id = this.client.users.resolveID(user);
|
||||
return this.client.api.channels[this.id].recipients[id].delete()
|
||||
.then(() => this);
|
||||
}
|
||||
|
||||
/**
|
||||
* When concatenated with a string, this automatically returns the channel's name instead of the
|
||||
* GroupDMChannel object.
|
||||
* @returns {string}
|
||||
* @example
|
||||
* // Logs: Hello from My Group DM!
|
||||
* console.log(`Hello from ${channel}!`);
|
||||
*/
|
||||
toString() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
// These are here only for documentation purposes - they are implemented by TextBasedChannel
|
||||
/* eslint-disable no-empty-function */
|
||||
get lastMessage() {}
|
||||
get lastPinAt() {}
|
||||
send() {}
|
||||
startTyping() {}
|
||||
stopTyping() {}
|
||||
get typing() {}
|
||||
get typingCount() {}
|
||||
createMessageCollector() {}
|
||||
awaitMessages() {}
|
||||
// Doesn't work on Group DMs; bulkDelete() {}
|
||||
acknowledge() {}
|
||||
_cacheMessage() {}
|
||||
}
|
||||
|
||||
TextBasedChannel.applyToClass(GroupDMChannel, true, ['bulkDelete']);
|
||||
|
||||
module.exports = GroupDMChannel;
|
||||
@@ -5,7 +5,7 @@ const Integration = require('./Integration');
|
||||
const GuildAuditLogs = require('./GuildAuditLogs');
|
||||
const Webhook = require('./Webhook');
|
||||
const VoiceRegion = require('./VoiceRegion');
|
||||
const { ChannelTypes, DefaultMessageNotifications, browser } = require('../util/Constants');
|
||||
const { ChannelTypes, DefaultMessageNotifications, PartialTypes, browser } = require('../util/Constants');
|
||||
const Collection = require('../util/Collection');
|
||||
const Util = require('../util/Util');
|
||||
const DataResolver = require('../util/DataResolver');
|
||||
@@ -341,7 +341,9 @@ class Guild extends Base {
|
||||
* @readonly
|
||||
*/
|
||||
get owner() {
|
||||
return this.members.get(this.ownerID) || null;
|
||||
return this.members.get(this.ownerID) || (this.client.options.partials.includes(PartialTypes.GUILD_MEMBER) ?
|
||||
this.members.add({ user: { id: this.ownerID } }, true) :
|
||||
null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,7 @@ const Collection = require('../util/Collection');
|
||||
const Snowflake = require('../util/Snowflake');
|
||||
const Webhook = require('./Webhook');
|
||||
const Util = require('../util/Util');
|
||||
const PartialTypes = require('../util/Constants');
|
||||
|
||||
/**
|
||||
* The target type of an entry, e.g. `GUILD`. Here are the available types:
|
||||
@@ -234,7 +235,7 @@ class GuildAuditLogs {
|
||||
* Audit logs entry.
|
||||
*/
|
||||
class GuildAuditLogsEntry {
|
||||
constructor(logs, guild, data) {
|
||||
constructor(logs, guild, data) { // eslint-disable-line complexity
|
||||
const targetType = GuildAuditLogs.targetType(data.action_type);
|
||||
/**
|
||||
* The target type of this entry
|
||||
@@ -264,7 +265,9 @@ class GuildAuditLogsEntry {
|
||||
* The user that executed this entry
|
||||
* @type {User}
|
||||
*/
|
||||
this.executor = guild.client.users.get(data.user_id);
|
||||
this.executor = guild.client.options.partials.includes(PartialTypes.USER) ?
|
||||
guild.client.users.add({ id: data.user_id }) :
|
||||
guild.client.users.get(data.user_id);
|
||||
|
||||
/**
|
||||
* An entry in the audit log representing a specific change.
|
||||
@@ -329,8 +332,12 @@ class GuildAuditLogsEntry {
|
||||
return o;
|
||||
}, {});
|
||||
this.target.id = data.target_id;
|
||||
} else if ([Targets.USER, Targets.GUILD].includes(targetType)) {
|
||||
this.target = guild.client[`${targetType.toLowerCase()}s`].get(data.target_id);
|
||||
} else if (targetType === Targets.USER) {
|
||||
this.target = guild.client.options.partials.includes(PartialTypes.USER) ?
|
||||
guild.client.users.add({ id: data.target_id }) :
|
||||
guild.client.users.get(data.target_id);
|
||||
} else if (targetType === Targets.GUILD) {
|
||||
this.target = guild.client.guilds.get(data.target_id);
|
||||
} else if (targetType === Targets.WEBHOOK) {
|
||||
this.target = logs.webhooks.get(data.target_id) ||
|
||||
new Webhook(guild.client,
|
||||
|
||||
@@ -28,7 +28,7 @@ class GuildMember extends Base {
|
||||
* The user that this guild member instance represents
|
||||
* @type {User}
|
||||
*/
|
||||
this.user = {};
|
||||
if (data.user) this.user = client.users.add(data.user, true);
|
||||
|
||||
/**
|
||||
* The timestamp the member joined the guild at
|
||||
@@ -79,6 +79,14 @@ class GuildMember extends Base {
|
||||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this GuildMember is a partial
|
||||
* @type {boolean}
|
||||
*/
|
||||
get partial() {
|
||||
return !this.joinedTimestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* A collection of roles that are applied to this member, mapped by the role ID
|
||||
* @type {GuildMemberRoleStore<Snowflake, Role>}
|
||||
@@ -355,6 +363,14 @@ class GuildMember extends Base {
|
||||
return this.guild.members.ban(this, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches this GuildMember.
|
||||
* @returns {Promise<GuildMember>}
|
||||
*/
|
||||
fetch() {
|
||||
return this.guild.members.fetch(this.id, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* When concatenated with a string, this automatically returns the user's mention instead of the GuildMember object.
|
||||
* @returns {string}
|
||||
|
||||
@@ -24,7 +24,7 @@ class Message extends Base {
|
||||
|
||||
/**
|
||||
* The channel that the message was sent in
|
||||
* @type {TextChannel|DMChannel|GroupDMChannel}
|
||||
* @type {TextChannel|DMChannel}
|
||||
*/
|
||||
this.channel = channel;
|
||||
|
||||
@@ -60,7 +60,7 @@ class Message extends Base {
|
||||
* The author of the message
|
||||
* @type {User}
|
||||
*/
|
||||
this.author = this.client.users.add(data.author, !data.webhook_id);
|
||||
this.author = data.author ? this.client.users.add(data.author, !data.webhook_id) : null;
|
||||
|
||||
/**
|
||||
* Whether or not this message is pinned
|
||||
@@ -90,17 +90,19 @@ class Message extends Base {
|
||||
* A list of embeds in the message - e.g. YouTube Player
|
||||
* @type {MessageEmbed[]}
|
||||
*/
|
||||
this.embeds = data.embeds.map(e => new Embed(e));
|
||||
this.embeds = (data.embeds || []).map(e => new Embed(e));
|
||||
|
||||
/**
|
||||
* A collection of attachments in the message - e.g. Pictures - mapped by their ID
|
||||
* @type {Collection<Snowflake, MessageAttachment>}
|
||||
*/
|
||||
this.attachments = new Collection();
|
||||
for (const attachment of data.attachments) {
|
||||
this.attachments.set(attachment.id, new MessageAttachment(
|
||||
attachment.url, attachment.filename, attachment
|
||||
));
|
||||
if (data.attachments) {
|
||||
for (const attachment of data.attachments) {
|
||||
this.attachments.set(attachment.id, new MessageAttachment(
|
||||
attachment.url, attachment.filename, attachment
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,6 +169,14 @@ class Message extends Base {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this message is a partial
|
||||
* @type {boolean}
|
||||
*/
|
||||
get partial() {
|
||||
return typeof this.content !== 'string' || !this.author;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the message.
|
||||
* @param {Object} data Raw Discord message update data
|
||||
@@ -472,6 +482,14 @@ class Message extends Base {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch this message.
|
||||
* @returns {Promise<Message>}
|
||||
*/
|
||||
fetch() {
|
||||
return this.channel.messages.fetch(this.id, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the webhook used to create this message.
|
||||
* @returns {Promise<?Webhook>}
|
||||
|
||||
@@ -15,7 +15,7 @@ const { Events } = require('../util/Constants');
|
||||
*/
|
||||
class MessageCollector extends Collector {
|
||||
/**
|
||||
* @param {TextChannel|DMChannel|GroupDMChannel} channel The channel
|
||||
* @param {TextChannel|DMChannel} channel The channel
|
||||
* @param {CollectorFilter} filter The filter to be applied to this collector
|
||||
* @param {MessageCollectorOptions} options The options to be applied to this collector
|
||||
* @emits MessageCollector#message
|
||||
|
||||
@@ -53,6 +53,8 @@ class User extends Base {
|
||||
*/
|
||||
if (typeof data.avatar !== 'undefined') this.avatar = data.avatar;
|
||||
|
||||
if (typeof data.bot !== 'undefined') this.bot = Boolean(data.bot);
|
||||
|
||||
/**
|
||||
* The locale of the user's client (ISO 639-1)
|
||||
* @type {?string}
|
||||
@@ -73,6 +75,14 @@ class User extends Base {
|
||||
this.lastMessageChannelID = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this User is a partial
|
||||
* @type {boolean}
|
||||
*/
|
||||
get partial() {
|
||||
return typeof this.username !== 'string';
|
||||
}
|
||||
|
||||
/**
|
||||
* The timestamp the user was created at
|
||||
* @type {number}
|
||||
@@ -228,6 +238,14 @@ class User extends Base {
|
||||
return equal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches this user.
|
||||
* @returns {Promise<User>}
|
||||
*/
|
||||
fetch() {
|
||||
return this.client.users.fetch(this.id, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* When concatenated with a string, this automatically returns the user's mention instead of the User object.
|
||||
* @returns {string}
|
||||
|
||||
@@ -21,6 +21,9 @@ const browser = exports.browser = typeof window !== 'undefined';
|
||||
* @property {boolean} [fetchAllMembers=false] Whether to cache all guild members and users upon startup, as well as
|
||||
* upon joining a guild (should be avoided whenever possible)
|
||||
* @property {boolean} [disableEveryone=false] Default value for {@link MessageOptions#disableEveryone}
|
||||
* @property {PartialType[]} [partials] Structures allowed to be partial. This means events can be emitted even when
|
||||
* they're missing all the data for a particular structure. See the "Partials" topic listed in the sidebar for some
|
||||
* important usage information, as partials require you to put checks in place when handling data.
|
||||
* @property {number} [restWsBridgeTimeout=5000] Maximum time permitted between REST responses and their
|
||||
* corresponding websocket events
|
||||
* @property {number} [restTimeOffset=500] Extra time in millseconds to wait before continuing to make REST
|
||||
@@ -44,6 +47,7 @@ exports.DefaultOptions = {
|
||||
messageSweepInterval: 0,
|
||||
fetchAllMembers: false,
|
||||
disableEveryone: false,
|
||||
partials: [],
|
||||
restWsBridgeTimeout: 5000,
|
||||
disabledEvents: [],
|
||||
retryLimit: 1,
|
||||
@@ -261,6 +265,23 @@ exports.Events = {
|
||||
RAW: 'raw',
|
||||
};
|
||||
|
||||
/**
|
||||
* The type of Structure allowed to be a partial:
|
||||
* * USER
|
||||
* * CHANNEL (only affects DMChannels)
|
||||
* * GUILD_MEMBER
|
||||
* * MESSAGE
|
||||
* <warn>Partials require you to put checks in place when handling data, read the Partials topic listed in the
|
||||
* sidebar for more information.</warn>
|
||||
* @typedef {string} PartialType
|
||||
*/
|
||||
exports.PartialTypes = keyMirror([
|
||||
'USER',
|
||||
'CHANNEL',
|
||||
'GUILD_MEMBER',
|
||||
'MESSAGE',
|
||||
]);
|
||||
|
||||
/**
|
||||
* The type of a websocket message event, e.g. `MESSAGE_CREATE`. Here are the available events:
|
||||
* * READY
|
||||
|
||||
@@ -67,7 +67,6 @@ class Structures {
|
||||
const structures = {
|
||||
GuildEmoji: require('../structures/GuildEmoji'),
|
||||
DMChannel: require('../structures/DMChannel'),
|
||||
GroupDMChannel: require('../structures/GroupDMChannel'),
|
||||
TextChannel: require('../structures/TextChannel'),
|
||||
VoiceChannel: require('../structures/VoiceChannel'),
|
||||
CategoryChannel: require('../structures/CategoryChannel'),
|
||||
|
||||
@@ -395,7 +395,7 @@ class Util {
|
||||
.replace(/@(everyone|here)/g, '@\u200b$1')
|
||||
.replace(/<@!?[0-9]+>/g, input => {
|
||||
const id = input.replace(/<|!|>|@/g, '');
|
||||
if (message.channel.type === 'dm' || message.channel.type === 'group') {
|
||||
if (message.channel.type === 'dm') {
|
||||
const user = message.client.users.get(id);
|
||||
return user ? `@${user.username}` : input;
|
||||
}
|
||||
@@ -413,7 +413,7 @@ class Util {
|
||||
return channel ? `#${channel.name}` : input;
|
||||
})
|
||||
.replace(/<@&[0-9]+>/g, input => {
|
||||
if (message.channel.type === 'dm' || message.channel.type === 'group') return input;
|
||||
if (message.channel.type === 'dm') return input;
|
||||
const role = message.guild.roles.get(input.replace(/<|@|>|&/g, ''));
|
||||
return role ? `@${role.name}` : input;
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ const ytdl = require('ytdl-core');
|
||||
const prism = require('prism-media');
|
||||
const fs = require('fs');
|
||||
|
||||
const client = new Discord.Client({ fetchAllMembers: false, apiRequestMethod: 'sequential' });
|
||||
const client = new Discord.Client({ fetchAllMembers: false, partials: true, apiRequestMethod: 'sequential' });
|
||||
|
||||
const auth = require('./auth.js');
|
||||
|
||||
@@ -34,6 +34,15 @@ client.on('presenceUpdate', (a, b) => {
|
||||
console.log(a ? a.status : null, b.status, b.user.username);
|
||||
});
|
||||
|
||||
client.on('messageDelete', async (m) => {
|
||||
if (m.channel.id != '80426989059575808') return;
|
||||
console.log(m.channel.recipient);
|
||||
console.log(m.channel.partial);
|
||||
await m.channel.fetch();
|
||||
console.log('\n\n\n\n');
|
||||
console.log(m.channel);
|
||||
});
|
||||
|
||||
client.on('message', m => {
|
||||
if (!m.guild) return;
|
||||
if (m.author.id !== '66564597481480192') return;
|
||||
|
||||
57
typings/index.d.ts
vendored
57
typings/index.d.ts
vendored
@@ -129,8 +129,9 @@ declare module 'discord.js' {
|
||||
public readonly createdTimestamp: number;
|
||||
public deleted: boolean;
|
||||
public id: Snowflake;
|
||||
public type: 'dm' | 'group' | 'text' | 'voice' | 'category' | 'unknown';
|
||||
public type: 'dm' | 'text' | 'voice' | 'category' | 'unknown';
|
||||
public delete(reason?: string): Promise<Channel>;
|
||||
public fetch(): Promise<Channel>;
|
||||
public toString(): string;
|
||||
}
|
||||
|
||||
@@ -264,7 +265,6 @@ declare module 'discord.js' {
|
||||
export class ClientUser extends User {
|
||||
public mfaEnabled: boolean;
|
||||
public verified: boolean;
|
||||
public createGroupDM(recipients: GroupDMRecipientOptions[]): Promise<GroupDMChannel>;
|
||||
public setActivity(options?: ActivityOptions): Promise<Presence>;
|
||||
public setActivity(name: string, options?: ActivityOptions): Promise<Presence>;
|
||||
public setAFK(afk: boolean): Promise<Presence>;
|
||||
@@ -360,6 +360,7 @@ declare module 'discord.js' {
|
||||
constructor(client: Client, data?: object);
|
||||
public messages: MessageStore;
|
||||
public recipient: User;
|
||||
public readonly partial: boolean;
|
||||
}
|
||||
|
||||
export class Emoji extends Base {
|
||||
@@ -376,26 +377,6 @@ declare module 'discord.js' {
|
||||
public toString(): string;
|
||||
}
|
||||
|
||||
export class GroupDMChannel extends TextBasedChannel(Channel) {
|
||||
constructor(client: Client, data?: object);
|
||||
public applicationID: Snowflake;
|
||||
public icon: string;
|
||||
public managed: boolean;
|
||||
public messages: MessageStore;
|
||||
public name: string;
|
||||
public nicks: Collection<Snowflake, string>;
|
||||
public readonly owner: User;
|
||||
public ownerID: Snowflake;
|
||||
public recipients: Collection<Snowflake, User>;
|
||||
public addUser(options: { user: UserResolvable, accessToken?: string, nick?: string }): Promise<GroupDMChannel>;
|
||||
public edit (data: { icon?: string, name?: string }): Promise<GroupDMChannel>;
|
||||
public equals(channel: GroupDMChannel): boolean;
|
||||
public iconURL(options?: AvatarOptions): string;
|
||||
public removeUser(user: UserResolvable): Promise<GroupDMChannel>;
|
||||
public setIcon(icon: Base64Resolvable | BufferResolvable): Promise<GroupDMChannel>;
|
||||
public setName(name: string): Promise<GroupDMChannel>;
|
||||
}
|
||||
|
||||
export class Guild extends Base {
|
||||
constructor(client: Client, data: object);
|
||||
private _sortedRoles(): Collection<Snowflake, Role>;
|
||||
@@ -570,12 +551,14 @@ declare module 'discord.js' {
|
||||
public readonly kickable: boolean;
|
||||
public readonly manageable: boolean;
|
||||
public nickname: string;
|
||||
public readonly partial: boolean;
|
||||
public readonly permissions: Readonly<Permissions>;
|
||||
public readonly presence: Presence;
|
||||
public roles: GuildMemberRoleStore;
|
||||
public user: User;
|
||||
public readonly voice: VoiceState;
|
||||
public ban(options?: BanOptions): Promise<GuildMember>;
|
||||
public fetch(): Promise<GuildMember>;
|
||||
public createDM(): Promise<DMChannel>;
|
||||
public deleteDM(): Promise<DMChannel>;
|
||||
public edit(data: GuildMemberEditData, reason?: string): Promise<GuildMember>;
|
||||
@@ -619,7 +602,7 @@ declare module 'discord.js' {
|
||||
|
||||
export class Invite extends Base {
|
||||
constructor(client: Client, data: object);
|
||||
public channel: GuildChannel | GroupDMChannel;
|
||||
public channel: GuildChannel;
|
||||
public code: string;
|
||||
public readonly createdAt: Date;
|
||||
public createdTimestamp: number;
|
||||
@@ -640,7 +623,7 @@ declare module 'discord.js' {
|
||||
}
|
||||
|
||||
export class Message extends Base {
|
||||
constructor(client: Client, data: object, channel: TextChannel | DMChannel | GroupDMChannel);
|
||||
constructor(client: Client, data: object, channel: TextChannel | DMChannel);
|
||||
private _edits: Message[];
|
||||
private patch(data: object): void;
|
||||
|
||||
@@ -648,7 +631,7 @@ declare module 'discord.js' {
|
||||
public application: ClientApplication;
|
||||
public attachments: Collection<Snowflake, MessageAttachment>;
|
||||
public author: User;
|
||||
public channel: TextChannel | DMChannel | GroupDMChannel;
|
||||
public channel: TextChannel | DMChannel;
|
||||
public readonly cleanContent: string;
|
||||
public content: string;
|
||||
public readonly createdAt: Date;
|
||||
@@ -665,6 +648,7 @@ declare module 'discord.js' {
|
||||
public readonly member: GuildMember;
|
||||
public mentions: MessageMentions;
|
||||
public nonce: string;
|
||||
public readonly partial: boolean;
|
||||
public readonly pinnable: boolean;
|
||||
public pinned: boolean;
|
||||
public reactions: ReactionStore;
|
||||
@@ -680,6 +664,7 @@ declare module 'discord.js' {
|
||||
public edit(options: MessageEditOptions | MessageEmbed | APIMessage): Promise<Message>;
|
||||
public equals(message: Message, rawData: object): boolean;
|
||||
public fetchWebhook(): Promise<Webhook>;
|
||||
public fetch(): Promise<Message>;
|
||||
public pin(): Promise<Message>;
|
||||
public react(emoji: EmojiIdentifierResolvable): Promise<MessageReaction>;
|
||||
public reply(content?: StringResolvable, options?: MessageOptions | MessageAdditions): Promise<Message | Message[]>;
|
||||
@@ -706,7 +691,7 @@ declare module 'discord.js' {
|
||||
}
|
||||
|
||||
export class MessageCollector extends Collector<Snowflake, Message> {
|
||||
constructor(channel: TextChannel | DMChannel | GroupDMChannel, filter: CollectorFilter, options?: MessageCollectorOptions);
|
||||
constructor(channel: TextChannel | DMChannel, filter: CollectorFilter, options?: MessageCollectorOptions);
|
||||
public channel: Channel;
|
||||
public options: MessageCollectorOptions;
|
||||
public received: number;
|
||||
@@ -1078,6 +1063,7 @@ declare module 'discord.js' {
|
||||
public readonly dmChannel: DMChannel;
|
||||
public id: Snowflake;
|
||||
public locale: string;
|
||||
public readonly partial: boolean;
|
||||
public readonly presence: Presence;
|
||||
public readonly tag: string;
|
||||
public username: string;
|
||||
@@ -1086,6 +1072,7 @@ declare module 'discord.js' {
|
||||
public deleteDM(): Promise<DMChannel>;
|
||||
public displayAvatarURL(options?: AvatarOptions): string;
|
||||
public equals(user: User): boolean;
|
||||
public fetch(): Promise<User>;
|
||||
public toString(): string;
|
||||
public typingDurationIn(channel: ChannelResolvable): number;
|
||||
public typingIn(channel: ChannelResolvable): boolean;
|
||||
@@ -1385,7 +1372,7 @@ declare module 'discord.js' {
|
||||
}
|
||||
|
||||
export class MessageStore extends DataStore<Snowflake, Message, typeof Message, MessageResolvable> {
|
||||
constructor(channel: TextChannel | DMChannel | GroupDMChannel, iterable?: Iterable<any>);
|
||||
constructor(channel: TextChannel | DMChannel, iterable?: Iterable<any>);
|
||||
public fetch(message: Snowflake): Promise<Message>;
|
||||
public fetch(options?: ChannelLogsQueryOptions): Promise<Collection<Snowflake, Message>>;
|
||||
public fetchPinned(): Promise<Collection<Snowflake, Message>>;
|
||||
@@ -1607,6 +1594,7 @@ declare module 'discord.js' {
|
||||
messageSweepInterval?: number;
|
||||
fetchAllMembers?: boolean;
|
||||
disableEveryone?: boolean;
|
||||
partials?: PartialTypes[];
|
||||
restWsBridgeTimeout?: number;
|
||||
restTimeOffset?: number;
|
||||
restSweepInterval?: number;
|
||||
@@ -1676,7 +1664,6 @@ declare module 'discord.js' {
|
||||
type Extendable = {
|
||||
GuildEmoji: typeof GuildEmoji;
|
||||
DMChannel: typeof DMChannel;
|
||||
GroupDMChannel: typeof GroupDMChannel;
|
||||
TextChannel: typeof TextChannel;
|
||||
VoiceChannel: typeof VoiceChannel;
|
||||
CategoryChannel: typeof CategoryChannel;
|
||||
@@ -1711,13 +1698,6 @@ declare module 'discord.js' {
|
||||
type: number;
|
||||
};
|
||||
|
||||
type GroupDMRecipientOptions = {
|
||||
user?: UserResolvable | Snowflake;
|
||||
accessToken?: string;
|
||||
nick?: string;
|
||||
id?: Snowflake;
|
||||
};
|
||||
|
||||
type GuildAuditLogsAction = keyof GuildAuditLogsActions;
|
||||
|
||||
type GuildAuditLogsActions = {
|
||||
@@ -1934,7 +1914,7 @@ declare module 'discord.js' {
|
||||
|
||||
type MessageResolvable = Message | Snowflake;
|
||||
|
||||
type MessageTarget = TextChannel | DMChannel | GroupDMChannel | User | GuildMember | Webhook | WebhookClient;
|
||||
type MessageTarget = TextChannel | DMChannel | User | GuildMember | Webhook | WebhookClient;
|
||||
|
||||
type MessageType = 'DEFAULT'
|
||||
| 'RECIPIENT_ADD'
|
||||
@@ -2023,6 +2003,11 @@ declare module 'discord.js' {
|
||||
desktop?: ClientPresenceStatus
|
||||
};
|
||||
|
||||
type PartialTypes = 'USER'
|
||||
| 'CHANNEL'
|
||||
| 'GUILD_MEMBER'
|
||||
| 'MESSAGE';
|
||||
|
||||
type PresenceStatus = ClientPresenceStatus | 'offline';
|
||||
|
||||
type PresenceStatusData = ClientPresenceStatus | 'invisible';
|
||||
|
||||
Reference in New Issue
Block a user