mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-15 02:53:31 +01:00
Merge branch 'master' into indev-prism
This commit is contained in:
@@ -1,21 +1,34 @@
|
|||||||
# Version 11
|
# Version 11
|
||||||
|
Version 11 contains loads of new and improved features, optimisations, and bug fixes.
|
||||||
|
See [the changelog](https://github.com/hydrabolt/discord.js/releases/tag/11.0.0) for a full list of changes.
|
||||||
|
|
||||||
**Significant Additions (see the changelog for a full list):**
|
## Significant additions
|
||||||
* Message Reactions and Embeds (rich text)
|
* Message Reactions and Embeds (rich text)
|
||||||
* Support for uws and erlpack for better performance
|
* Support for uws and erlpack for better performance
|
||||||
* OAuthApplication support
|
* OAuthApplication support
|
||||||
|
* Web distributions
|
||||||
|
|
||||||
### 1) Client.login() no longer supports logging in with email + password
|
## Breaking changes
|
||||||
Logging in with an email or password has been discouraged previously, mainly because of [this](https://github.com/hammerandchisel/discord-api-docs/issues/69#issuecomment-223886862), however we have made the decision to now remove all email and password logins in v11. Instead, you can use authentication tokens. You can find your token for a self-bot by entering `CTRL+SHIFT+I` in the Discord application, entering the console tab and executing `localStorage.token`. As always, you can get your token for real bot accounts [here.](https://discordapp.com/developers/applications/me)
|
### Client.login() no longer supports logging in with email + password
|
||||||
|
Logging in with an email and password has always been heavily discouraged since the advent of proper token support, but in v11 we have made the decision to completely remove the functionality, since Hammer & Chisel have [officially stated](https://github.com/hammerandchisel/discord-api-docs/issues/69#issuecomment-223886862) it simply shouldn't be done.
|
||||||
|
|
||||||
### 2) ClientUser.setEmail()/setPassword() now require the current password, as well as setUsername() on user accounts
|
User accounts can still log in with tokens just like bot accounts. To obtain the token for a user account, you can log in to Discord with that account, and use Ctrl + Shift + I to open the developer tools. In the console tab, evaluating `localStorage.token` will give you the token for that account.
|
||||||
In order to change email, password or username on user accounts (self-bots), you need to now pass a password parameter to these methods (changes highlighted in documentation for ClientUser).
|
|
||||||
|
|
||||||
### 3) Removed TextBasedChannel.sendTTSMessage()
|
### ClientUser.setEmail()/setPassword() now require the current password, as well as setUsername() on user accounts
|
||||||
This method was redundant and has been removed as the same results can be achieved using sendMessage()
|
Since you can no longer log in with email and password, you must provide the current account password to the `setEmail()`, `setPassword()`, and `setUsername()` methods for user accounts (self-bots).
|
||||||
|
|
||||||
### 4) Using Collection.find()/exists() with IDs will throw an error
|
### Removed TextBasedChannel.sendTTSMessage()
|
||||||
To find something or check its existence using an ID, you should now use `.get()` and `.has()` which are part of a normal [Map.](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Map)
|
This method was deemed to be an entirely pointless shortcut that virtually nobody even used.
|
||||||
|
The same results can be achieved by passing options to `send()` or `sendMessage()`.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```js
|
||||||
|
channel.send('Hi there', { tts: true });
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using Collection.find()/exists() with IDs will throw an error
|
||||||
|
This is simply to help prevent a common mistake that is made frequently.
|
||||||
|
To find something or check its existence using an ID, you should use `.get()` and `.has()` which are part of the [ES6 Map class](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Map), which Collection is an extension of.
|
||||||
|
|
||||||
# Version 10
|
# Version 10
|
||||||
Version 10's non-BC changes focus on cleaning up some inconsistencies that exist in previous versions.
|
Version 10's non-BC changes focus on cleaning up some inconsistencies that exist in previous versions.
|
||||||
|
|||||||
@@ -268,7 +268,7 @@ class ClientUser extends User {
|
|||||||
*/
|
*/
|
||||||
createGuild(name, region, icon = null) {
|
createGuild(name, region, icon = null) {
|
||||||
if (!icon) return this.client.rest.methods.createGuild({ name, icon, region });
|
if (!icon) return this.client.rest.methods.createGuild({ name, icon, region });
|
||||||
if (icon.startsWith('data:')) {
|
if (typeof icon === 'string' && icon.startsWith('data:')) {
|
||||||
return this.client.rest.methods.createGuild({ name, icon, region });
|
return this.client.rest.methods.createGuild({ name, icon, region });
|
||||||
} else {
|
} else {
|
||||||
return this.client.resolver.resolveBuffer(icon).then(data =>
|
return this.client.resolver.resolveBuffer(icon).then(data =>
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ class DMChannel extends Channel {
|
|||||||
fetchMessage() { return; }
|
fetchMessage() { return; }
|
||||||
fetchMessages() { return; }
|
fetchMessages() { return; }
|
||||||
fetchPinnedMessages() { return; }
|
fetchPinnedMessages() { return; }
|
||||||
|
search() { return; }
|
||||||
startTyping() { return; }
|
startTyping() { return; }
|
||||||
stopTyping() { return; }
|
stopTyping() { return; }
|
||||||
get typing() { return; }
|
get typing() { return; }
|
||||||
@@ -53,7 +54,6 @@ class DMChannel extends Channel {
|
|||||||
awaitMessages() { return; }
|
awaitMessages() { return; }
|
||||||
bulkDelete() { return; }
|
bulkDelete() { return; }
|
||||||
_cacheMessage() { return; }
|
_cacheMessage() { return; }
|
||||||
search() { return; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TextBasedChannel.applyToClass(DMChannel, true);
|
TextBasedChannel.applyToClass(DMChannel, true);
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ class GroupDMChannel extends Channel {
|
|||||||
fetchMessage() { return; }
|
fetchMessage() { return; }
|
||||||
fetchMessages() { return; }
|
fetchMessages() { return; }
|
||||||
fetchPinnedMessages() { return; }
|
fetchPinnedMessages() { return; }
|
||||||
|
search() { return; }
|
||||||
startTyping() { return; }
|
startTyping() { return; }
|
||||||
stopTyping() { return; }
|
stopTyping() { return; }
|
||||||
get typing() { return; }
|
get typing() { return; }
|
||||||
@@ -137,7 +138,6 @@ class GroupDMChannel extends Channel {
|
|||||||
awaitMessages() { return; }
|
awaitMessages() { return; }
|
||||||
bulkDelete() { return; }
|
bulkDelete() { return; }
|
||||||
_cacheMessage() { return; }
|
_cacheMessage() { return; }
|
||||||
search() { return; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TextBasedChannel.applyToClass(GroupDMChannel, true);
|
TextBasedChannel.applyToClass(GroupDMChannel, true);
|
||||||
|
|||||||
@@ -362,6 +362,25 @@ class Guild {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a search within the entire guild.
|
||||||
|
* @param {MessageSearchOptions} [options={}] Options to pass to the search
|
||||||
|
* @returns {Promise<Array<Message[]>>}
|
||||||
|
* An array containing arrays of messages. Each inner array is a search context cluster.
|
||||||
|
* The message which has triggered the result will have the `hit` property set to `true`.
|
||||||
|
* @example
|
||||||
|
* guild.search({
|
||||||
|
* content: 'discord.js',
|
||||||
|
* before: '2016-11-17'
|
||||||
|
* }).then(res => {
|
||||||
|
* const hit = res[0].find(m => m.hit).content;
|
||||||
|
* console.log(`I found: **${hit}**`);
|
||||||
|
* }).catch(console.error);
|
||||||
|
*/
|
||||||
|
search(options) {
|
||||||
|
return this.client.rest.methods.search(this, options);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data for editing a guild
|
* The data for editing a guild
|
||||||
* @typedef {Object} GuildEditData
|
* @typedef {Object} GuildEditData
|
||||||
@@ -600,9 +619,48 @@ class Guild {
|
|||||||
return create.then(role => role.edit(data));
|
return create.then(role => role.edit(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the position of a role in this guild
|
||||||
|
* @param {string|Role} role the role to edit, can be a role object or a role ID.
|
||||||
|
* @param {number} position the new position of the role
|
||||||
|
* @returns {Promise<Guild>}
|
||||||
|
*/
|
||||||
|
setRolePosition(role, position) {
|
||||||
|
if (typeof role === 'string') {
|
||||||
|
role = this.roles.get(role);
|
||||||
|
if (!role) return Promise.reject(new Error('Supplied role is not a role or string.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
position = Number(position);
|
||||||
|
if (isNaN(position)) return Promise.reject(new Error('Supplied position is not a number.'));
|
||||||
|
|
||||||
|
const lowestAffected = Math.min(role.position, position);
|
||||||
|
const highestAffected = Math.max(role.position, position);
|
||||||
|
|
||||||
|
const rolesToUpdate = this.roles.filter(r => r.position >= lowestAffected && r.position <= highestAffected);
|
||||||
|
|
||||||
|
// stop role positions getting stupidly inflated
|
||||||
|
if (position > role.position) {
|
||||||
|
position = rolesToUpdate.first().position;
|
||||||
|
} else {
|
||||||
|
position = rolesToUpdate.last().position;
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedRoles = [];
|
||||||
|
|
||||||
|
for (const uRole of rolesToUpdate.values()) {
|
||||||
|
updatedRoles.push({
|
||||||
|
id: uRole.id,
|
||||||
|
position: uRole.id === role.id ? position : uRole.position + (position < role.position ? 1 : -1),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.client.rest.methods.setRolePositions(this.id, updatedRoles);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new custom emoji in the guild.
|
* Creates a new custom emoji in the guild.
|
||||||
* @param {BufferResolvable} attachment The image for the emoji.
|
* @param {BufferResolvable|Base64Resolvable} attachment The image for the emoji.
|
||||||
* @param {string} name The name for the emoji.
|
* @param {string} name The name for the emoji.
|
||||||
* @returns {Promise<Emoji>} The created emoji.
|
* @returns {Promise<Emoji>} The created emoji.
|
||||||
* @example
|
* @example
|
||||||
@@ -618,7 +676,7 @@ class Guild {
|
|||||||
*/
|
*/
|
||||||
createEmoji(attachment, name) {
|
createEmoji(attachment, name) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
if (attachment.startsWith('data:')) {
|
if (typeof attachment === 'string' && attachment.startsWith('data:')) {
|
||||||
resolve(this.client.rest.methods.createEmoji(this, attachment, name));
|
resolve(this.client.rest.methods.createEmoji(this, attachment, name));
|
||||||
} else {
|
} else {
|
||||||
this.client.resolver.resolveBuffer(attachment).then(data =>
|
this.client.resolver.resolveBuffer(attachment).then(data =>
|
||||||
@@ -664,66 +722,6 @@ class Guild {
|
|||||||
return this.client.rest.methods.deleteGuild(this);
|
return this.client.rest.methods.deleteGuild(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the position of a role in this guild
|
|
||||||
* @param {string|Role} role the role to edit, can be a role object or a role ID.
|
|
||||||
* @param {number} position the new position of the role
|
|
||||||
* @returns {Promise<Guild>}
|
|
||||||
*/
|
|
||||||
setRolePosition(role, position) {
|
|
||||||
if (typeof role === 'string') {
|
|
||||||
role = this.roles.get(role);
|
|
||||||
if (!role) return Promise.reject(new Error('Supplied role is not a role or string.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
position = Number(position);
|
|
||||||
if (isNaN(position)) return Promise.reject(new Error('Supplied position is not a number.'));
|
|
||||||
|
|
||||||
const lowestAffected = Math.min(role.position, position);
|
|
||||||
const highestAffected = Math.max(role.position, position);
|
|
||||||
|
|
||||||
const rolesToUpdate = this.roles.filter(r => r.position >= lowestAffected && r.position <= highestAffected);
|
|
||||||
|
|
||||||
// stop role positions getting stupidly inflated
|
|
||||||
if (position > role.position) {
|
|
||||||
position = rolesToUpdate.first().position;
|
|
||||||
} else {
|
|
||||||
position = rolesToUpdate.last().position;
|
|
||||||
}
|
|
||||||
|
|
||||||
const updatedRoles = [];
|
|
||||||
|
|
||||||
for (const uRole of rolesToUpdate.values()) {
|
|
||||||
updatedRoles.push({
|
|
||||||
id: uRole.id,
|
|
||||||
position: uRole.id === role.id ? position : uRole.position + (position < role.position ? 1 : -1),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.client.rest.methods.setRolePositions(this.id, updatedRoles);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs a search
|
|
||||||
* @param {MessageSearchOptions} [options={}] Options to pass to the search
|
|
||||||
* @returns {Promise<Array<Message[]>>}
|
|
||||||
* An array containing arrays of messages. Each inner array is a search context cluster.
|
|
||||||
* The message which has triggered the result will have the `hit` property set to `true`.
|
|
||||||
* @example
|
|
||||||
* guild.search({
|
|
||||||
* content: 'discord.js',
|
|
||||||
* before: '2016-11-17'
|
|
||||||
* })
|
|
||||||
* .then(res => {
|
|
||||||
* const hit = res[0].find(m => m.hit).content;
|
|
||||||
* console.log(`I found: **${hit}**`);
|
|
||||||
* })
|
|
||||||
* .catch(console.error);
|
|
||||||
*/
|
|
||||||
search(options) {
|
|
||||||
return this.client.rest.methods.search(this, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this Guild equals another Guild. It compares all properties, so for most operations
|
* 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
|
* it is advisable to just compare `guild.id === guild2.id` as it is much faster and is often
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class TextChannel extends GuildChannel {
|
|||||||
/**
|
/**
|
||||||
* Create a webhook for the channel.
|
* Create a webhook for the channel.
|
||||||
* @param {string} name The name of the webhook.
|
* @param {string} name The name of the webhook.
|
||||||
* @param {BufferResolvable} avatar The avatar for the webhook.
|
* @param {BufferResolvable|Base64Resolvable} avatar The avatar for the webhook.
|
||||||
* @returns {Promise<Webhook>} webhook The created webhook.
|
* @returns {Promise<Webhook>} webhook The created webhook.
|
||||||
* @example
|
* @example
|
||||||
* channel.createWebhook('Snek', 'http://snek.s3.amazonaws.com/topSnek.png')
|
* channel.createWebhook('Snek', 'http://snek.s3.amazonaws.com/topSnek.png')
|
||||||
@@ -62,7 +62,7 @@ class TextChannel extends GuildChannel {
|
|||||||
*/
|
*/
|
||||||
createWebhook(name, avatar) {
|
createWebhook(name, avatar) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
if (avatar.startsWith('data:')) {
|
if (typeof avatar === 'string' && avatar.startsWith('data:')) {
|
||||||
resolve(this.client.rest.methods.createWebhook(this, name, avatar));
|
resolve(this.client.rest.methods.createWebhook(this, name, avatar));
|
||||||
} else {
|
} else {
|
||||||
this.client.resolver.resolveBuffer(avatar).then(data =>
|
this.client.resolver.resolveBuffer(avatar).then(data =>
|
||||||
@@ -81,6 +81,7 @@ class TextChannel extends GuildChannel {
|
|||||||
fetchMessage() { return; }
|
fetchMessage() { return; }
|
||||||
fetchMessages() { return; }
|
fetchMessages() { return; }
|
||||||
fetchPinnedMessages() { return; }
|
fetchPinnedMessages() { return; }
|
||||||
|
search() { return; }
|
||||||
startTyping() { return; }
|
startTyping() { return; }
|
||||||
stopTyping() { return; }
|
stopTyping() { return; }
|
||||||
get typing() { return; }
|
get typing() { return; }
|
||||||
@@ -89,7 +90,6 @@ class TextChannel extends GuildChannel {
|
|||||||
awaitMessages() { return; }
|
awaitMessages() { return; }
|
||||||
bulkDelete() { return; }
|
bulkDelete() { return; }
|
||||||
_cacheMessage() { return; }
|
_cacheMessage() { return; }
|
||||||
search() { return; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TextBasedChannel.applyToClass(TextChannel, true);
|
TextBasedChannel.applyToClass(TextChannel, true);
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ class TextBasedChannel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs a search
|
* Performs a search within the channel.
|
||||||
* @param {MessageSearchOptions} [options={}] Options to pass to the search
|
* @param {MessageSearchOptions} [options={}] Options to pass to the search
|
||||||
* @returns {Promise<Array<Message[]>>}
|
* @returns {Promise<Array<Message[]>>}
|
||||||
* An array containing arrays of messages. Each inner array is a search context cluster.
|
* An array containing arrays of messages. Each inner array is a search context cluster.
|
||||||
@@ -223,12 +223,10 @@ class TextBasedChannel {
|
|||||||
* channel.search({
|
* channel.search({
|
||||||
* content: 'discord.js',
|
* content: 'discord.js',
|
||||||
* before: '2016-11-17'
|
* before: '2016-11-17'
|
||||||
* })
|
* }).then(res => {
|
||||||
* .then(res => {
|
|
||||||
* const hit = res[0].find(m => m.hit).content;
|
* const hit = res[0].find(m => m.hit).content;
|
||||||
* console.log(`I found: **${hit}**`);
|
* console.log(`I found: **${hit}**`);
|
||||||
* })
|
* }).catch(console.error);
|
||||||
* .catch(console.error);
|
|
||||||
*/
|
*/
|
||||||
search(options) {
|
search(options) {
|
||||||
return this.client.rest.methods.search(this, options);
|
return this.client.rest.methods.search(this, options);
|
||||||
|
|||||||
Reference in New Issue
Block a user