discord.js
Advanced tools
Comparing version 12.0.2 to 12.1.0
{ | ||
"name": "discord.js", | ||
"version": "12.0.2", | ||
"version": "12.1.0", | ||
"description": "A powerful library for interacting with the Discord API", | ||
@@ -16,3 +16,3 @@ "main": "./src/index", | ||
"build:browser": "webpack", | ||
"prepublishOnly": "npm run test && npm run build:browser" | ||
"prepublishOnly": "npm run test && cross-env NODE_ENV=production npm run build:browser" | ||
}, | ||
@@ -82,2 +82,3 @@ "repository": { | ||
"@types/ws": "^7.2.1", | ||
"cross-env": "^7.0.2", | ||
"discord.js-docgen": "discordjs/docgen", | ||
@@ -84,0 +85,0 @@ "dtslint": "^3.0.0", |
@@ -21,3 +21,3 @@ 'use strict'; | ||
if (guild.available && data.unavailable) { | ||
if (data.unavailable) { | ||
// Guild is unavailable | ||
@@ -24,0 +24,0 @@ guild.available = false; |
@@ -14,2 +14,3 @@ 'use strict'; | ||
const ClientApplication = require('../structures/ClientApplication'); | ||
const GuildPreview = require('../structures/GuildPreview'); | ||
const Invite = require('../structures/Invite'); | ||
@@ -343,2 +344,16 @@ const VoiceRegion = require('../structures/VoiceRegion'); | ||
/** | ||
* Obtains a guild preview from Discord, only available for public guilds. | ||
* @param {GuildResolvable} guild The guild to fetch the preview for | ||
* @returns {Promise<GuildPreview>} | ||
*/ | ||
fetchGuildPreview(guild) { | ||
const id = this.guilds.resolveID(guild); | ||
if (!id) throw new TypeError('INVALID_TYPE', 'guild', 'GuildResolvable'); | ||
return this.api | ||
.guilds(id) | ||
.preview.get() | ||
.then(data => new GuildPreview(this, data)); | ||
} | ||
/** | ||
* Generates a link that can be used to invite the bot to a guild. | ||
@@ -345,0 +360,0 @@ * @param {PermissionResolvable} [permissions] Permissions to request |
@@ -54,3 +54,3 @@ 'use strict'; | ||
* // Play a voice broadcast | ||
* const broadcast = client.createVoiceBroadcast(); | ||
* const broadcast = client.voice.createBroadcast(); | ||
* broadcast.play('/home/hydrabolt/audio.mp3'); | ||
@@ -57,0 +57,0 @@ * connection.play(broadcast); |
@@ -8,12 +8,43 @@ 'use strict'; | ||
const user = client.users.cache.get(data.user_id); | ||
const timestamp = new Date(data.timestamp * 1000); | ||
if (channel && user) { | ||
/** | ||
* Emitted whenever a user starts typing in a channel. | ||
* @event Client#typingStart | ||
* @param {Channel} channel The channel the user started typing in | ||
* @param {User} user The user that started typing | ||
*/ | ||
client.emit(Events.TYPING_START, channel, user); | ||
if (channel.type === 'voice') { | ||
client.emit(Events.WARN, `Discord sent a typing packet to a voice channel ${channel.id}`); | ||
return; | ||
} | ||
if (channel._typing.has(user.id)) { | ||
const typing = channel._typing.get(user.id); | ||
typing.lastTimestamp = timestamp; | ||
typing.elapsedTime = Date.now() - typing.since; | ||
client.clearTimeout(typing.timeout); | ||
typing.timeout = tooLate(channel, user); | ||
} else { | ||
const since = new Date(); | ||
const lastTimestamp = new Date(); | ||
channel._typing.set(user.id, { | ||
user, | ||
since, | ||
lastTimestamp, | ||
elapsedTime: Date.now() - since, | ||
timeout: tooLate(channel, user), | ||
}); | ||
/** | ||
* Emitted whenever a user starts typing in a channel. | ||
* @event Client#typingStart | ||
* @param {Channel} channel The channel the user started typing in | ||
* @param {User} user The user that started typing | ||
*/ | ||
client.emit(Events.TYPING_START, channel, user); | ||
} | ||
} | ||
}; | ||
function tooLate(channel, user) { | ||
return channel.client.setTimeout(() => { | ||
channel._typing.delete(user.id); | ||
}, 10000); | ||
} |
@@ -432,3 +432,3 @@ 'use strict'; | ||
case OPCodes.HEARTBEAT: | ||
this.sendHeartbeat('HeartbeatRequest'); | ||
this.sendHeartbeat('HeartbeatRequest', true); | ||
break; | ||
@@ -435,0 +435,0 @@ default: |
@@ -60,2 +60,3 @@ 'use strict'; | ||
APIMessage: require('./structures/APIMessage'), | ||
BaseGuildEmoji: require('./structures/BaseGuildEmoji'), | ||
CategoryChannel: require('./structures/CategoryChannel'), | ||
@@ -76,2 +77,3 @@ Channel: require('./structures/Channel'), | ||
GuildMember: require('./structures/GuildMember'), | ||
GuildPreview: require('./structures/GuildPreview'), | ||
Integration: require('./structures/Integration'), | ||
@@ -78,0 +80,0 @@ Invite: require('./structures/Invite'), |
@@ -53,25 +53,24 @@ 'use strict'; | ||
*/ | ||
create(attachment, name, { roles, reason } = {}) { | ||
if (typeof attachment === 'string' && attachment.startsWith('data:')) { | ||
const data = { image: attachment, name }; | ||
if (roles) { | ||
data.roles = []; | ||
for (let role of roles instanceof Collection ? roles.values() : roles) { | ||
role = this.guild.roles.resolve(role); | ||
if (!role) { | ||
return Promise.reject( | ||
new TypeError('INVALID_TYPE', 'options.roles', 'Array or Collection of Roles or Snowflakes', true), | ||
); | ||
} | ||
data.roles.push(role.id); | ||
async create(attachment, name, { roles, reason } = {}) { | ||
attachment = await DataResolver.resolveImage(attachment); | ||
if (!attachment) throw new TypeError('REQ_RESOURCE_TYPE'); | ||
const data = { image: attachment, name }; | ||
if (roles) { | ||
data.roles = []; | ||
for (let role of roles instanceof Collection ? roles.values() : roles) { | ||
role = this.guild.roles.resolve(role); | ||
if (!role) { | ||
return Promise.reject( | ||
new TypeError('INVALID_TYPE', 'options.roles', 'Array or Collection of Roles or Snowflakes', true), | ||
); | ||
} | ||
data.roles.push(role.id); | ||
} | ||
return this.client.api | ||
.guilds(this.guild.id) | ||
.emojis.post({ data, reason }) | ||
.then(emoji => this.client.actions.GuildEmojiCreate.handle(this.guild, emoji).emoji); | ||
} | ||
return DataResolver.resolveImage(attachment).then(image => this.create(image, name, { roles, reason })); | ||
return this.client.api | ||
.guilds(this.guild.id) | ||
.emojis.post({ data, reason }) | ||
.then(emoji => this.client.actions.GuildEmojiCreate.handle(this.guild, emoji).emoji); | ||
} | ||
@@ -78,0 +77,0 @@ |
@@ -93,3 +93,8 @@ 'use strict'; | ||
if (roleOrRoles === null) { | ||
throw new TypeError('INVALID_TYPE', 'roles', 'Array or Collection of Roles or Snowflakes', true); | ||
throw new TypeError( | ||
'INVALID_TYPE', | ||
'roles', | ||
'Role, Snowflake or Array or Collection of Roles or Snowflakes', | ||
true, | ||
); | ||
} | ||
@@ -96,0 +101,0 @@ |
@@ -67,30 +67,4 @@ 'use strict'; | ||
} | ||
_partial(emoji) { | ||
const id = emoji.id || emoji.name; | ||
const existing = this.cache.get(id); | ||
return !existing || existing.partial; | ||
} | ||
async _fetchReaction(reactionEmoji, cache) { | ||
const id = reactionEmoji.id || reactionEmoji.name; | ||
const existing = this.cache.get(id); | ||
if (!this._partial(reactionEmoji)) return existing; | ||
const data = await this.client.api | ||
.channels(this.message.channel.id) | ||
.messages(this.message.id) | ||
.get(); | ||
if (this.message.partial) this.message._patch(data); | ||
if (!data.reactions || !data.reactions.some(r => (r.emoji.id || r.emoji.name) === id)) { | ||
reactionEmoji.reaction._patch({ count: 0 }); | ||
this.message.reactions.cache.delete(id); | ||
return existing; | ||
} | ||
for (const reaction of data.reactions) { | ||
if (this._partial(reaction.emoji)) this.add(reaction, cache); | ||
} | ||
return existing; | ||
} | ||
} | ||
module.exports = ReactionManager; |
@@ -51,3 +51,3 @@ 'use strict'; | ||
get limited() { | ||
return (this.manager.globalTimeout || this.remaining <= 0) && Date.now() < this.reset; | ||
return Boolean(this.manager.globalTimeout) || (this.remaining <= 0 && Date.now() < this.reset); | ||
} | ||
@@ -54,0 +54,0 @@ |
@@ -187,2 +187,3 @@ 'use strict'; | ||
avatar_url: avatarURL, | ||
allowed_mentions: this.options.allowedMentions, | ||
flags, | ||
@@ -189,0 +190,0 @@ }; |
@@ -103,13 +103,8 @@ 'use strict'; | ||
if (!data.guild_id && !guild) { | ||
switch (data.type) { | ||
case ChannelTypes.DM: { | ||
const DMChannel = Structures.get('DMChannel'); | ||
channel = new DMChannel(client, data); | ||
break; | ||
} | ||
case ChannelTypes.GROUP: { | ||
const PartialGroupDMChannel = require('./PartialGroupDMChannel'); | ||
channel = new PartialGroupDMChannel(client, data); | ||
break; | ||
} | ||
if ((data.recipients && data.type !== ChannelTypes.GROUP) || data.type === ChannelTypes.DM) { | ||
const DMChannel = Structures.get('DMChannel'); | ||
channel = new DMChannel(client, data); | ||
} else if (data.type === ChannelTypes.GROUP) { | ||
const PartialGroupDMChannel = require('./PartialGroupDMChannel'); | ||
channel = new PartialGroupDMChannel(client, data); | ||
} | ||
@@ -116,0 +111,0 @@ } else { |
@@ -5,2 +5,3 @@ 'use strict'; | ||
const GuildAuditLogs = require('./GuildAuditLogs'); | ||
const GuildPreview = require('./GuildPreview'); | ||
const Integration = require('./Integration'); | ||
@@ -304,3 +305,3 @@ const Invite = require('./Invite'); | ||
*/ | ||
if (typeof data.max_presences !== 'undefined') this.maximumPresences = data.max_presences || 5000; | ||
if (typeof data.max_presences !== 'undefined') this.maximumPresences = data.max_presences || 25000; | ||
@@ -715,2 +716,13 @@ /** | ||
/** | ||
* Obtains a guild preview for this guild from Discord, only available for public guilds. | ||
* @returns {Promise<GuildPreview>} | ||
*/ | ||
fetchPreview() { | ||
return this.client.api | ||
.guilds(this.id) | ||
.preview.get() | ||
.then(data => new GuildPreview(this.client, data)); | ||
} | ||
/** | ||
* Fetches the vanity url invite code to this guild. | ||
@@ -717,0 +729,0 @@ * Resolves with a string matching the vanity url invite code, not the full url. |
'use strict'; | ||
const Emoji = require('./Emoji'); | ||
const BaseGuildEmoji = require('./BaseGuildEmoji'); | ||
const { Error } = require('../errors'); | ||
@@ -10,6 +10,9 @@ const GuildEmojiRoleManager = require('../managers/GuildEmojiRoleManager'); | ||
* Represents a custom emoji. | ||
* @extends {Emoji} | ||
* @extends {BaseGuildEmoji} | ||
*/ | ||
class GuildEmoji extends Emoji { | ||
class GuildEmoji extends BaseGuildEmoji { | ||
/** | ||
* @name GuildEmoji | ||
* @kind constructor | ||
* @memberof GuildEmoji | ||
* @param {Client} client The instantiating client | ||
@@ -19,48 +22,9 @@ * @param {Object} data The data for the guild emoji | ||
*/ | ||
constructor(client, data, guild) { | ||
super(client, data); | ||
/** | ||
* The guild this emoji is part of | ||
* @type {Guild} | ||
*/ | ||
this.guild = guild; | ||
/** | ||
* The guild this emoji is part of | ||
* @type {Guild} | ||
* @name GuildEmoji#guild | ||
*/ | ||
/** | ||
* The ID of this emoji | ||
* @type {Snowflake} | ||
* @name GuildEmoji#id | ||
*/ | ||
this._roles = []; | ||
this._patch(data); | ||
} | ||
_patch(data) { | ||
if (data.name) this.name = data.name; | ||
/** | ||
* Whether or not this emoji requires colons surrounding it | ||
* @type {boolean} | ||
* @name GuildEmoji#requiresColons | ||
*/ | ||
if (typeof data.require_colons !== 'undefined') this.requiresColons = data.require_colons; | ||
/** | ||
* Whether this emoji is managed by an external service | ||
* @type {boolean} | ||
* @name GuildEmoji#managed | ||
*/ | ||
if (typeof data.managed !== 'undefined') this.managed = data.managed; | ||
/** | ||
* Whether this emoji is available | ||
* @type {boolean} | ||
* @name GuildEmoji#available | ||
*/ | ||
if (typeof data.available !== 'undefined') this.available = data.available; | ||
if (data.roles) this._roles = data.roles; | ||
} | ||
_clone() { | ||
@@ -67,0 +31,0 @@ const clone = super._clone(); |
@@ -61,4 +61,5 @@ 'use strict'; | ||
* (see [here](https://discordapp.com/developers/docs/resources/channel#embed-object) for more details) | ||
* @property {'none' | 'all' | 'everyone'} [disableMentions=this.client.options.disableMentions] Whether or not | ||
* all mentions or everyone/here mentions should be sanitized to prevent unexpected mentions | ||
* @property {MessageMentionOptions} [allowedMentions] Which mentions should be parsed from the message content | ||
* @property {DisableMentionType} [disableMentions=this.client.options.disableMentions] Whether or not all mentions or | ||
* everyone/here mentions should be sanitized to prevent unexpected mentions | ||
* @property {FileOptions[]|BufferResolvable[]} [files] Files to send with the message | ||
@@ -72,2 +73,26 @@ * @property {string|boolean} [code] Language for optional codeblock formatting to apply | ||
/** | ||
* Options provided to control parsing of mentions by Discord | ||
* @typedef {Object} MessageMentionOptions | ||
* @property {MessageMentionTypes[]} [parse] Types of mentions to be parsed | ||
* @property {Snowflake[]} [users] Snowflakes of Users to be parsed as mentions | ||
* @property {Snowflake[]} [roles] Snowflakes of Roles to be parsed as mentions | ||
*/ | ||
/** | ||
* Types of mentions to enable in MessageMentionOptions. | ||
* - `roles` | ||
* - `users` | ||
* - `everyone` | ||
* @typedef {string} MessageMentionTypes | ||
*/ | ||
/** | ||
* The type of mentions to disable. | ||
* - `none` | ||
* - `all` | ||
* - `everyone` | ||
* @typedef {string} DisableMentionType | ||
*/ | ||
/** | ||
* @typedef {Object} FileOptions | ||
@@ -74,0 +99,0 @@ * @property {BufferResolvable} attachment File to attach |
@@ -202,3 +202,3 @@ 'use strict'; | ||
/** | ||
* The date this embed was created at | ||
* The date displayed on this embed | ||
* @type {?Date} | ||
@@ -205,0 +205,0 @@ * @readonly |
@@ -52,2 +52,3 @@ 'use strict'; | ||
* @type {?number} | ||
* @name MessageReaction#count | ||
*/ | ||
@@ -105,4 +106,8 @@ // eslint-disable-next-line eqeqeq | ||
*/ | ||
fetch() { | ||
return this.message.reactions._fetchReaction(this.emoji, true); | ||
async fetch() { | ||
const message = await this.message.fetch(); | ||
const existing = message.reactions.cache.get(this.emoji.id || this.emoji.name); | ||
// The reaction won't get set when it has been completely removed | ||
this._patch(existing || { count: 0 }); | ||
return this; | ||
} | ||
@@ -109,0 +114,0 @@ |
@@ -41,3 +41,3 @@ 'use strict'; | ||
* The username of the user | ||
* @type {string} | ||
* @type {?string} | ||
* @name User#username | ||
@@ -49,3 +49,3 @@ */ | ||
* A discriminator based on username for the user | ||
* @type {string} | ||
* @type {?string} | ||
* @name User#discriminator | ||
@@ -171,7 +171,7 @@ */ | ||
* The Discord "tag" (e.g. `hydrabolt#0001`) for this user | ||
* @type {string} | ||
* @type {?string} | ||
* @readonly | ||
*/ | ||
get tag() { | ||
return `${this.username}#${this.discriminator}`; | ||
return typeof this.username === 'string' ? `${this.username}#${this.discriminator}` : null; | ||
} | ||
@@ -178,0 +178,0 @@ |
@@ -155,6 +155,6 @@ 'use strict'; | ||
/** | ||
* Moves the member to a different channel, or kick them from the one they're in. | ||
* @param {ChannelResolvable|null} [channel] Channel to move the member to, or `null` if you want to kick them from | ||
* voice | ||
* @param {string} [reason] Reason for moving member to another channel or kicking | ||
* Moves the member to a different channel, or disconnects them from the one they're in. | ||
* @param {ChannelResolvable|null} [channel] Channel to move the member to, or `null` if you want to disconnect them | ||
* from voice. Requires the `MOVE_MEMBERS` permission. | ||
* @param {string} [reason] Reason for moving member to another channel or disconnecting | ||
* @returns {Promise<GuildMember>} | ||
@@ -161,0 +161,0 @@ */ |
@@ -87,5 +87,6 @@ 'use strict'; | ||
* @property {Object[]} [embeds] An array of embeds for the message | ||
* @property {MessageMentionOptions} [allowedMentions] Which mentions should be parsed from the message content | ||
* (see [here](https://discordapp.com/developers/docs/resources/channel#embed-object) for more details) | ||
* @property {'none' | 'all' | 'everyone'} [disableMentions=this.client.options.disableMentions] Whether or not | ||
* all mentions or everyone/here mentions should be sanitized to prevent unexpected mentions | ||
* @property {DisableMentionType} [disableMentions=this.client.options.disableMentions] Whether or not all mentions or | ||
* everyone/here mentions should be sanitized to prevent unexpected mentions | ||
* @property {FileOptions[]|string[]} [files] Files to send with the message | ||
@@ -92,0 +93,0 @@ * @property {string|boolean} [code] Language for optional codeblock formatting to apply |
@@ -24,4 +24,3 @@ 'use strict'; | ||
* upon joining a guild (should be avoided whenever possible) | ||
* @property {'none' | 'all' | 'everyone'} [disableMentions='none'] Default value | ||
* for {@link MessageOptions#disableMentions} | ||
* @property {DisableMentionType} [disableMentions='none'] Default value for {@link MessageOptions#disableMentions} | ||
* @property {PartialType[]} [partials] Structures allowed to be partial. This means events can be emitted even when | ||
@@ -146,2 +145,4 @@ * they're missing all the data for a particular structure. See the "Partials" topic listed in the sidebar for some | ||
makeImageUrl(`${root}/splashes/${guildID}/${hash}`, { size, format }), | ||
DiscoverySplash: (guildID, hash, format = 'webp', size) => | ||
makeImageUrl(`${root}/discovery-splashes/${guildID}/${hash}`, { size, format }), | ||
TeamIcon: (teamID, hash, { format = 'webp', size } = {}) => | ||
@@ -148,0 +149,0 @@ makeImageUrl(`${root}/team-icons/${teamID}/${hash}`, { size, format }), |
@@ -70,2 +70,3 @@ 'use strict'; | ||
* * `USE_EXTERNAL_EMOJIS` (use emojis from different guilds) | ||
* * `VIEW_GUILD_INSIGHTS` | ||
* * `CONNECT` (connect to a voice channel) | ||
@@ -105,3 +106,3 @@ * * `SPEAK` (speak in a voice channel) | ||
USE_EXTERNAL_EMOJIS: 1 << 18, | ||
VIEW_GUILD_INSIGHTS: 1 << 19, | ||
CONNECT: 1 << 20, | ||
@@ -113,3 +114,2 @@ SPEAK: 1 << 21, | ||
USE_VAD: 1 << 25, | ||
CHANGE_NICKNAME: 1 << 26, | ||
@@ -116,0 +116,0 @@ MANAGE_NICKNAMES: 1 << 27, |
@@ -558,11 +558,2 @@ 'use strict'; | ||
static cleanContent(str, message) { | ||
if (message.client.options.disableMentions === 'everyone') { | ||
str = str.replace(/@([^<>@ ]*)/gmsu, (match, target) => { | ||
if (target.match(/^[&!]?\d+$/)) { | ||
return `@${target}`; | ||
} else { | ||
return `@\u200b${target}`; | ||
} | ||
}); | ||
} | ||
str = str | ||
@@ -593,2 +584,11 @@ .replace(/<@!?[0-9]+>/g, input => { | ||
}); | ||
if (message.client.options.disableMentions === 'everyone') { | ||
str = str.replace(/@([^<>@ ]*)/gmsu, (match, target) => { | ||
if (target.match(/^[&!]?\d+$/)) { | ||
return `@${target}`; | ||
} else { | ||
return `@\u200b${target}`; | ||
} | ||
}); | ||
} | ||
if (message.client.options.disableMentions === 'all') { | ||
@@ -595,0 +595,0 @@ return Util.removeMentions(str); |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
954936
184
21283
7
21