diff --git a/discord.11.1-dev.js b/discord.11.1-dev.js
index 125aa95f..760dc235 100644
--- a/discord.11.1-dev.js
+++ b/discord.11.1-dev.js
@@ -33,9 +33,6 @@
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
-/******/ // identity function for calling harmony imports with the correct context
-/******/ __webpack_require__.i = function(value) { return value; };
-/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
@@ -63,14 +60,14 @@
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
-/******/ return __webpack_require__(__webpack_require__.s = 181);
+/******/ return __webpack_require__(__webpack_require__.s = 73);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
-/* WEBPACK VAR INJECTION */(function(process) {exports.Package = __webpack_require__(41);
+/* WEBPACK VAR INJECTION */(function(process) {exports.Package = __webpack_require__(53);
/**
* Options for a client.
@@ -125,7 +122,7 @@ exports.DefaultOptions = {
*/
ws: {
large_threshold: 250,
- compress: __webpack_require__(24).platform() !== 'browser',
+ compress: __webpack_require__(27).platform() !== 'browser',
properties: {
$os: process ? process.platform : 'discord.js',
$browser: 'discord.js',
@@ -667,6 +664,99 @@ exports.Colors = {
NOT_QUITE_BLACK: 0x23272A,
};
+/**
+ * An error encountered while performing an API request. Here are the potential errors:
+ * - UNKNOWN_ACCOUNT
+ * - UNKNOWN_APPLICATION
+ * - UNKNOWN_CHANNEL
+ * - UNKNOWN_GUILD
+ * - UNKNOWN_INTEGRATION
+ * - UNKNOWN_INVITE
+ * - UNKNOWN_MEMBER
+ * - UNKNOWN_MESSAGE
+ * - UNKNOWN_OVERWRITE
+ * - UNKNOWN_PROVIDER
+ * - UNKNOWN_ROLE
+ * - UNKNOWN_TOKEN
+ * - UNKNOWN_USER
+ * - UNKNOWN_EMOJI
+ * - BOT_PROHIBITED_ENDPOINT
+ * - BOT_ONLY_ENDPOINT
+ * - MAXIMUM_GUILDS
+ * - MAXIMUM_FRIENDS
+ * - MAXIMUM_PINS
+ * - MAXIMUM_ROLES
+ * - MAXIMUM_REACTIONS
+ * - UNAUTHORIZED
+ * - MISSING_ACCESS
+ * - INVALID_ACCOUNT_TYPE
+ * - CANNOT_EXECUTE_ON_DM
+ * - EMBED_DISABLED
+ * - CANNOT_EDIT_MESSAGE_BY_OTHER
+ * - CANNOT_SEND_EMPTY_MESSAGE
+ * - CANNOT_MESSAGE_USER
+ * - CANNOT_SEND_MESSAGES_IN_VOICE_CHANNEL
+ * - CHANNEL_VERIFICATION_LEVEL_TOO_HIGH
+ * - OAUTH2_APPLICATION_BOT_ABSENT
+ * - MAXIMUM_OAUTH2_APPLICATIONS
+ * - INVALID_OAUTH_STATE
+ * - MISSING_PERMISSIONS
+ * - INVALID_AUTHENTICATION_TOKEN
+ * - NOTE_TOO_LONG
+ * - INVALID_BULK_DELETE_QUANTITY
+ * - CANNOT_PIN_MESSAGE_IN_OTHER_CHANNEL
+ * - CANNOT_EXECUTE_ON_SYSTEM_MESSAGE
+ * - BULK_DELETE_MESSAGE_TOO_OLD
+ * - INVITE_ACCEPTED_TO_GUILD_NOT_CONTANING_BOT
+ * - REACTION_BLOCKED
+ * @typedef {string} APIError
+ */
+exports.APIErrors = {
+ UNKNOWN_ACCOUNT: 10001,
+ UNKNOWN_APPLICATION: 10002,
+ UNKNOWN_CHANNEL: 10003,
+ UNKNOWN_GUILD: 10004,
+ UNKNOWN_INTEGRATION: 10005,
+ UNKNOWN_INVITE: 10006,
+ UNKNOWN_MEMBER: 10007,
+ UNKNOWN_MESSAGE: 10008,
+ UNKNOWN_OVERWRITE: 10009,
+ UNKNOWN_PROVIDER: 10010,
+ UNKNOWN_ROLE: 10011,
+ UNKNOWN_TOKEN: 10012,
+ UNKNOWN_USER: 10013,
+ UNKNOWN_EMOJI: 10014,
+ BOT_PROHIBITED_ENDPOINT: 20001,
+ BOT_ONLY_ENDPOINT: 20002,
+ MAXIMUM_GUILDS: 30001,
+ MAXIMUM_FRIENDS: 30002,
+ MAXIMUM_PINS: 30003,
+ MAXIMUM_ROLES: 30005,
+ MAXIMUM_REACTIONS: 30010,
+ UNAUTHORIZED: 40001,
+ MISSING_ACCESS: 50001,
+ INVALID_ACCOUNT_TYPE: 50002,
+ CANNOT_EXECUTE_ON_DM: 50003,
+ EMBED_DISABLED: 50004,
+ CANNOT_EDIT_MESSAGE_BY_OTHER: 50005,
+ CANNOT_SEND_EMPTY_MESSAGE: 50006,
+ CANNOT_MESSAGE_USER: 50007,
+ CANNOT_SEND_MESSAGES_IN_VOICE_CHANNEL: 50008,
+ CHANNEL_VERIFICATION_LEVEL_TOO_HIGH: 50009,
+ OAUTH2_APPLICATION_BOT_ABSENT: 50010,
+ MAXIMUM_OAUTH2_APPLICATIONS: 50011,
+ INVALID_OAUTH_STATE: 50012,
+ MISSING_PERMISSIONS: 50013,
+ INVALID_AUTHENTICATION_TOKEN: 50014,
+ NOTE_TOO_LONG: 50015,
+ INVALID_BULK_DELETE_QUANTITY: 50016,
+ CANNOT_PIN_MESSAGE_IN_OTHER_CHANNEL: 50019,
+ CANNOT_EXECUTE_ON_SYSTEM_MESSAGE: 50021,
+ BULK_DELETE_MESSAGE_TOO_OLD: 50034,
+ INVITE_ACCEPTED_TO_GUILD_NOT_CONTANING_BOT: 50036,
+ REACTION_BLOCKED: 90001,
+};
+
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7)))
/***/ }),
@@ -1111,7 +1201,7 @@ module.exports = Collection;
/* 4 */
/***/ (function(module, exports, __webpack_require__) {
-/* WEBPACK VAR INJECTION */(function(Buffer) {const snekfetch = __webpack_require__(38);
+/* WEBPACK VAR INJECTION */(function(Buffer) {const snekfetch = __webpack_require__(30);
const Constants = __webpack_require__(0);
const ConstantsHttp = Constants.DefaultOptions.http;
@@ -1324,93 +1414,12 @@ class Util {
module.exports = Util;
-/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(6).Buffer))
+/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(5).Buffer))
/***/ }),
/* 5 */
/***/ (function(module, exports, __webpack_require__) {
-const Long = __webpack_require__(33);
-
-// Discord epoch (2015-01-01T00:00:00.000Z)
-const EPOCH = 1420070400000;
-let INCREMENT = 0;
-
-/**
- * A container for useful snowflake-related methods.
- */
-class SnowflakeUtil {
- constructor() {
- throw new Error(`The ${this.constructor.name} class may not be instantiated.`);
- }
-
- /**
- * A Twitter snowflake, except the epoch is 2015-01-01T00:00:00.000Z
- * ```
- * If we have a snowflake '266241948824764416' we can represent it as binary:
- *
- * 64 22 17 12 0
- * 000000111011000111100001101001000101000000 00001 00000 000000000000
- * number of ms since Discord epoch worker pid increment
- * ```
- * @typedef {string} Snowflake
- */
-
- /**
- * Generates a Discord snowflake.
- * This hardcodes the worker ID as 1 and the process ID as 0.
- * @returns {Snowflake} The generated snowflake
- */
- static generate() {
- if (INCREMENT >= 4095) INCREMENT = 0;
- const BINARY = `${pad((Date.now() - EPOCH).toString(2), 42)}0000100000${pad((INCREMENT++).toString(2), 12)}`;
- return Long.fromString(BINARY, 2).toString();
- }
-
- /**
- * A deconstructed snowflake.
- * @typedef {Object} DeconstructedSnowflake
- * @property {number} timestamp Timestamp the snowflake was created
- * @property {Date} date Date the snowflake was created
- * @property {number} workerID Worker ID in the snowflake
- * @property {number} processID Process ID in the snowflake
- * @property {number} increment Increment in the snowflake
- * @property {string} binary Binary representation of the snowflake
- */
-
- /**
- * Deconstructs a Discord snowflake.
- * @param {Snowflake} snowflake Snowflake to deconstruct
- * @returns {DeconstructedSnowflake} Deconstructed snowflake
- */
- static deconstruct(snowflake) {
- const BINARY = pad(Long.fromString(snowflake).toString(2), 64);
- const res = {
- timestamp: parseInt(BINARY.substring(0, 42), 2) + EPOCH,
- workerID: parseInt(BINARY.substring(42, 47), 2),
- processID: parseInt(BINARY.substring(47, 52), 2),
- increment: parseInt(BINARY.substring(52, 64), 2),
- binary: BINARY,
- };
- Object.defineProperty(res, 'date', {
- get: function get() { return new Date(this.timestamp); },
- enumerable: true,
- });
- return res;
- }
-}
-
-function pad(v, n, c = '0') {
- return String(v).length >= n ? String(v) : (String(c).repeat(n) + v).slice(-n);
-}
-
-module.exports = SnowflakeUtil;
-
-
-/***/ }),
-/* 6 */
-/***/ (function(module, exports, __webpack_require__) {
-
"use strict";
/* WEBPACK VAR INJECTION */(function(global) {/*!
* The buffer module from node.js, for the browser.
@@ -1422,9 +1431,9 @@ module.exports = SnowflakeUtil;
-var base64 = __webpack_require__(77)
-var ieee754 = __webpack_require__(80)
-var isArray = __webpack_require__(58)
+var base64 = __webpack_require__(74)
+var ieee754 = __webpack_require__(75)
+var isArray = __webpack_require__(43)
exports.Buffer = Buffer
exports.SlowBuffer = SlowBuffer
@@ -3202,7 +3211,34 @@ function isnan (val) {
return val !== val // eslint-disable-line no-self-compare
}
-/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(9)))
+/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(6)))
+
+/***/ }),
+/* 6 */
+/***/ (function(module, exports) {
+
+var g;
+
+// This works in non-strict mode
+g = (function() {
+ return this;
+})();
+
+try {
+ // This works if eval is allowed (see CSP)
+ g = g || Function("return this")() || (1,eval)("this");
+} catch(e) {
+ // This works if the window reference is available
+ if(typeof window === "object")
+ g = window;
+}
+
+// g can still be undefined, but nothing to do about it...
+// We return undefined, instead of nothing here, so it's
+// easier to handle this case. if(!global) { ...}
+
+module.exports = g;
+
/***/ }),
/* 7 */
@@ -3398,441 +3434,87 @@ process.umask = function() { return 0; };
/* 8 */
/***/ (function(module, exports, __webpack_require__) {
-const Constants = __webpack_require__(0);
-const util = __webpack_require__(22);
+const Long = __webpack_require__(35);
+
+// Discord epoch (2015-01-01T00:00:00.000Z)
+const EPOCH = 1420070400000;
+let INCREMENT = 0;
/**
- * Data structure that makes it easy to interact with a permission bitfield. All {@link GuildMember}s have a set of
- * permissions in their guild, and each channel in the guild may also have {@link PermissionOverwrites} for the member
- * that override their default permissions.
+ * A container for useful snowflake-related methods.
*/
-class Permissions {
- /**
- * @param {GuildMember} [member] Member the permissions are for **(deprecated)**
- * @param {number|PermissionResolvable[]} permissions Permissions or bitfield to read from
- */
- constructor(member, permissions) {
- permissions = typeof member === 'object' && !(member instanceof Array) ? permissions : member;
-
- /**
- * Member the permissions are for
- * @type {GuildMember}
- * @deprecated
- */
- this._member = typeof member === 'object' ? member : null;
-
- /**
- * Bitfield of the packed permissions
- * @type {number}
- */
- this.bitfield = typeof permissions === 'number' ? permissions : this.constructor.resolve(permissions);
- }
-
- get member() {
- return this._member;
- }
-
- set member(value) {
- this._member = value;
+class SnowflakeUtil {
+ constructor() {
+ throw new Error(`The ${this.constructor.name} class may not be instantiated.`);
}
/**
- * Bitfield of the packed permissions
- * @type {number}
- * @see {@link Permissions#bitfield}
- * @deprecated
- * @readonly
- */
- get raw() {
- return this.bitfield;
- }
-
- set raw(raw) {
- this.bitfield = raw;
- }
-
- /**
- * Checks whether the bitfield has a permission, or multiple permissions.
- * @param {PermissionResolvable|PermissionResolvable[]} permission Permission(s) to check for
- * @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override
- * @returns {boolean}
- */
- has(permission, checkAdmin = true) {
- if (permission instanceof Array) return permission.every(p => this.has(p, checkAdmin));
- permission = this.constructor.resolve(permission);
- if (checkAdmin && (this.bitfield & this.constructor.FLAGS.ADMINISTRATOR) > 0) return true;
- return (this.bitfield & permission) === permission;
- }
-
- /**
- * Gets all given permissions that are missing from the bitfield.
- * @param {PermissionResolvable[]} permissions Permissions to check for
- * @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override
- * @returns {PermissionResolvable[]}
- */
- missing(permissions, checkAdmin = true) {
- return permissions.filter(p => !this.has(p, checkAdmin));
- }
-
- /**
- * Adds permissions to this one, creating a new instance to represent the new bitfield.
- * @param {...PermissionResolvable} permissions Permissions to add
- * @returns {Permissions}
- */
- add(...permissions) {
- let total = 0;
- for (let p = 0; p < permissions.length; p++) {
- const perm = this.constructor.resolve(permissions[p]);
- if ((this.bitfield & perm) !== perm) total |= perm;
- }
- return new this.constructor(this.member, this.bitfield | total);
- }
-
- /**
- * Removes permissions to this one, creating a new instance to represent the new bitfield.
- * @param {...PermissionResolvable} permissions Permissions to remove
- * @returns {Permissions}
- */
- remove(...permissions) {
- let total = 0;
- for (let p = 0; p < permissions.length; p++) {
- const perm = this.constructor.resolve(permissions[p]);
- if ((this.bitfield & perm) === perm) total |= perm;
- }
- return new this.constructor(this.member, this.bitfield & ~total);
- }
-
- /**
- * Gets an object mapping permission name (like `READ_MESSAGES`) to a {@link boolean} indicating whether the
- * permission is available.
- * @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override
- * @returns {Object}
- */
- serialize(checkAdmin = true) {
- const serialized = {};
- for (const perm in this.constructor.FLAGS) serialized[perm] = this.has(perm, checkAdmin);
- return serialized;
- }
-
- /**
- * Checks whether the user has a certain permission, e.g. `READ_MESSAGES`.
- * @param {PermissionResolvable} permission The permission to check for
- * @param {boolean} [explicit=false] Whether to require the user to explicitly have the exact permission
- * @returns {boolean}
- * @see {@link Permissions#has}
- * @deprecated
- */
- hasPermission(permission, explicit = false) {
- return this.has(permission, !explicit);
- }
-
- /**
- * Checks whether the user has all specified permissions.
- * @param {PermissionResolvable[]} permissions The permissions to check for
- * @param {boolean} [explicit=false] Whether to require the user to explicitly have the exact permissions
- * @returns {boolean}
- * @see {@link Permissions#has}
- * @deprecated
- */
- hasPermissions(permissions, explicit = false) {
- return this.has(permissions, !explicit);
- }
-
- /**
- * Checks whether the user has all specified permissions, and lists any missing permissions.
- * @param {PermissionResolvable[]} permissions The permissions to check for
- * @param {boolean} [explicit=false] Whether to require the user to explicitly have the exact permissions
- * @returns {PermissionResolvable[]}
- * @see {@link Permissions#missing}
- * @deprecated
- */
- missingPermissions(permissions, explicit = false) {
- return this.missing(permissions, !explicit);
- }
-
- /**
- * Data that can be resolved to give a permission number. This can be:
- * - A string (see {@link Permissions.FLAGS})
- * - A permission number
- * @typedef {string|number} PermissionResolvable
+ * A Twitter snowflake, except the epoch is 2015-01-01T00:00:00.000Z
+ * ```
+ * If we have a snowflake '266241948824764416' we can represent it as binary:
+ *
+ * 64 22 17 12 0
+ * 000000111011000111100001101001000101000000 00001 00000 000000000000
+ * number of ms since Discord epoch worker pid increment
+ * ```
+ * @typedef {string} Snowflake
*/
/**
- * Resolves permissions to their numeric form.
- * @param {PermissionResolvable|PermissionResolvable[]} permission - Permission(s) to resolve
- * @returns {number}
+ * Generates a Discord snowflake.
+ * This hardcodes the worker ID as 1 and the process ID as 0.
+ * @returns {Snowflake} The generated snowflake
*/
- static resolve(permission) {
- if (permission instanceof Array) return permission.map(p => this.resolve(p)).reduce((prev, p) => prev | p, 0);
- if (typeof permission === 'string') permission = this.FLAGS[permission];
- if (typeof permission !== 'number' || permission < 1) throw new RangeError(Constants.Errors.NOT_A_PERMISSION);
- return permission;
+ static generate() {
+ if (INCREMENT >= 4095) INCREMENT = 0;
+ const BINARY = `${pad((Date.now() - EPOCH).toString(2), 42)}0000100000${pad((INCREMENT++).toString(2), 12)}`;
+ return Long.fromString(BINARY, 2).toString();
+ }
+
+ /**
+ * A deconstructed snowflake.
+ * @typedef {Object} DeconstructedSnowflake
+ * @property {number} timestamp Timestamp the snowflake was created
+ * @property {Date} date Date the snowflake was created
+ * @property {number} workerID Worker ID in the snowflake
+ * @property {number} processID Process ID in the snowflake
+ * @property {number} increment Increment in the snowflake
+ * @property {string} binary Binary representation of the snowflake
+ */
+
+ /**
+ * Deconstructs a Discord snowflake.
+ * @param {Snowflake} snowflake Snowflake to deconstruct
+ * @returns {DeconstructedSnowflake} Deconstructed snowflake
+ */
+ static deconstruct(snowflake) {
+ const BINARY = pad(Long.fromString(snowflake).toString(2), 64);
+ const res = {
+ timestamp: parseInt(BINARY.substring(0, 42), 2) + EPOCH,
+ workerID: parseInt(BINARY.substring(42, 47), 2),
+ processID: parseInt(BINARY.substring(47, 52), 2),
+ increment: parseInt(BINARY.substring(52, 64), 2),
+ binary: BINARY,
+ };
+ Object.defineProperty(res, 'date', {
+ get: function get() { return new Date(this.timestamp); },
+ enumerable: true,
+ });
+ return res;
}
}
-/**
- * Numeric permission flags. All available properties:
- * - `ADMINISTRATOR` (implicitly has *all* permissions, and bypasses all channel overwrites)
- * - `CREATE_INSTANT_INVITE` (create invitations to the guild)
- * - `KICK_MEMBERS`
- * - `BAN_MEMBERS`
- * - `MANAGE_CHANNELS` (edit and reorder channels)
- * - `MANAGE_GUILD` (edit the guild information, region, etc.)
- * - `ADD_REACTIONS` (add new reactions to messages)
- * - `VIEW_AUDIT_LOG`
- * - `READ_MESSAGES`
- * - `SEND_MESSAGES`
- * - `SEND_TTS_MESSAGES`
- * - `MANAGE_MESSAGES` (delete messages and reactions)
- * - `EMBED_LINKS` (links posted will have a preview embedded)
- * - `ATTACH_FILES`
- * - `READ_MESSAGE_HISTORY` (view messages that were posted prior to opening Discord)
- * - `MENTION_EVERYONE`
- * - `USE_EXTERNAL_EMOJIS` (use emojis from different guilds)
- * - `EXTERNAL_EMOJIS` **(deprecated)**
- * - `CONNECT` (connect to a voice channel)
- * - `SPEAK` (speak in a voice channel)
- * - `MUTE_MEMBERS` (mute members across all voice channels)
- * - `DEAFEN_MEMBERS` (deafen members across all voice channels)
- * - `MOVE_MEMBERS` (move members between voice channels)
- * - `USE_VAD` (use voice activity detection)
- * - `CHANGE_NICKNAME`
- * - `MANAGE_NICKNAMES` (change other members' nicknames)
- * - `MANAGE_ROLES`
- * - `MANAGE_ROLES_OR_PERMISSIONS` **(deprecated)**
- * - `MANAGE_WEBHOOKS`
- * - `MANAGE_EMOJIS`
- * @type {Object}
- * @see {@link https://discordapp.com/developers/docs/topics/permissions}
- */
-Permissions.FLAGS = {
- CREATE_INSTANT_INVITE: 1 << 0,
- KICK_MEMBERS: 1 << 1,
- BAN_MEMBERS: 1 << 2,
- ADMINISTRATOR: 1 << 3,
- MANAGE_CHANNELS: 1 << 4,
- MANAGE_GUILD: 1 << 5,
- ADD_REACTIONS: 1 << 6,
- VIEW_AUDIT_LOG: 1 << 7,
+function pad(v, n, c = '0') {
+ return String(v).length >= n ? String(v) : (String(c).repeat(n) + v).slice(-n);
+}
- READ_MESSAGES: 1 << 10,
- SEND_MESSAGES: 1 << 11,
- SEND_TTS_MESSAGES: 1 << 12,
- MANAGE_MESSAGES: 1 << 13,
- EMBED_LINKS: 1 << 14,
- ATTACH_FILES: 1 << 15,
- READ_MESSAGE_HISTORY: 1 << 16,
- MENTION_EVERYONE: 1 << 17,
- EXTERNAL_EMOJIS: 1 << 18,
- USE_EXTERNAL_EMOJIS: 1 << 18,
-
- CONNECT: 1 << 20,
- SPEAK: 1 << 21,
- MUTE_MEMBERS: 1 << 22,
- DEAFEN_MEMBERS: 1 << 23,
- MOVE_MEMBERS: 1 << 24,
- USE_VAD: 1 << 25,
-
- CHANGE_NICKNAME: 1 << 26,
- MANAGE_NICKNAMES: 1 << 27,
- MANAGE_ROLES: 1 << 28,
- MANAGE_ROLES_OR_PERMISSIONS: 1 << 28,
- MANAGE_WEBHOOKS: 1 << 29,
- MANAGE_EMOJIS: 1 << 30,
-};
-
-/**
- * Bitfield representing every permission combined
- * @type {number}
- */
-Permissions.ALL = Object.keys(Permissions.FLAGS).reduce((all, p) => all | Permissions.FLAGS[p], 0);
-
-/**
- * Bitfield representing the default permissions for users
- * @type {number}
- */
-Permissions.DEFAULT = 104324097;
-
-/**
- * @class EvaluatedPermissions
- * @classdesc The final evaluated permissions for a member in a channel
- * @see {@link Permissions}
- * @deprecated
- */
-
-Permissions.prototype.hasPermission = util.deprecate(Permissions.prototype.hasPermission,
- 'EvaluatedPermissions#hasPermission is deprecated, use Permissions#has instead');
-Permissions.prototype.hasPermissions = util.deprecate(Permissions.prototype.hasPermissions,
- 'EvaluatedPermissions#hasPermissions is deprecated, use Permissions#has instead');
-Permissions.prototype.missingPermissions = util.deprecate(Permissions.prototype.missingPermissions,
- 'EvaluatedPermissions#missingPermissions is deprecated, use Permissions#missing instead');
-Object.defineProperty(Permissions.prototype, 'member', {
- get: util
- .deprecate(Object.getOwnPropertyDescriptor(Permissions.prototype, 'member').get,
- 'EvaluatedPermissions#member is deprecated'),
-});
-
-module.exports = Permissions;
+module.exports = SnowflakeUtil;
/***/ }),
/* 9 */
/***/ (function(module, exports) {
-var g;
-
-// This works in non-strict mode
-g = (function() {
- return this;
-})();
-
-try {
- // This works if eval is allowed (see CSP)
- g = g || Function("return this")() || (1,eval)("this");
-} catch(e) {
- // This works if the window reference is available
- if(typeof window === "object")
- g = window;
-}
-
-// g can still be undefined, but nothing to do about it...
-// We return undefined, instead of nothing here, so it's
-// easier to handle this case. if(!global) { ...}
-
-module.exports = g;
-
-
-/***/ }),
-/* 10 */
-/***/ (function(module, exports) {
-
-if (typeof Object.create === 'function') {
- // implementation from standard node.js 'util' module
- module.exports = function inherits(ctor, superCtor) {
- ctor.super_ = superCtor
- ctor.prototype = Object.create(superCtor.prototype, {
- constructor: {
- value: ctor,
- enumerable: false,
- writable: true,
- configurable: true
- }
- });
- };
-} else {
- // old school shim for old browsers
- module.exports = function inherits(ctor, superCtor) {
- ctor.super_ = superCtor
- var TempCtor = function () {}
- TempCtor.prototype = superCtor.prototype
- ctor.prototype = new TempCtor()
- ctor.prototype.constructor = ctor
- }
-}
-
-
-/***/ }),
-/* 11 */
-/***/ (function(module, exports) {
-
-/**
- * Represents a user's presence.
- */
-class Presence {
- constructor(data = {}) {
- /**
- * The status of the presence:
- *
- * * **`online`** - user is online
- * * **`offline`** - user is offline or invisible
- * * **`idle`** - user is AFK
- * * **`dnd`** - user is in Do not Disturb
- * @type {string}
- */
- this.status = data.status || 'offline';
-
- /**
- * The game that the user is playing
- * @type {?Game}
- */
- this.game = data.game ? new Game(data.game) : null;
- }
-
- update(data) {
- this.status = data.status || this.status;
- this.game = data.game ? new Game(data.game) : null;
- }
-
- /**
- * Whether this presence is equal to another
- * @param {Presence} presence The presence to compare with
- * @returns {boolean}
- */
- equals(presence) {
- return this === presence || (
- presence &&
- this.status === presence.status &&
- this.game ? this.game.equals(presence.game) : !presence.game
- );
- }
-}
-
-/**
- * Represents a game that is part of a user's presence.
- */
-class Game {
- constructor(data) {
- /**
- * The name of the game being played
- * @type {string}
- */
- this.name = data.name;
-
- /**
- * The type of the game status
- * @type {number}
- */
- this.type = data.type;
-
- /**
- * If the game is being streamed, a link to the stream
- * @type {?string}
- */
- this.url = data.url || null;
- }
-
- /**
- * Whether or not the game is being streamed
- * @type {boolean}
- * @readonly
- */
- get streaming() {
- return this.type === 1;
- }
-
- /**
- * Whether this game is equal to another game
- * @param {Game} game The game to compare with
- * @returns {boolean}
- */
- equals(game) {
- return this === game || (
- game &&
- this.name === game.name &&
- this.type === game.type &&
- this.url === game.url
- );
- }
-}
-
-exports.Presence = Presence;
-exports.Game = Game;
-
-
-/***/ }),
-/* 12 */
-/***/ (function(module, exports) {
-
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
@@ -4138,10 +3820,341 @@ function isUndefined(arg) {
/***/ }),
-/* 13 */
+/* 10 */
+/***/ (function(module, exports) {
+
+if (typeof Object.create === 'function') {
+ // implementation from standard node.js 'util' module
+ module.exports = function inherits(ctor, superCtor) {
+ ctor.super_ = superCtor
+ ctor.prototype = Object.create(superCtor.prototype, {
+ constructor: {
+ value: ctor,
+ enumerable: false,
+ writable: true,
+ configurable: true
+ }
+ });
+ };
+} else {
+ // old school shim for old browsers
+ module.exports = function inherits(ctor, superCtor) {
+ ctor.super_ = superCtor
+ var TempCtor = function () {}
+ TempCtor.prototype = superCtor.prototype
+ ctor.prototype = new TempCtor()
+ ctor.prototype.constructor = ctor
+ }
+}
+
+
+/***/ }),
+/* 11 */
+/***/ (function(module, exports, __webpack_require__) {
+
+const Constants = __webpack_require__(0);
+const util = __webpack_require__(20);
+
+/**
+ * Data structure that makes it easy to interact with a permission bitfield. All {@link GuildMember}s have a set of
+ * permissions in their guild, and each channel in the guild may also have {@link PermissionOverwrites} for the member
+ * that override their default permissions.
+ */
+class Permissions {
+ /**
+ * @param {GuildMember} [member] Member the permissions are for **(deprecated)**
+ * @param {number|PermissionResolvable[]} permissions Permissions or bitfield to read from
+ */
+ constructor(member, permissions) {
+ permissions = typeof member === 'object' && !(member instanceof Array) ? permissions : member;
+
+ /**
+ * Member the permissions are for
+ * @type {GuildMember}
+ * @deprecated
+ */
+ this._member = typeof member === 'object' ? member : null;
+
+ /**
+ * Bitfield of the packed permissions
+ * @type {number}
+ */
+ this.bitfield = typeof permissions === 'number' ? permissions : this.constructor.resolve(permissions);
+ }
+
+ get member() {
+ return this._member;
+ }
+
+ set member(value) {
+ this._member = value;
+ }
+
+ /**
+ * Bitfield of the packed permissions
+ * @type {number}
+ * @see {@link Permissions#bitfield}
+ * @deprecated
+ * @readonly
+ */
+ get raw() {
+ return this.bitfield;
+ }
+
+ set raw(raw) {
+ this.bitfield = raw;
+ }
+
+ /**
+ * Checks whether the bitfield has a permission, or multiple permissions.
+ * @param {PermissionResolvable|PermissionResolvable[]} permission Permission(s) to check for
+ * @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override
+ * @returns {boolean}
+ */
+ has(permission, checkAdmin = true) {
+ if (permission instanceof Array) return permission.every(p => this.has(p, checkAdmin));
+ permission = this.constructor.resolve(permission);
+ if (checkAdmin && (this.bitfield & this.constructor.FLAGS.ADMINISTRATOR) > 0) return true;
+ return (this.bitfield & permission) === permission;
+ }
+
+ /**
+ * Gets all given permissions that are missing from the bitfield.
+ * @param {PermissionResolvable[]} permissions Permissions to check for
+ * @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override
+ * @returns {PermissionResolvable[]}
+ */
+ missing(permissions, checkAdmin = true) {
+ return permissions.filter(p => !this.has(p, checkAdmin));
+ }
+
+ /**
+ * Adds permissions to this one, creating a new instance to represent the new bitfield.
+ * @param {...PermissionResolvable} permissions Permissions to add
+ * @returns {Permissions}
+ */
+ add(...permissions) {
+ let total = 0;
+ for (let p = 0; p < permissions.length; p++) {
+ const perm = this.constructor.resolve(permissions[p]);
+ if ((this.bitfield & perm) !== perm) total |= perm;
+ }
+ return new this.constructor(this.member, this.bitfield | total);
+ }
+
+ /**
+ * Removes permissions to this one, creating a new instance to represent the new bitfield.
+ * @param {...PermissionResolvable} permissions Permissions to remove
+ * @returns {Permissions}
+ */
+ remove(...permissions) {
+ let total = 0;
+ for (let p = 0; p < permissions.length; p++) {
+ const perm = this.constructor.resolve(permissions[p]);
+ if ((this.bitfield & perm) === perm) total |= perm;
+ }
+ return new this.constructor(this.member, this.bitfield & ~total);
+ }
+
+ /**
+ * Gets an object mapping permission name (like `READ_MESSAGES`) to a {@link boolean} indicating whether the
+ * permission is available.
+ * @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override
+ * @returns {Object}
+ */
+ serialize(checkAdmin = true) {
+ const serialized = {};
+ for (const perm in this.constructor.FLAGS) serialized[perm] = this.has(perm, checkAdmin);
+ return serialized;
+ }
+
+ /**
+ * Checks whether the user has a certain permission, e.g. `READ_MESSAGES`.
+ * @param {PermissionResolvable} permission The permission to check for
+ * @param {boolean} [explicit=false] Whether to require the user to explicitly have the exact permission
+ * @returns {boolean}
+ * @see {@link Permissions#has}
+ * @deprecated
+ */
+ hasPermission(permission, explicit = false) {
+ return this.has(permission, !explicit);
+ }
+
+ /**
+ * Checks whether the user has all specified permissions.
+ * @param {PermissionResolvable[]} permissions The permissions to check for
+ * @param {boolean} [explicit=false] Whether to require the user to explicitly have the exact permissions
+ * @returns {boolean}
+ * @see {@link Permissions#has}
+ * @deprecated
+ */
+ hasPermissions(permissions, explicit = false) {
+ return this.has(permissions, !explicit);
+ }
+
+ /**
+ * Checks whether the user has all specified permissions, and lists any missing permissions.
+ * @param {PermissionResolvable[]} permissions The permissions to check for
+ * @param {boolean} [explicit=false] Whether to require the user to explicitly have the exact permissions
+ * @returns {PermissionResolvable[]}
+ * @see {@link Permissions#missing}
+ * @deprecated
+ */
+ missingPermissions(permissions, explicit = false) {
+ return this.missing(permissions, !explicit);
+ }
+
+ /**
+ * Data that can be resolved to give a permission number. This can be:
+ * - A string (see {@link Permissions.FLAGS})
+ * - A permission number
+ * @typedef {string|number} PermissionResolvable
+ */
+
+ /**
+ * Resolves permissions to their numeric form.
+ * @param {PermissionResolvable|PermissionResolvable[]} permission - Permission(s) to resolve
+ * @returns {number}
+ */
+ static resolve(permission) {
+ if (permission instanceof Array) return permission.map(p => this.resolve(p)).reduce((prev, p) => prev | p, 0);
+ if (typeof permission === 'string') permission = this.FLAGS[permission];
+ if (typeof permission !== 'number' || permission < 1) throw new RangeError(Constants.Errors.NOT_A_PERMISSION);
+ return permission;
+ }
+}
+
+/**
+ * Numeric permission flags. All available properties:
+ * - `ADMINISTRATOR` (implicitly has *all* permissions, and bypasses all channel overwrites)
+ * - `CREATE_INSTANT_INVITE` (create invitations to the guild)
+ * - `KICK_MEMBERS`
+ * - `BAN_MEMBERS`
+ * - `MANAGE_CHANNELS` (edit and reorder channels)
+ * - `MANAGE_GUILD` (edit the guild information, region, etc.)
+ * - `ADD_REACTIONS` (add new reactions to messages)
+ * - `VIEW_AUDIT_LOG`
+ * - `READ_MESSAGES`
+ * - `SEND_MESSAGES`
+ * - `SEND_TTS_MESSAGES`
+ * - `MANAGE_MESSAGES` (delete messages and reactions)
+ * - `EMBED_LINKS` (links posted will have a preview embedded)
+ * - `ATTACH_FILES`
+ * - `READ_MESSAGE_HISTORY` (view messages that were posted prior to opening Discord)
+ * - `MENTION_EVERYONE`
+ * - `USE_EXTERNAL_EMOJIS` (use emojis from different guilds)
+ * - `EXTERNAL_EMOJIS` **(deprecated)**
+ * - `CONNECT` (connect to a voice channel)
+ * - `SPEAK` (speak in a voice channel)
+ * - `MUTE_MEMBERS` (mute members across all voice channels)
+ * - `DEAFEN_MEMBERS` (deafen members across all voice channels)
+ * - `MOVE_MEMBERS` (move members between voice channels)
+ * - `USE_VAD` (use voice activity detection)
+ * - `CHANGE_NICKNAME`
+ * - `MANAGE_NICKNAMES` (change other members' nicknames)
+ * - `MANAGE_ROLES`
+ * - `MANAGE_ROLES_OR_PERMISSIONS` **(deprecated)**
+ * - `MANAGE_WEBHOOKS`
+ * - `MANAGE_EMOJIS`
+ * @type {Object}
+ * @see {@link https://discordapp.com/developers/docs/topics/permissions}
+ */
+Permissions.FLAGS = {
+ CREATE_INSTANT_INVITE: 1 << 0,
+ KICK_MEMBERS: 1 << 1,
+ BAN_MEMBERS: 1 << 2,
+ ADMINISTRATOR: 1 << 3,
+ MANAGE_CHANNELS: 1 << 4,
+ MANAGE_GUILD: 1 << 5,
+ ADD_REACTIONS: 1 << 6,
+ VIEW_AUDIT_LOG: 1 << 7,
+
+ READ_MESSAGES: 1 << 10,
+ SEND_MESSAGES: 1 << 11,
+ SEND_TTS_MESSAGES: 1 << 12,
+ MANAGE_MESSAGES: 1 << 13,
+ EMBED_LINKS: 1 << 14,
+ ATTACH_FILES: 1 << 15,
+ READ_MESSAGE_HISTORY: 1 << 16,
+ MENTION_EVERYONE: 1 << 17,
+ EXTERNAL_EMOJIS: 1 << 18,
+ USE_EXTERNAL_EMOJIS: 1 << 18,
+
+ CONNECT: 1 << 20,
+ SPEAK: 1 << 21,
+ MUTE_MEMBERS: 1 << 22,
+ DEAFEN_MEMBERS: 1 << 23,
+ MOVE_MEMBERS: 1 << 24,
+ USE_VAD: 1 << 25,
+
+ CHANGE_NICKNAME: 1 << 26,
+ MANAGE_NICKNAMES: 1 << 27,
+ MANAGE_ROLES: 1 << 28,
+ MANAGE_ROLES_OR_PERMISSIONS: 1 << 28,
+ MANAGE_WEBHOOKS: 1 << 29,
+ MANAGE_EMOJIS: 1 << 30,
+};
+
+/**
+ * Bitfield representing every permission combined
+ * @type {number}
+ */
+Permissions.ALL = Object.keys(Permissions.FLAGS).reduce((all, p) => all | Permissions.FLAGS[p], 0);
+
+/**
+ * Bitfield representing the default permissions for users
+ * @type {number}
+ */
+Permissions.DEFAULT = 104324097;
+
+/**
+ * @class EvaluatedPermissions
+ * @classdesc The final evaluated permissions for a member in a channel
+ * @see {@link Permissions}
+ * @deprecated
+ */
+
+Permissions.prototype.hasPermission = util.deprecate(Permissions.prototype.hasPermission,
+ 'EvaluatedPermissions#hasPermission is deprecated, use Permissions#has instead');
+Permissions.prototype.hasPermissions = util.deprecate(Permissions.prototype.hasPermissions,
+ 'EvaluatedPermissions#hasPermissions is deprecated, use Permissions#has instead');
+Permissions.prototype.missingPermissions = util.deprecate(Permissions.prototype.missingPermissions,
+ 'EvaluatedPermissions#missingPermissions is deprecated, use Permissions#missing instead');
+Object.defineProperty(Permissions.prototype, 'member', {
+ get: util
+ .deprecate(Object.getOwnPropertyDescriptor(Permissions.prototype, 'member').get,
+ 'EvaluatedPermissions#member is deprecated'),
+});
+
+module.exports = Permissions;
+
+
+/***/ }),
+/* 12 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
// a duplex stream is just a stream that is both readable and writable.
// Since JS doesn't have multiple prototypal inheritance, this class
// prototypally inherits from Readable, and then parasitically from
@@ -4151,6 +4164,10 @@ function isUndefined(arg) {
/**/
+var processNextTick = __webpack_require__(25);
+/**/
+
+/**/
var objectKeys = Object.keys || function (obj) {
var keys = [];
for (var key in obj) {
@@ -4162,16 +4179,12 @@ var objectKeys = Object.keys || function (obj) {
module.exports = Duplex;
/**/
-var processNextTick = __webpack_require__(34);
-/**/
-
-/**/
-var util = __webpack_require__(20);
+var util = __webpack_require__(18);
util.inherits = __webpack_require__(10);
/**/
-var Readable = __webpack_require__(59);
-var Writable = __webpack_require__(36);
+var Readable = __webpack_require__(44);
+var Writable = __webpack_require__(33);
util.inherits(Duplex, Readable);
@@ -4212,6 +4225,34 @@ function onEndNT(self) {
self.end();
}
+Object.defineProperty(Duplex.prototype, 'destroyed', {
+ get: function () {
+ if (this._readableState === undefined || this._writableState === undefined) {
+ return false;
+ }
+ return this._readableState.destroyed && this._writableState.destroyed;
+ },
+ set: function (value) {
+ // we ignore the value if the stream
+ // has not been initialized yet
+ if (this._readableState === undefined || this._writableState === undefined) {
+ return;
+ }
+
+ // backward compatibility, the user is explicitly
+ // managing destroyed
+ this._readableState.destroyed = value;
+ this._writableState.destroyed = value;
+ }
+});
+
+Duplex.prototype._destroy = function (err, cb) {
+ this.push(null);
+ this.end();
+
+ processNextTick(cb, err);
+};
+
function forEach(xs, f) {
for (var i = 0, l = xs.length; i < l; i++) {
f(xs[i], i);
@@ -4219,47 +4260,84 @@ function forEach(xs, f) {
}
/***/ }),
-/* 14 */
+/* 13 */
/***/ (function(module, exports, __webpack_require__) {
-const Snowflake = __webpack_require__(5);
+const TextBasedChannel = __webpack_require__(21);
+const Constants = __webpack_require__(0);
+const Presence = __webpack_require__(15).Presence;
+const Snowflake = __webpack_require__(8);
/**
- * Represents any channel on Discord.
+ * Represents a user on Discord.
+ * @implements {TextBasedChannel}
*/
-class Channel {
+class User {
constructor(client, data) {
/**
- * The client that instantiated the Channel
- * @name Channel#client
- * @type {Client}
+ * The client that created the instance of the the user
+ * @name User#client
+ * @type {}
* @readonly
*/
Object.defineProperty(this, 'client', { value: client });
- /**
- * 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
- * @type {string}
- */
- this.type = null;
-
if (data) this.setup(data);
}
setup(data) {
/**
- * The unique ID of the channel
+ * The ID of the user
* @type {Snowflake}
*/
this.id = data.id;
+
+ /**
+ * The username of the user
+ * @type {string}
+ */
+ this.username = data.username;
+
+ /**
+ * A discriminator based on username for the user
+ * @type {string}
+ */
+ this.discriminator = data.discriminator;
+
+ /**
+ * The ID of the user's avatar
+ * @type {string}
+ */
+ this.avatar = data.avatar;
+
+ /**
+ * Whether or not the user is a bot
+ * @type {boolean}
+ */
+ this.bot = Boolean(data.bot);
+
+ /**
+ * The ID of the last message sent by the user, if one was sent
+ * @type {?Snowflake}
+ */
+ this.lastMessageID = null;
+
+ /**
+ * The Message object of the last message sent by the user, if one was sent
+ * @type {?Message}
+ */
+ this.lastMessage = null;
+ }
+
+ patch(data) {
+ for (const prop of ['id', 'username', 'discriminator', 'avatar', 'bot']) {
+ if (typeof data[prop] !== 'undefined') this[prop] = data[prop];
+ }
+ if (data.token) this.client.token = data.token;
}
/**
- * The timestamp the channel was created at
+ * The timestamp the user was created at
* @type {number}
* @readonly
*/
@@ -4268,7 +4346,7 @@ class Channel {
}
/**
- * The time the channel was created
+ * The time the user was created
* @type {Date}
* @readonly
*/
@@ -4277,29 +4355,226 @@ class Channel {
}
/**
- * Deletes the channel.
- * @returns {Promise}
- * @example
- * // Delete the channel
- * channel.delete()
- * .then() // Success
- * .catch(console.error); // Log error
+ * The presence of this user
+ * @type {Presence}
+ * @readonly
*/
- delete() {
+ get presence() {
+ if (this.client.presences.has(this.id)) return this.client.presences.get(this.id);
+ for (const guild of this.client.guilds.values()) {
+ if (guild.presences.has(this.id)) return guild.presences.get(this.id);
+ }
+ return new Presence();
+ }
+
+ /**
+ * A link to the user's avatar
+ * @type {?string}
+ * @readonly
+ */
+ get avatarURL() {
+ if (!this.avatar) return null;
+ return Constants.Endpoints.User(this).Avatar(this.client.options.http.cdn, this.avatar);
+ }
+
+ /**
+ * A link to the user's default avatar
+ * @type {string}
+ * @readonly
+ */
+ get defaultAvatarURL() {
+ const avatars = Object.keys(Constants.DefaultAvatars);
+ const avatar = avatars[this.discriminator % avatars.length];
+ return Constants.Endpoints.CDN(this.client.options.http.host).Asset(`${Constants.DefaultAvatars[avatar]}.png`);
+ }
+
+ /**
+ * A link to the user's avatar if they have one. Otherwise a link to their default avatar will be returned
+ * @type {string}
+ * @readonly
+ */
+ get displayAvatarURL() {
+ return this.avatarURL || this.defaultAvatarURL;
+ }
+
+ /**
+ * The Discord "tag" for this user
+ * @type {string}
+ * @readonly
+ */
+ get tag() {
+ return `${this.username}#${this.discriminator}`;
+ }
+
+ /**
+ * The note that is set for the user
+ * This is only available when using a user account.
+ * @type {?string}
+ * @readonly
+ */
+ get note() {
+ return this.client.user.notes.get(this.id) || null;
+ }
+
+ /**
+ * Check whether the user is typing in a channel.
+ * @param {ChannelResolvable} channel The channel to check in
+ * @returns {boolean}
+ */
+ typingIn(channel) {
+ channel = this.client.resolver.resolveChannel(channel);
+ return channel._typing.has(this.id);
+ }
+
+ /**
+ * Get the time that the user started typing.
+ * @param {ChannelResolvable} channel The channel to get the time in
+ * @returns {?Date}
+ */
+ typingSinceIn(channel) {
+ channel = this.client.resolver.resolveChannel(channel);
+ return channel._typing.has(this.id) ? new Date(channel._typing.get(this.id).since) : null;
+ }
+
+ /**
+ * Get the amount of time the user has been typing in a channel for (in milliseconds), or -1 if they're not typing.
+ * @param {ChannelResolvable} channel The channel to get the time in
+ * @returns {number}
+ */
+ typingDurationIn(channel) {
+ channel = this.client.resolver.resolveChannel(channel);
+ return channel._typing.has(this.id) ? channel._typing.get(this.id).elapsedTime : -1;
+ }
+
+ /**
+ * The DM between the client's user and this user
+ * @type {?DMChannel}
+ * @readonly
+ */
+ get dmChannel() {
+ return this.client.channels.filter(c => c.type === 'dm').find(c => c.recipient.id === this.id);
+ }
+
+ /**
+ * Creates a DM channel between the client and the user.
+ * @returns {Promise}
+ */
+ createDM() {
+ return this.client.rest.methods.createDM(this);
+ }
+
+ /**
+ * Deletes a DM channel (if one exists) between the client and the user. Resolves with the channel if successful.
+ * @returns {Promise}
+ */
+ deleteDM() {
return this.client.rest.methods.deleteChannel(this);
}
+
+ /**
+ * Sends a friend request to the user.
+ * This is only available when using a user account.
+ * @returns {Promise}
+ */
+ addFriend() {
+ return this.client.rest.methods.addFriend(this);
+ }
+
+ /**
+ * Removes the user from your friends.
+ * This is only available when using a user account.
+ * @returns {Promise}
+ */
+ removeFriend() {
+ return this.client.rest.methods.removeFriend(this);
+ }
+
+ /**
+ * Blocks the user.
+ * This is only available when using a user account.
+ * @returns {Promise}
+ */
+ block() {
+ return this.client.rest.methods.blockUser(this);
+ }
+
+ /**
+ * Unblocks the user.
+ * This is only available when using a user account.
+ * @returns {Promise}
+ */
+ unblock() {
+ return this.client.rest.methods.unblockUser(this);
+ }
+
+ /**
+ * Get the profile of the user.
+ * This is only available when using a user account.
+ * @returns {Promise}
+ */
+ fetchProfile() {
+ return this.client.rest.methods.fetchUserProfile(this);
+ }
+
+ /**
+ * Sets a note for the user.
+ * This is only available when using a user account.
+ * @param {string} note The note to set for the user
+ * @returns {Promise}
+ */
+ setNote(note) {
+ return this.client.rest.methods.setNote(this, note);
+ }
+
+ /**
+ * Checks if the user is equal to another. It compares ID, username, discriminator, avatar, and bot flags.
+ * It is recommended to compare equality by using `user.id === user2.id` unless you want to compare all properties.
+ * @param {User} user User to compare with
+ * @returns {boolean}
+ */
+ equals(user) {
+ let equal = user &&
+ this.id === user.id &&
+ this.username === user.username &&
+ this.discriminator === user.discriminator &&
+ this.avatar === user.avatar &&
+ this.bot === Boolean(user.bot);
+
+ return equal;
+ }
+
+ /**
+ * When concatenated with a string, this automatically concatenates the user's mention instead of the User object.
+ * @returns {string}
+ * @example
+ * // logs: Hello from <@123456789>!
+ * console.log(`Hello from ${user}!`);
+ */
+ toString() {
+ return `<@${this.id}>`;
+ }
+
+ // These are here only for documentation purposes - they are implemented by TextBasedChannel
+ /* eslint-disable no-empty-function */
+ send() {}
+ sendMessage() {}
+ sendEmbed() {}
+ sendFile() {}
+ sendCode() {}
}
-module.exports = Channel;
+TextBasedChannel.applyToClass(User);
+
+module.exports = User;
/***/ }),
-/* 15 */
+/* 14 */
/***/ (function(module, exports, __webpack_require__) {
-const Snowflake = __webpack_require__(5);
-const Permissions = __webpack_require__(8);
-const util = __webpack_require__(22);
+const Snowflake = __webpack_require__(8);
+const Permissions = __webpack_require__(11);
+const util = __webpack_require__(20);
/**
* Represents a role on Discord.
@@ -4657,85 +4932,146 @@ Role.prototype.hasPermissions = util
module.exports = Role;
+/***/ }),
+/* 15 */
+/***/ (function(module, exports) {
+
+/**
+ * Represents a user's presence.
+ */
+class Presence {
+ constructor(data = {}) {
+ /**
+ * The status of the presence:
+ *
+ * * **`online`** - user is online
+ * * **`offline`** - user is offline or invisible
+ * * **`idle`** - user is AFK
+ * * **`dnd`** - user is in Do not Disturb
+ * @type {string}
+ */
+ this.status = data.status || 'offline';
+
+ /**
+ * The game that the user is playing
+ * @type {?Game}
+ */
+ this.game = data.game ? new Game(data.game) : null;
+ }
+
+ update(data) {
+ this.status = data.status || this.status;
+ this.game = data.game ? new Game(data.game) : null;
+ }
+
+ /**
+ * Whether this presence is equal to another
+ * @param {Presence} presence The presence to compare with
+ * @returns {boolean}
+ */
+ equals(presence) {
+ return this === presence || (
+ presence &&
+ this.status === presence.status &&
+ this.game ? this.game.equals(presence.game) : !presence.game
+ );
+ }
+}
+
+/**
+ * Represents a game that is part of a user's presence.
+ */
+class Game {
+ constructor(data) {
+ /**
+ * The name of the game being played
+ * @type {string}
+ */
+ this.name = data.name;
+
+ /**
+ * The type of the game status
+ * @type {number}
+ */
+ this.type = data.type;
+
+ /**
+ * If the game is being streamed, a link to the stream
+ * @type {?string}
+ */
+ this.url = data.url || null;
+ }
+
+ /**
+ * Whether or not the game is being streamed
+ * @type {boolean}
+ * @readonly
+ */
+ get streaming() {
+ return this.type === 1;
+ }
+
+ /**
+ * Whether this game is equal to another game
+ * @param {Game} game The game to compare with
+ * @returns {boolean}
+ */
+ equals(game) {
+ return this === game || (
+ game &&
+ this.name === game.name &&
+ this.type === game.type &&
+ this.url === game.url
+ );
+ }
+}
+
+exports.Presence = Presence;
+exports.Game = Game;
+
+
/***/ }),
/* 16 */
/***/ (function(module, exports, __webpack_require__) {
-const TextBasedChannel = __webpack_require__(23);
-const Constants = __webpack_require__(0);
-const Presence = __webpack_require__(11).Presence;
-const Snowflake = __webpack_require__(5);
+const Snowflake = __webpack_require__(8);
/**
- * Represents a user on Discord.
- * @implements {TextBasedChannel}
+ * Represents any channel on Discord.
*/
-class User {
+class Channel {
constructor(client, data) {
/**
- * The client that created the instance of the the user
- * @name User#client
- * @type {}
+ * The client that instantiated the Channel
+ * @name Channel#client
+ * @type {Client}
* @readonly
*/
Object.defineProperty(this, 'client', { value: client });
+ /**
+ * 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
+ * @type {string}
+ */
+ this.type = null;
+
if (data) this.setup(data);
}
setup(data) {
/**
- * The ID of the user
+ * The unique ID of the channel
* @type {Snowflake}
*/
this.id = data.id;
-
- /**
- * The username of the user
- * @type {string}
- */
- this.username = data.username;
-
- /**
- * A discriminator based on username for the user
- * @type {string}
- */
- this.discriminator = data.discriminator;
-
- /**
- * The ID of the user's avatar
- * @type {string}
- */
- this.avatar = data.avatar;
-
- /**
- * Whether or not the user is a bot
- * @type {boolean}
- */
- this.bot = Boolean(data.bot);
-
- /**
- * The ID of the last message sent by the user, if one was sent
- * @type {?Snowflake}
- */
- this.lastMessageID = null;
-
- /**
- * The Message object of the last message sent by the user, if one was sent
- * @type {?Message}
- */
- this.lastMessage = null;
- }
-
- patch(data) {
- for (const prop of ['id', 'username', 'discriminator', 'avatar', 'bot']) {
- if (typeof data[prop] !== 'undefined') this[prop] = data[prop];
- }
- if (data.token) this.client.token = data.token;
}
/**
- * The timestamp the user was created at
+ * The timestamp the channel was created at
* @type {number}
* @readonly
*/
@@ -4744,7 +5080,7 @@ class User {
}
/**
- * The time the user was created
+ * The time the channel was created
* @type {Date}
* @readonly
*/
@@ -4753,1548 +5089,39 @@ class User {
}
/**
- * The presence of this user
- * @type {Presence}
- * @readonly
+ * Deletes the channel.
+ * @returns {Promise}
+ * @example
+ * // Delete the channel
+ * channel.delete()
+ * .then() // Success
+ * .catch(console.error); // Log error
*/
- get presence() {
- if (this.client.presences.has(this.id)) return this.client.presences.get(this.id);
- for (const guild of this.client.guilds.values()) {
- if (guild.presences.has(this.id)) return guild.presences.get(this.id);
- }
- return new Presence();
- }
-
- /**
- * A link to the user's avatar
- * @type {?string}
- * @readonly
- */
- get avatarURL() {
- if (!this.avatar) return null;
- return Constants.Endpoints.User(this).Avatar(this.client.options.http.cdn, this.avatar);
- }
-
- /**
- * A link to the user's default avatar
- * @type {string}
- * @readonly
- */
- get defaultAvatarURL() {
- const avatars = Object.keys(Constants.DefaultAvatars);
- const avatar = avatars[this.discriminator % avatars.length];
- return Constants.Endpoints.CDN(this.client.options.http.host).Asset(`${Constants.DefaultAvatars[avatar]}.png`);
- }
-
- /**
- * A link to the user's avatar if they have one. Otherwise a link to their default avatar will be returned
- * @type {string}
- * @readonly
- */
- get displayAvatarURL() {
- return this.avatarURL || this.defaultAvatarURL;
- }
-
- /**
- * The Discord "tag" for this user
- * @type {string}
- * @readonly
- */
- get tag() {
- return `${this.username}#${this.discriminator}`;
- }
-
- /**
- * The note that is set for the user
- * This is only available when using a user account.
- * @type {?string}
- * @readonly
- */
- get note() {
- return this.client.user.notes.get(this.id) || null;
- }
-
- /**
- * Check whether the user is typing in a channel.
- * @param {ChannelResolvable} channel The channel to check in
- * @returns {boolean}
- */
- typingIn(channel) {
- channel = this.client.resolver.resolveChannel(channel);
- return channel._typing.has(this.id);
- }
-
- /**
- * Get the time that the user started typing.
- * @param {ChannelResolvable} channel The channel to get the time in
- * @returns {?Date}
- */
- typingSinceIn(channel) {
- channel = this.client.resolver.resolveChannel(channel);
- return channel._typing.has(this.id) ? new Date(channel._typing.get(this.id).since) : null;
- }
-
- /**
- * Get the amount of time the user has been typing in a channel for (in milliseconds), or -1 if they're not typing.
- * @param {ChannelResolvable} channel The channel to get the time in
- * @returns {number}
- */
- typingDurationIn(channel) {
- channel = this.client.resolver.resolveChannel(channel);
- return channel._typing.has(this.id) ? channel._typing.get(this.id).elapsedTime : -1;
- }
-
- /**
- * The DM between the client's user and this user
- * @type {?DMChannel}
- * @readonly
- */
- get dmChannel() {
- return this.client.channels.filter(c => c.type === 'dm').find(c => c.recipient.id === this.id);
- }
-
- /**
- * Creates a DM channel between the client and the user.
- * @returns {Promise}
- */
- createDM() {
- return this.client.rest.methods.createDM(this);
- }
-
- /**
- * Deletes a DM channel (if one exists) between the client and the user. Resolves with the channel if successful.
- * @returns {Promise}
- */
- deleteDM() {
+ delete() {
return this.client.rest.methods.deleteChannel(this);
}
-
- /**
- * Sends a friend request to the user.
- * This is only available when using a user account.
- * @returns {Promise}
- */
- addFriend() {
- return this.client.rest.methods.addFriend(this);
- }
-
- /**
- * Removes the user from your friends.
- * This is only available when using a user account.
- * @returns {Promise}
- */
- removeFriend() {
- return this.client.rest.methods.removeFriend(this);
- }
-
- /**
- * Blocks the user.
- * This is only available when using a user account.
- * @returns {Promise}
- */
- block() {
- return this.client.rest.methods.blockUser(this);
- }
-
- /**
- * Unblocks the user.
- * This is only available when using a user account.
- * @returns {Promise}
- */
- unblock() {
- return this.client.rest.methods.unblockUser(this);
- }
-
- /**
- * Get the profile of the user.
- * This is only available when using a user account.
- * @returns {Promise}
- */
- fetchProfile() {
- return this.client.rest.methods.fetchUserProfile(this);
- }
-
- /**
- * Sets a note for the user.
- * This is only available when using a user account.
- * @param {string} note The note to set for the user
- * @returns {Promise}
- */
- setNote(note) {
- return this.client.rest.methods.setNote(this, note);
- }
-
- /**
- * Checks if the user is equal to another. It compares ID, username, discriminator, avatar, and bot flags.
- * It is recommended to compare equality by using `user.id === user2.id` unless you want to compare all properties.
- * @param {User} user User to compare with
- * @returns {boolean}
- */
- equals(user) {
- let equal = user &&
- this.id === user.id &&
- this.username === user.username &&
- this.discriminator === user.discriminator &&
- this.avatar === user.avatar &&
- this.bot === Boolean(user.bot);
-
- return equal;
- }
-
- /**
- * When concatenated with a string, this automatically concatenates the user's mention instead of the User object.
- * @returns {string}
- * @example
- * // logs: Hello from <@123456789>!
- * console.log(`Hello from ${user}!`);
- */
- toString() {
- return `<@${this.id}>`;
- }
-
- // These are here only for documentation purposes - they are implemented by TextBasedChannel
- /* eslint-disable no-empty-function */
- send() {}
- sendMessage() {}
- sendEmbed() {}
- sendFile() {}
- sendCode() {}
}
-TextBasedChannel.applyToClass(User);
-
-module.exports = User;
+module.exports = Channel;
/***/ }),
/* 17 */
/***/ (function(module, exports, __webpack_require__) {
-const Constants = __webpack_require__(0);
-const Collection = __webpack_require__(3);
-const Snowflake = __webpack_require__(5);
-
-/**
- * Represents a custom emoji.
- */
-class Emoji {
- constructor(guild, data) {
- /**
- * The client that instantiated this object
- * @name Emoji#client
- * @type {Client}
- * @readonly
- */
- Object.defineProperty(this, 'client', { value: guild.client });
-
- /**
- * The guild this emoji is part of
- * @type {Guild}
- */
- this.guild = guild;
-
- this.setup(data);
- }
-
- setup(data) {
- /**
- * The ID of the emoji
- * @type {Snowflake}
- */
- this.id = data.id;
-
- /**
- * The name of the emoji
- * @type {string}
- */
- this.name = data.name;
-
- /**
- * Whether or not this emoji requires colons surrounding it
- * @type {boolean}
- */
- this.requiresColons = data.require_colons;
-
- /**
- * Whether this emoji is managed by an external service
- * @type {boolean}
- */
- this.managed = data.managed;
-
- this._roles = data.roles;
- }
-
- /**
- * The timestamp the emoji was created at
- * @type {number}
- * @readonly
- */
- get createdTimestamp() {
- return Snowflake.deconstruct(this.id).timestamp;
- }
-
- /**
- * The time the emoji was created
- * @type {Date}
- * @readonly
- */
- get createdAt() {
- return new Date(this.createdTimestamp);
- }
-
- /**
- * A collection of roles this emoji is active for (empty if all), mapped by role ID
- * @type {Collection}
- * @readonly
- */
- get roles() {
- const roles = new Collection();
- for (const role of this._roles) {
- if (this.guild.roles.has(role)) roles.set(role, this.guild.roles.get(role));
- }
- return roles;
- }
-
- /**
- * The URL to the emoji file
- * @type {string}
- * @readonly
- */
- get url() {
- return Constants.Endpoints.CDN(this.client.options.http.cdn).Emoji(this.id);
- }
-
- /**
- * The identifier of this emoji, used for message reactions
- * @type {string}
- * @readonly
- */
- get identifier() {
- if (this.id) return `${this.name}:${this.id}`;
- return encodeURIComponent(this.name);
- }
-
- /**
- * Data for editing an emoji.
- * @typedef {Object} EmojiEditData
- * @property {string} [name] The name of the emoji
- * @property {Collection|Array} [roles] Roles to restrict emoji to
- */
-
- /**
- * Edits the emoji.
- * @param {EmojiEditData} data The new data for the emoji
- * @returns {Promise}
- * @example
- * // Edit a emoji
- * emoji.edit({name: 'newemoji'})
- * .then(e => console.log(`Edited emoji ${e}`))
- * .catch(console.error);
- */
- edit(data) {
- return this.client.rest.methods.updateEmoji(this, data);
- }
-
- /**
- * Set the name of the emoji.
- * @param {string} name The new name for the emoji
- * @returns {Promise}
- */
- setName(name) {
- return this.edit({ name });
- }
-
- /**
- * Add a role to the list of roles that can use this emoji.
- * @param {Role} role The role to add
- * @returns {Promise}
- */
- addRestrictedRole(role) {
- return this.addRestrictedRoles([role]);
- }
-
- /**
- * Add multiple roles to the list of roles that can use this emoji.
- * @param {Role[]} roles Roles to add
- * @returns {Promise}
- */
- addRestrictedRoles(roles) {
- const newRoles = new Collection(this.roles);
- for (const role of roles) {
- if (this.guild.roles.has(role.id)) newRoles.set(role.id, role);
- }
- return this.edit({ roles: newRoles });
- }
-
- /**
- * Remove a role from the list of roles that can use this emoji.
- * @param {Role} role The role to remove
- * @returns {Promise}
- */
- removeRestrictedRole(role) {
- return this.removeRestrictedRoles([role]);
- }
-
- /**
- * Remove multiple roles from the list of roles that can use this emoji.
- * @param {Role[]} roles Roles to remove
- * @returns {Promise}
- */
- removeRestrictedRoles(roles) {
- const newRoles = new Collection(this.roles);
- for (const role of roles) {
- if (newRoles.has(role.id)) newRoles.delete(role.id);
- }
- return this.edit({ roles: newRoles });
- }
-
- /**
- * When concatenated with a string, this automatically returns the emoji mention rather than the object.
- * @returns {string}
- * @example
- * // Send an emoji:
- * const emoji = guild.emojis.first();
- * msg.reply(`Hello! ${emoji}`);
- */
- toString() {
- return this.requiresColons ? `<:${this.name}:${this.id}>` : this.name;
- }
-
- /**
- * Whether this emoji is the same as another one.
- * @param {Emoji|Object} other The emoji to compare it to
- * @returns {boolean} Whether the emoji is equal to the given emoji or not
- */
- equals(other) {
- if (other instanceof Emoji) {
- return (
- other.id === this.id &&
- other.name === this.name &&
- other.managed === this.managed &&
- other.requiresColons === this.requiresColons
- );
- } else {
- return (
- other.id === this.id &&
- other.name === this.name
- );
- }
- }
-}
-
-module.exports = Emoji;
+exports = module.exports = __webpack_require__(44);
+exports.Stream = exports;
+exports.Readable = exports;
+exports.Writable = __webpack_require__(33);
+exports.Duplex = __webpack_require__(12);
+exports.Transform = __webpack_require__(48);
+exports.PassThrough = __webpack_require__(82);
/***/ }),
/* 18 */
/***/ (function(module, exports, __webpack_require__) {
-const TextBasedChannel = __webpack_require__(23);
-const Role = __webpack_require__(15);
-const Permissions = __webpack_require__(8);
-const Collection = __webpack_require__(3);
-const Presence = __webpack_require__(11).Presence;
-const util = __webpack_require__(22);
-
-/**
- * Represents a member of a guild on Discord.
- * @implements {TextBasedChannel}
- */
-class GuildMember {
- constructor(guild, data) {
- /**
- * The client that instantiated this GuildMember
- * @name GuildMember#client
- * @type {Client}
- * @readonly
- */
- Object.defineProperty(this, 'client', { value: guild.client });
-
- /**
- * The guild that this member is part of
- * @type {Guild}
- */
- this.guild = guild;
-
- /**
- * The user that this guild member instance Represents
- * @type {User}
- */
- this.user = {};
-
- this._roles = [];
- if (data) this.setup(data);
-
- /**
- * The ID of the last message sent by the member in their guild, if one was sent
- * @type {?Snowflake}
- */
- this.lastMessageID = null;
-
- /**
- * The Message object of the last message sent by the member in their guild, if one was sent
- * @type {?Message}
- */
- this.lastMessage = null;
- }
-
- setup(data) {
- /**
- * Whether this member is deafened server-wide
- * @type {boolean}
- */
- this.serverDeaf = data.deaf;
-
- /**
- * Whether this member is muted server-wide
- * @type {boolean}
- */
- this.serverMute = data.mute;
-
- /**
- * Whether this member is self-muted
- * @type {boolean}
- */
- this.selfMute = data.self_mute;
-
- /**
- * Whether this member is self-deafened
- * @type {boolean}
- */
- this.selfDeaf = data.self_deaf;
-
- /**
- * The voice session ID of this member, if any
- * @type {?Snowflake}
- */
- this.voiceSessionID = data.session_id;
-
- /**
- * The voice channel ID of this member, if any
- * @type {?Snowflake}
- */
- this.voiceChannelID = data.channel_id;
-
- /**
- * Whether this member is speaking
- * @type {boolean}
- */
- this.speaking = false;
-
- /**
- * The nickname of this guild member, if they have one
- * @type {?string}
- */
- this.nickname = data.nick || null;
-
- /**
- * The timestamp the member joined the guild at
- * @type {number}
- */
- this.joinedTimestamp = new Date(data.joined_at).getTime();
-
- this.user = data.user;
- this._roles = data.roles;
- }
-
- /**
- * The time the member joined the guild
- * @type {Date}
- * @readonly
- */
- get joinedAt() {
- return new Date(this.joinedTimestamp);
- }
-
- /**
- * The presence of this guild member
- * @type {Presence}
- * @readonly
- */
- get presence() {
- return this.frozenPresence || this.guild.presences.get(this.id) || new Presence();
- }
-
- /**
- * A list of roles that are applied to this GuildMember, mapped by the role ID
- * @type {Collection}
- * @readonly
- */
- get roles() {
- const list = new Collection();
- const everyoneRole = this.guild.roles.get(this.guild.id);
-
- if (everyoneRole) list.set(everyoneRole.id, everyoneRole);
-
- for (const roleID of this._roles) {
- const role = this.guild.roles.get(roleID);
- if (role) list.set(role.id, role);
- }
-
- return list;
- }
-
- /**
- * The role of the member with the highest position
- * @type {Role}
- * @readonly
- */
- get highestRole() {
- return this.roles.reduce((prev, role) => !prev || role.comparePositionTo(prev) > 0 ? role : prev);
- }
-
- /**
- * The role of the member used to set their color
- * @type {?Role}
- * @readonly
- */
- get colorRole() {
- const coloredRoles = this.roles.filter(role => role.color);
- if (!coloredRoles.size) return null;
- return coloredRoles.reduce((prev, role) => !prev || role.comparePositionTo(prev) > 0 ? role : prev);
- }
-
- /**
- * The displayed color of the member in base 10
- * @type {number}
- * @readonly
- */
- get displayColor() {
- const role = this.colorRole;
- return (role && role.color) || 0;
- }
-
- /**
- * The displayed color of the member in hexadecimal
- * @type {string}
- * @readonly
- */
- get displayHexColor() {
- const role = this.colorRole;
- return (role && role.hexColor) || '#000000';
- }
-
- /**
- * The role of the member used to hoist them in a separate category in the users list
- * @type {?Role}
- * @readonly
- */
- get hoistRole() {
- const hoistedRoles = this.roles.filter(role => role.hoist);
- if (!hoistedRoles.size) return null;
- return hoistedRoles.reduce((prev, role) => !prev || role.comparePositionTo(prev) > 0 ? role : prev);
- }
-
- /**
- * Whether this member is muted in any way
- * @type {boolean}
- * @readonly
- */
- get mute() {
- return this.selfMute || this.serverMute;
- }
-
- /**
- * Whether this member is deafened in any way
- * @type {boolean}
- * @readonly
- */
- get deaf() {
- return this.selfDeaf || this.serverDeaf;
- }
-
- /**
- * The voice channel this member is in, if any
- * @type {?VoiceChannel}
- * @readonly
- */
- get voiceChannel() {
- return this.guild.channels.get(this.voiceChannelID);
- }
-
- /**
- * The ID of this user
- * @type {Snowflake}
- * @readonly
- */
- get id() {
- return this.user.id;
- }
-
- /**
- * The nickname of the member, or their username if they don't have one
- * @type {string}
- * @readonly
- */
- get displayName() {
- return this.nickname || this.user.username;
- }
-
- /**
- * The overall set of permissions for the guild member, taking only roles into account
- * @type {Permissions}
- * @readonly
- */
- get permissions() {
- if (this.user.id === this.guild.ownerID) return new Permissions(this, Permissions.ALL);
-
- let permissions = 0;
- const roles = this.roles;
- for (const role of roles.values()) permissions |= role.permissions;
-
- return new Permissions(this, permissions);
- }
-
- /**
- * Whether the member is kickable by the client user
- * @type {boolean}
- * @readonly
- */
- get kickable() {
- if (this.user.id === this.guild.ownerID) return false;
- if (this.user.id === this.client.user.id) return false;
- const clientMember = this.guild.member(this.client.user);
- if (!clientMember.permissions.has(Permissions.FLAGS.KICK_MEMBERS)) return false;
- return clientMember.highestRole.comparePositionTo(this.highestRole) > 0;
- }
-
- /**
- * Whether the member is bannable by the client user
- * @type {boolean}
- * @readonly
- */
- get bannable() {
- if (this.user.id === this.guild.ownerID) return false;
- if (this.user.id === this.client.user.id) return false;
- const clientMember = this.guild.member(this.client.user);
- if (!clientMember.permissions.has(Permissions.FLAGS.BAN_MEMBERS)) return false;
- return clientMember.highestRole.comparePositionTo(this.highestRole) > 0;
- }
-
- /**
- * Returns `channel.permissionsFor(guildMember)`. Returns permissions for a member in a guild channel,
- * taking into account roles and permission overwrites.
- * @param {ChannelResolvable} channel The guild channel to use as context
- * @returns {?Permissions}
- */
- permissionsIn(channel) {
- channel = this.client.resolver.resolveChannel(channel);
- if (!channel || !channel.guild) throw new Error('Could not resolve channel to a guild channel.');
- return channel.permissionsFor(this);
- }
-
- /**
- * Checks if any of the member's roles have a permission.
- * @param {PermissionResolvable|PermissionResolvable[]} permission Permission(s) to check for
- * @param {boolean} [explicit=false] Whether to require the role to explicitly have the exact permission
- * **(deprecated)**
- * @param {boolean} [checkAdmin] Whether to allow the administrator permission to override
- * (takes priority over `explicit`)
- * @param {boolean} [checkOwner] Whether to allow being the guild's owner to override
- * (takes priority over `explicit`)
- * @returns {boolean}
- */
- hasPermission(permission, explicit = false, checkAdmin, checkOwner) {
- if (typeof checkAdmin === 'undefined') checkAdmin = !explicit;
- if (typeof checkOwner === 'undefined') checkOwner = !explicit;
- if (checkOwner && this.user.id === this.guild.ownerID) return true;
- return this.roles.some(r => r.hasPermission(permission, undefined, checkAdmin));
- }
-
- /**
- * Checks whether the roles of the member allows them to perform specific actions.
- * @param {PermissionResolvable[]} permissions The permissions to check for
- * @param {boolean} [explicit=false] Whether to require the member to explicitly have the exact permissions
- * @returns {boolean}
- * @deprecated
- */
- hasPermissions(permissions, explicit = false) {
- if (!explicit && this.user.id === this.guild.ownerID) return true;
- return this.hasPermission(permissions, explicit);
- }
-
- /**
- * Checks whether the roles of the member allows them to perform specific actions, and lists any missing permissions.
- * @param {PermissionResolvable[]} permissions The permissions to check for
- * @param {boolean} [explicit=false] Whether to require the member to explicitly have the exact permissions
- * @returns {PermissionResolvable[]}
- */
- missingPermissions(permissions, explicit = false) {
- return permissions.missing(permissions, explicit);
- }
-
- /**
- * The data for editing a guild member.
- * @typedef {Object} GuildMemberEditData
- * @property {string} [nick] The nickname to set for the member
- * @property {Collection|Role[]|Snowflake[]} [roles] The roles or role IDs to apply
- * @property {boolean} [mute] Whether or not the member should be muted
- * @property {boolean} [deaf] Whether or not the member should be deafened
- * @property {ChannelResolvable} [channel] Channel to move member to (if they are connected to voice)
- */
-
- /**
- * Edit a guild member.
- * @param {GuildMemberEditData} data The data to edit the member with
- * @returns {Promise}
- */
- edit(data) {
- return this.client.rest.methods.updateGuildMember(this, data);
- }
-
- /**
- * Mute/unmute a user.
- * @param {boolean} mute Whether or not the member should be muted
- * @returns {Promise}
- */
- setMute(mute) {
- return this.edit({ mute });
- }
-
- /**
- * Deafen/undeafen a user.
- * @param {boolean} deaf Whether or not the member should be deafened
- * @returns {Promise}
- */
- setDeaf(deaf) {
- return this.edit({ deaf });
- }
-
- /**
- * Moves the guild member to the given channel.
- * @param {ChannelResolvable} channel The channel to move the member to
- * @returns {Promise}
- */
- setVoiceChannel(channel) {
- return this.edit({ channel });
- }
-
- /**
- * Sets the roles applied to the member.
- * @param {Collection|Role[]|Snowflake[]} roles The roles or role IDs to apply
- * @returns {Promise}
- */
- setRoles(roles) {
- return this.edit({ roles });
- }
-
- /**
- * Adds a single role to the member.
- * @param {Role|Snowflake} role The role or ID of the role to add
- * @returns {Promise}
- */
- addRole(role) {
- if (!(role instanceof Role)) role = this.guild.roles.get(role);
- if (!role) return Promise.reject(new TypeError('Supplied parameter was neither a Role nor a Snowflake.'));
- return this.client.rest.methods.addMemberRole(this, role);
- }
-
- /**
- * Adds multiple roles to the member.
- * @param {Collection|Role[]|Snowflake[]} roles The roles or role IDs to add
- * @returns {Promise}
- */
- addRoles(roles) {
- let allRoles;
- if (roles instanceof Collection) {
- allRoles = this._roles.slice();
- for (const role of roles.values()) allRoles.push(role.id);
- } else {
- allRoles = this._roles.concat(roles);
- }
- return this.edit({ roles: allRoles });
- }
-
- /**
- * Removes a single role from the member.
- * @param {Role|Snowflake} role The role or ID of the role to remove
- * @returns {Promise}
- */
- removeRole(role) {
- if (!(role instanceof Role)) role = this.guild.roles.get(role);
- if (!role) return Promise.reject(new TypeError('Supplied parameter was neither a Role nor a Snowflake.'));
- return this.client.rest.methods.removeMemberRole(this, role);
- }
-
- /**
- * Removes multiple roles from the member.
- * @param {Collection|Role[]|Snowflake[]} roles The roles or role IDs to remove
- * @returns {Promise}
- */
- removeRoles(roles) {
- const allRoles = this._roles.slice();
- if (roles instanceof Collection) {
- for (const role of roles.values()) {
- const index = allRoles.indexOf(role.id);
- if (index >= 0) allRoles.splice(index, 1);
- }
- } else {
- for (const role of roles) {
- const index = allRoles.indexOf(role instanceof Role ? role.id : role);
- if (index >= 0) allRoles.splice(index, 1);
- }
- }
- return this.edit({ roles: allRoles });
- }
-
- /**
- * Set the nickname for the guild member.
- * @param {string} nick The nickname for the guild member
- * @returns {Promise}
- */
- setNickname(nick) {
- return this.edit({ nick });
- }
-
- /**
- * Creates a DM channel between the client and the member.
- * @returns {Promise}
- */
- createDM() {
- return this.user.createDM();
- }
-
- /**
- * Deletes any DMs with this guild member.
- * @returns {Promise}
- */
- deleteDM() {
- return this.user.deleteDM();
- }
-
- /**
- * Kick this member from the guild.
- * @param {string} [reason] Reason for kicking user
- * @returns {Promise}
- */
- kick(reason) {
- return this.client.rest.methods.kickGuildMember(this.guild, this, reason);
- }
-
- /**
- * Ban this guild member
- * @param {Object|number|string} [options] Ban options. If a number, the number of days to delete messages for, if a
- * string, the ban reason. Supplying an object allows you to do both.
- * @param {number} [options.days=0] Number of days of messages to delete
- * @param {string} [options.reason] Reason for banning
- * @returns {Promise}
- * @example
- * // ban a guild member
- * guildMember.ban(7);
- */
- ban(options) {
- return this.guild.ban(this, options);
- }
-
- /**
- * When concatenated with a string, this automatically concatenates the user's mention instead of the Member object.
- * @returns {string}
- * @example
- * // Logs: Hello from <@123456789>!
- * console.log(`Hello from ${member}!`);
- */
- toString() {
- return `<@${this.nickname ? '!' : ''}${this.user.id}>`;
- }
-
- // These are here only for documentation purposes - they are implemented by TextBasedChannel
- /* eslint-disable no-empty-function */
- send() {}
- sendMessage() {}
- sendEmbed() {}
- sendFile() {}
- sendCode() {}
-}
-
-TextBasedChannel.applyToClass(GuildMember);
-
-GuildMember.prototype.hasPermissions = util.deprecate(GuildMember.prototype.hasPermissions,
- 'GuildMember#hasPermissions is deprecated - use GuildMember#hasPermission, it now takes an array');
-
-module.exports = GuildMember;
-
-
-/***/ }),
-/* 19 */
-/***/ (function(module, exports, __webpack_require__) {
-
-const Mentions = __webpack_require__(50);
-const Attachment = __webpack_require__(47);
-const Embed = __webpack_require__(49);
-const MessageReaction = __webpack_require__(51);
-const ReactionCollector = __webpack_require__(55);
-const Util = __webpack_require__(4);
-const Collection = __webpack_require__(3);
-const Constants = __webpack_require__(0);
-const Permissions = __webpack_require__(8);
-let GuildMember;
-
-/**
- * Represents a message on Discord.
- */
-class Message {
- constructor(channel, data, client) {
- /**
- * The client that instantiated the Message
- * @name Message#client
- * @type {Client}
- * @readonly
- */
- Object.defineProperty(this, 'client', { value: client });
-
- /**
- * The channel that the message was sent in
- * @type {TextChannel|DMChannel|GroupDMChannel}
- */
- this.channel = channel;
-
- if (data) this.setup(data);
- }
-
- setup(data) { // eslint-disable-line complexity
- /**
- * The ID of the message
- * @type {Snowflake}
- */
- this.id = data.id;
-
- /**
- * The type of the message
- * @type {string}
- */
- this.type = Constants.MessageTypes[data.type];
-
- /**
- * The content of the message
- * @type {string}
- */
- this.content = data.content;
-
- /**
- * The author of the message
- * @type {User}
- */
- this.author = this.client.dataManager.newUser(data.author);
-
- /**
- * Represents the author of the message as a guild member. Only available if the message comes from a guild
- * where the author is still a member.
- * @type {?GuildMember}
- */
- this.member = this.guild ? this.guild.member(this.author) || null : null;
-
- /**
- * Whether or not this message is pinned
- * @type {boolean}
- */
- this.pinned = data.pinned;
-
- /**
- * Whether or not the message was Text-To-Speech
- * @type {boolean}
- */
- this.tts = data.tts;
-
- /**
- * A random number or string used for checking message delivery
- * @type {string}
- */
- this.nonce = data.nonce;
-
- /**
- * Whether or not this message was sent by Discord, not actually a user (e.g. pin notifications)
- * @type {boolean}
- */
- this.system = data.type === 6;
-
- /**
- * A list of embeds in the message - e.g. YouTube Player
- * @type {MessageEmbed[]}
- */
- this.embeds = data.embeds.map(e => new Embed(this, e));
-
- /**
- * A collection of attachments in the message - e.g. Pictures - mapped by their ID
- * @type {Collection}
- */
- this.attachments = new Collection();
- for (const attachment of data.attachments) this.attachments.set(attachment.id, new Attachment(this, attachment));
-
- /**
- * The timestamp the message was sent at
- * @type {number}
- */
- this.createdTimestamp = new Date(data.timestamp).getTime();
-
- /**
- * The timestamp the message was last edited at (if applicable)
- * @type {?number}
- */
- this.editedTimestamp = data.edited_timestamp ? new Date(data.edited_timestamp).getTime() : null;
-
- /**
- * A collection of reactions to this message, mapped by the reaction ID
- * @type {Collection}
- */
- this.reactions = new Collection();
- if (data.reactions && data.reactions.length > 0) {
- for (const reaction of data.reactions) {
- const id = reaction.emoji.id ? `${reaction.emoji.name}:${reaction.emoji.id}` : reaction.emoji.name;
- this.reactions.set(id, new MessageReaction(this, reaction.emoji, reaction.count, reaction.me));
- }
- }
-
- /**
- * All valid mentions that the message contains
- * @type {MessageMentions}
- */
- this.mentions = new Mentions(this, data.mentions, data.mention_roles, data.mention_everyone);
-
- /**
- * ID of the webhook that sent the message, if applicable
- * @type {?Snowflake}
- */
- this.webhookID = data.webhook_id || null;
-
- /**
- * Whether this message is a hit in a search
- * @type {?boolean}
- */
- this.hit = typeof data.hit === 'boolean' ? data.hit : null;
-
- /**
- * The previous versions of the message, sorted with the most recent first
- * @type {Message[]}
- * @private
- */
- this._edits = [];
- }
-
- /**
- * Updates the message.
- * @param {Object} data Raw Discord message update data
- * @private
- */
- patch(data) {
- const clone = Util.cloneObject(this);
- this._edits.unshift(clone);
-
- this.editedTimestamp = new Date(data.edited_timestamp).getTime();
- if ('content' in data) this.content = data.content;
- if ('pinned' in data) this.pinned = data.pinned;
- if ('tts' in data) this.tts = data.tts;
- if ('embeds' in data) this.embeds = data.embeds.map(e => new Embed(this, e));
- else this.embeds = this.embeds.slice();
-
- if ('attachments' in data) {
- this.attachments = new Collection();
- for (const attachment of data.attachments) this.attachments.set(attachment.id, new Attachment(this, attachment));
- } else {
- this.attachments = new Collection(this.attachments);
- }
-
- this.mentions = new Mentions(
- this,
- 'mentions' in data ? data.mentions : this.mentions.users,
- 'mentions_roles' in data ? data.mentions_roles : this.mentions.roles,
- 'mention_everyone' in data ? data.mention_everyone : this.mentions.everyone
- );
- }
-
- /**
- * The time the message was sent
- * @type {Date}
- * @readonly
- */
- get createdAt() {
- return new Date(this.createdTimestamp);
- }
-
- /**
- * The time the message was last edited at (if applicable)
- * @type {?Date}
- * @readonly
- */
- get editedAt() {
- return this.editedTimestamp ? new Date(this.editedTimestamp) : null;
- }
-
- /**
- * The guild the message was sent in (if in a guild channel)
- * @type {?Guild}
- * @readonly
- */
- get guild() {
- return this.channel.guild || null;
- }
-
- /**
- * The message contents with all mentions replaced by the equivalent text. If mentions cannot be resolved to a name,
- * the relevant mention in the message content will not be converted
- * @type {string}
- * @readonly
- */
- get cleanContent() {
- return this.content
- .replace(/@(everyone|here)/g, '@\u200b$1')
- .replace(/<@!?[0-9]+>/g, input => {
- const id = input.replace(/<|!|>|@/g, '');
- if (this.channel.type === 'dm' || this.channel.type === 'group') {
- return this.client.users.has(id) ? `@${this.client.users.get(id).username}` : input;
- }
-
- const member = this.channel.guild.members.get(id);
- if (member) {
- if (member.nickname) return `@${member.nickname}`;
- return `@${member.user.username}`;
- } else {
- const user = this.client.users.get(id);
- if (user) return `@${user.username}`;
- return input;
- }
- })
- .replace(/<#[0-9]+>/g, input => {
- const channel = this.client.channels.get(input.replace(/<|#|>/g, ''));
- if (channel) return `#${channel.name}`;
- return input;
- })
- .replace(/<@&[0-9]+>/g, input => {
- if (this.channel.type === 'dm' || this.channel.type === 'group') return input;
- const role = this.guild.roles.get(input.replace(/<|@|>|&/g, ''));
- if (role) return `@${role.name}`;
- return input;
- });
- }
-
- /**
- * Creates a reaction collector.
- * @param {CollectorFilter} filter The filter to apply
- * @param {ReactionCollectorOptions} [options={}] Options to send to the collector
- * @returns {ReactionCollector}
- * @example
- * // Create a reaction collector
- * const collector = message.createReactionCollector(
- * (reaction, user) => reaction.emoji.name === '👌' && user.id === 'someID',
- * { time: 15000 }
- * );
- * collector.on('collect', r => console.log(`Collected ${r.emoji.name}`));
- * collector.on('end', collected => console.log(`Collected ${collected.size} items`));
- */
- createReactionCollector(filter, options = {}) {
- return new ReactionCollector(this, filter, options);
- }
-
- /**
- * An object containing the same properties as CollectorOptions, but a few more:
- * @typedef {ReactionCollectorOptions} AwaitReactionsOptions
- * @property {string[]} [errors] Stop/end reasons that cause the promise to reject
- */
-
- /**
- * Similar to createCollector but in promise form. Resolves with a collection of reactions that pass the specified
- * filter.
- * @param {CollectorFilter} filter The filter function to use
- * @param {AwaitReactionsOptions} [options={}] Optional options to pass to the internal collector
- * @returns {Promise>}
- */
- awaitReactions(filter, options = {}) {
- return new Promise((resolve, reject) => {
- const collector = this.createReactionCollector(filter, options);
- collector.once('end', (reactions, reason) => {
- if (options.errors && options.errors.includes(reason)) reject(reactions);
- else resolve(reactions);
- });
- });
- }
-
- /**
- * An array of cached versions of the message, including the current version
- * Sorted from latest (first) to oldest (last)
- * @type {Message[]}
- * @readonly
- */
- get edits() {
- const copy = this._edits.slice();
- copy.unshift(this);
- return copy;
- }
-
- /**
- * Whether the message is editable by the client user
- * @type {boolean}
- * @readonly
- */
- get editable() {
- return this.author.id === this.client.user.id;
- }
-
- /**
- * Whether the message is deletable by the client user
- * @type {boolean}
- * @readonly
- */
- get deletable() {
- return this.author.id === this.client.user.id || (this.guild &&
- this.channel.permissionsFor(this.client.user).has(Permissions.FLAGS.MANAGE_MESSAGES)
- );
- }
-
- /**
- * Whether the message is pinnable by the client user
- * @type {boolean}
- * @readonly
- */
- get pinnable() {
- return !this.guild ||
- this.channel.permissionsFor(this.client.user).has(Permissions.FLAGS.MANAGE_MESSAGES);
- }
-
- /**
- * Whether or not a user, channel or role is mentioned in this message.
- * @param {GuildChannel|User|Role|string} data Either a guild channel, user or a role object, or a string representing
- * the ID of any of these
- * @returns {boolean}
- */
- isMentioned(data) {
- data = data && data.id ? data.id : data;
- return this.mentions.users.has(data) || this.mentions.channels.has(data) || this.mentions.roles.has(data);
- }
-
- /**
- * Whether or not a guild member is mentioned in this message. Takes into account
- * user mentions, role mentions, and @everyone/@here mentions.
- * @param {GuildMember|User} member The member/user to check for a mention of
- * @returns {boolean}
- */
- isMemberMentioned(member) {
- // Lazy-loading is used here to get around a circular dependency that breaks things
- if (!GuildMember) GuildMember = __webpack_require__(18);
- if (this.mentions.everyone) return true;
- if (this.mentions.users.has(member.id)) return true;
- if (member instanceof GuildMember && member.roles.some(r => this.mentions.roles.has(r.id))) return true;
- return false;
- }
-
- /**
- * Options that can be passed into editMessage.
- * @typedef {Object} MessageEditOptions
- * @property {Object} [embed] An embed to be added/edited
- * @property {string|boolean} [code] Language for optional codeblock formatting to apply
- */
-
- /**
- * Edit the content of the message.
- * @param {StringResolvable} [content] The new content for the message
- * @param {MessageEditOptions} [options] The options to provide
- * @returns {Promise}
- * @example
- * // Update the content of a message
- * message.edit('This is my new content!')
- * .then(msg => console.log(`Updated the content of a message from ${msg.author}`))
- * .catch(console.error);
- */
- edit(content, options) {
- if (!options && typeof content === 'object' && !(content instanceof Array)) {
- options = content;
- content = '';
- } else if (!options) {
- options = {};
- }
- return this.client.rest.methods.updateMessage(this, content, options);
- }
-
- /**
- * Edit the content of the message, with a code block.
- * @param {string} lang The language for the code block
- * @param {StringResolvable} content The new content for the message
- * @returns {Promise}
- * @deprecated
- */
- editCode(lang, content) {
- content = Util.escapeMarkdown(this.client.resolver.resolveString(content), true);
- return this.edit(`\`\`\`${lang || ''}\n${content}\n\`\`\``);
- }
-
- /**
- * Pins this message to the channel's pinned messages.
- * @returns {Promise}
- */
- pin() {
- return this.client.rest.methods.pinMessage(this);
- }
-
- /**
- * Unpins this message from the channel's pinned messages.
- * @returns {Promise}
- */
- unpin() {
- return this.client.rest.methods.unpinMessage(this);
- }
-
- /**
- * Add a reaction to the message.
- * @param {string|Emoji|ReactionEmoji} emoji The emoji to react with
- * @returns {Promise}
- */
- react(emoji) {
- emoji = this.client.resolver.resolveEmojiIdentifier(emoji);
- if (!emoji) throw new TypeError('Emoji must be a string or Emoji/ReactionEmoji');
-
- return this.client.rest.methods.addMessageReaction(this, emoji);
- }
-
- /**
- * Remove all reactions from a message.
- * @returns {Promise}
- */
- clearReactions() {
- return this.client.rest.methods.removeMessageReactions(this);
- }
-
- /**
- * Deletes the message.
- * @param {number} [timeout=0] How long to wait to delete the message in milliseconds
- * @returns {Promise}
- * @example
- * // Delete a message
- * message.delete()
- * .then(msg => console.log(`Deleted message from ${msg.author}`))
- * .catch(console.error);
- */
- delete(timeout = 0) {
- if (timeout <= 0) {
- return this.client.rest.methods.deleteMessage(this);
- } else {
- return new Promise(resolve => {
- this.client.setTimeout(() => {
- resolve(this.delete());
- }, timeout);
- });
- }
- }
-
- /**
- * Reply to the message.
- * @param {StringResolvable} [content] The content for the message
- * @param {MessageOptions} [options] The options to provide
- * @returns {Promise}
- * @example
- * // Reply to a message
- * message.reply('Hey, I\'m a reply!')
- * .then(msg => console.log(`Sent a reply to ${msg.author}`))
- * .catch(console.error);
- */
- reply(content, options) {
- if (!options && typeof content === 'object' && !(content instanceof Array)) {
- options = content;
- content = '';
- } else if (!options) {
- options = {};
- }
- return this.channel.send(content, Object.assign(options, { reply: this.member || this.author }));
- }
-
- /**
- * Marks the message as read.
- * This is only available when using a user account.
- * @returns {Promise}
- */
- acknowledge() {
- return this.client.rest.methods.ackMessage(this);
- }
-
- /**
- * Fetches the webhook used to create this message.
- * @returns {Promise}
- */
- fetchWebhook() {
- if (!this.webhookID) return Promise.reject(new Error('The message was not sent by a webhook.'));
- return this.client.fetchWebhook(this.webhookID);
- }
-
- /**
- * Used mainly internally. Whether two messages are identical in properties. If you want to compare messages
- * without checking all the properties, use `message.id === message2.id`, which is much more efficient. This
- * method allows you to see if there are differences in content, embeds, attachments, nonce and tts properties.
- * @param {Message} message The message to compare it to
- * @param {Object} rawData Raw data passed through the WebSocket about this message
- * @returns {boolean}
- */
- equals(message, rawData) {
- if (!message) return false;
- const embedUpdate = !message.author && !message.attachments;
- if (embedUpdate) return this.id === message.id && this.embeds.length === message.embeds.length;
-
- let equal = this.id === message.id &&
- this.author.id === message.author.id &&
- this.content === message.content &&
- this.tts === message.tts &&
- this.nonce === message.nonce &&
- this.embeds.length === message.embeds.length &&
- this.attachments.length === message.attachments.length;
-
- if (equal && rawData) {
- equal = this.mentions.everyone === message.mentions.everyone &&
- this.createdTimestamp === new Date(rawData.timestamp).getTime() &&
- this.editedTimestamp === new Date(rawData.edited_timestamp).getTime();
- }
-
- return equal;
- }
-
- /**
- * When concatenated with a string, this automatically concatenates the message's content instead of the object.
- * @returns {string}
- * @example
- * // Logs: Message: This is a message!
- * console.log(`Message: ${message}`);
- */
- toString() {
- return this.content;
- }
-
- _addReaction(emoji, user) {
- const emojiID = emoji.id ? `${emoji.name}:${emoji.id}` : encodeURIComponent(emoji.name);
- let reaction;
- if (this.reactions.has(emojiID)) {
- reaction = this.reactions.get(emojiID);
- if (!reaction.me) reaction.me = user.id === this.client.user.id;
- } else {
- reaction = new MessageReaction(this, emoji, 0, user.id === this.client.user.id);
- this.reactions.set(emojiID, reaction);
- }
- if (!reaction.users.has(user.id)) reaction.users.set(user.id, user);
- reaction.count++;
- return reaction;
- }
-
- _removeReaction(emoji, user) {
- const emojiID = emoji.id ? `${emoji.name}:${emoji.id}` : encodeURIComponent(emoji.name);
- if (this.reactions.has(emojiID)) {
- const reaction = this.reactions.get(emojiID);
- if (reaction.users.has(user.id)) {
- reaction.users.delete(user.id);
- reaction.count--;
- if (user.id === this.client.user.id) reaction.me = false;
- if (reaction.count <= 0) this.reactions.delete(emojiID);
- return reaction;
- }
- }
- return null;
- }
-
- _clearReactions() {
- this.reactions.clear();
- }
-}
-
-module.exports = Message;
-
-
-/***/ }),
-/* 20 */
-/***/ (function(module, exports, __webpack_require__) {
-
/* WEBPACK VAR INJECTION */(function(Buffer) {// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
@@ -6403,23 +5230,241 @@ function objectToString(o) {
return Object.prototype.toString.call(o);
}
-/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(6).Buffer))
+/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(5).Buffer))
/***/ }),
-/* 21 */
+/* 19 */
/***/ (function(module, exports, __webpack_require__) {
-exports = module.exports = __webpack_require__(59);
-exports.Stream = exports;
-exports.Readable = exports;
-exports.Writable = __webpack_require__(36);
-exports.Duplex = __webpack_require__(13);
-exports.Transform = __webpack_require__(60);
-exports.PassThrough = __webpack_require__(85);
+/* WEBPACK VAR INJECTION */(function(process) {// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+// resolves . and .. elements in a path array with directory names there
+// must be no slashes, empty elements, or device names (c:\) in the array
+// (so also no leading and trailing slashes - it does not distinguish
+// relative and absolute paths)
+function normalizeArray(parts, allowAboveRoot) {
+ // if the path tries to go above the root, `up` ends up > 0
+ var up = 0;
+ for (var i = parts.length - 1; i >= 0; i--) {
+ var last = parts[i];
+ if (last === '.') {
+ parts.splice(i, 1);
+ } else if (last === '..') {
+ parts.splice(i, 1);
+ up++;
+ } else if (up) {
+ parts.splice(i, 1);
+ up--;
+ }
+ }
+
+ // if the path is allowed to go above the root, restore leading ..s
+ if (allowAboveRoot) {
+ for (; up--; up) {
+ parts.unshift('..');
+ }
+ }
+
+ return parts;
+}
+
+// Split a filename into [root, dir, basename, ext], unix version
+// 'root' is just a slash, or nothing.
+var splitPathRe =
+ /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+var splitPath = function(filename) {
+ return splitPathRe.exec(filename).slice(1);
+};
+
+// path.resolve([from ...], to)
+// posix version
+exports.resolve = function() {
+ var resolvedPath = '',
+ resolvedAbsolute = false;
+
+ for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+ var path = (i >= 0) ? arguments[i] : process.cwd();
+
+ // Skip empty and invalid entries
+ if (typeof path !== 'string') {
+ throw new TypeError('Arguments to path.resolve must be strings');
+ } else if (!path) {
+ continue;
+ }
+
+ resolvedPath = path + '/' + resolvedPath;
+ resolvedAbsolute = path.charAt(0) === '/';
+ }
+
+ // At this point the path should be resolved to a full absolute path, but
+ // handle relative paths to be safe (might happen when process.cwd() fails)
+
+ // Normalize the path
+ resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) {
+ return !!p;
+ }), !resolvedAbsolute).join('/');
+
+ return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+};
+
+// path.normalize(path)
+// posix version
+exports.normalize = function(path) {
+ var isAbsolute = exports.isAbsolute(path),
+ trailingSlash = substr(path, -1) === '/';
+
+ // Normalize the path
+ path = normalizeArray(filter(path.split('/'), function(p) {
+ return !!p;
+ }), !isAbsolute).join('/');
+
+ if (!path && !isAbsolute) {
+ path = '.';
+ }
+ if (path && trailingSlash) {
+ path += '/';
+ }
+
+ return (isAbsolute ? '/' : '') + path;
+};
+
+// posix version
+exports.isAbsolute = function(path) {
+ return path.charAt(0) === '/';
+};
+
+// posix version
+exports.join = function() {
+ var paths = Array.prototype.slice.call(arguments, 0);
+ return exports.normalize(filter(paths, function(p, index) {
+ if (typeof p !== 'string') {
+ throw new TypeError('Arguments to path.join must be strings');
+ }
+ return p;
+ }).join('/'));
+};
+
+
+// path.relative(from, to)
+// posix version
+exports.relative = function(from, to) {
+ from = exports.resolve(from).substr(1);
+ to = exports.resolve(to).substr(1);
+
+ function trim(arr) {
+ var start = 0;
+ for (; start < arr.length; start++) {
+ if (arr[start] !== '') break;
+ }
+
+ var end = arr.length - 1;
+ for (; end >= 0; end--) {
+ if (arr[end] !== '') break;
+ }
+
+ if (start > end) return [];
+ return arr.slice(start, end - start + 1);
+ }
+
+ var fromParts = trim(from.split('/'));
+ var toParts = trim(to.split('/'));
+
+ var length = Math.min(fromParts.length, toParts.length);
+ var samePartsLength = length;
+ for (var i = 0; i < length; i++) {
+ if (fromParts[i] !== toParts[i]) {
+ samePartsLength = i;
+ break;
+ }
+ }
+
+ var outputParts = [];
+ for (var i = samePartsLength; i < fromParts.length; i++) {
+ outputParts.push('..');
+ }
+
+ outputParts = outputParts.concat(toParts.slice(samePartsLength));
+
+ return outputParts.join('/');
+};
+
+exports.sep = '/';
+exports.delimiter = ':';
+
+exports.dirname = function(path) {
+ var result = splitPath(path),
+ root = result[0],
+ dir = result[1];
+
+ if (!root && !dir) {
+ // No dirname whatsoever
+ return '.';
+ }
+
+ if (dir) {
+ // It has a dirname, strip trailing slash
+ dir = dir.substr(0, dir.length - 1);
+ }
+
+ return root + dir;
+};
+
+
+exports.basename = function(path, ext) {
+ var f = splitPath(path)[2];
+ // TODO: make this comparison case-insensitive on windows?
+ if (ext && f.substr(-1 * ext.length) === ext) {
+ f = f.substr(0, f.length - ext.length);
+ }
+ return f;
+};
+
+
+exports.extname = function(path) {
+ return splitPath(path)[3];
+};
+
+function filter (xs, f) {
+ if (xs.filter) return xs.filter(f);
+ var res = [];
+ for (var i = 0; i < xs.length; i++) {
+ if (f(xs[i], i, xs)) res.push(xs[i]);
+ }
+ return res;
+}
+
+// String.prototype.substr - negative index don't work in IE8
+var substr = 'ab'.substr(-1) === 'b'
+ ? function (str, start, len) { return str.substr(start, len) }
+ : function (str, start, len) {
+ if (start < 0) start = str.length + start;
+ return str.substr(start, len);
+ }
+;
+
+/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7)))
/***/ }),
-/* 22 */
+/* 20 */
/***/ (function(module, exports, __webpack_require__) {
/* WEBPACK VAR INJECTION */(function(global, process) {// Copyright Joyent, Inc. and other Node contributors.
@@ -6991,7 +6036,7 @@ exports.log = function() {
* prototype.
* @param {function} superCtor Constructor function to inherit prototype from.
*/
-exports.inherits = __webpack_require__(103);
+exports.inherits = __webpack_require__(105);
exports._extend = function(origin, add) {
// Don't do anything if add isn't an object
@@ -7009,17 +6054,17 @@ function hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
-/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(9), __webpack_require__(7)))
+/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(6), __webpack_require__(7)))
/***/ }),
-/* 23 */
+/* 21 */
/***/ (function(module, exports, __webpack_require__) {
-const path = __webpack_require__(28);
-const Message = __webpack_require__(19);
-const MessageCollector = __webpack_require__(48);
+const path = __webpack_require__(19);
+const Message = __webpack_require__(22);
+const MessageCollector = __webpack_require__(60);
const Collection = __webpack_require__(3);
-const util = __webpack_require__(22);
+const util = __webpack_require__(20);
/**
* Interface for classes that have text-channel-like features.
@@ -7521,8 +6566,1390 @@ exports.applyToClass = (structure, full = false, ignore = []) => {
};
+/***/ }),
+/* 22 */
+/***/ (function(module, exports, __webpack_require__) {
+
+const Mentions = __webpack_require__(55);
+const Attachment = __webpack_require__(56);
+const Embed = __webpack_require__(57);
+const MessageReaction = __webpack_require__(58);
+const ReactionCollector = __webpack_require__(59);
+const Util = __webpack_require__(4);
+const Collection = __webpack_require__(3);
+const Constants = __webpack_require__(0);
+const Permissions = __webpack_require__(11);
+let GuildMember;
+
+/**
+ * Represents a message on Discord.
+ */
+class Message {
+ constructor(channel, data, client) {
+ /**
+ * The client that instantiated the Message
+ * @name Message#client
+ * @type {Client}
+ * @readonly
+ */
+ Object.defineProperty(this, 'client', { value: client });
+
+ /**
+ * The channel that the message was sent in
+ * @type {TextChannel|DMChannel|GroupDMChannel}
+ */
+ this.channel = channel;
+
+ if (data) this.setup(data);
+ }
+
+ setup(data) { // eslint-disable-line complexity
+ /**
+ * The ID of the message
+ * @type {Snowflake}
+ */
+ this.id = data.id;
+
+ /**
+ * The type of the message
+ * @type {string}
+ */
+ this.type = Constants.MessageTypes[data.type];
+
+ /**
+ * The content of the message
+ * @type {string}
+ */
+ this.content = data.content;
+
+ /**
+ * The author of the message
+ * @type {User}
+ */
+ this.author = this.client.dataManager.newUser(data.author);
+
+ /**
+ * Represents the author of the message as a guild member. Only available if the message comes from a guild
+ * where the author is still a member.
+ * @type {?GuildMember}
+ */
+ this.member = this.guild ? this.guild.member(this.author) || null : null;
+
+ /**
+ * Whether or not this message is pinned
+ * @type {boolean}
+ */
+ this.pinned = data.pinned;
+
+ /**
+ * Whether or not the message was Text-To-Speech
+ * @type {boolean}
+ */
+ this.tts = data.tts;
+
+ /**
+ * A random number or string used for checking message delivery
+ * @type {string}
+ */
+ this.nonce = data.nonce;
+
+ /**
+ * Whether or not this message was sent by Discord, not actually a user (e.g. pin notifications)
+ * @type {boolean}
+ */
+ this.system = data.type === 6;
+
+ /**
+ * A list of embeds in the message - e.g. YouTube Player
+ * @type {MessageEmbed[]}
+ */
+ this.embeds = data.embeds.map(e => new Embed(this, e));
+
+ /**
+ * A collection of attachments in the message - e.g. Pictures - mapped by their ID
+ * @type {Collection}
+ */
+ this.attachments = new Collection();
+ for (const attachment of data.attachments) this.attachments.set(attachment.id, new Attachment(this, attachment));
+
+ /**
+ * The timestamp the message was sent at
+ * @type {number}
+ */
+ this.createdTimestamp = new Date(data.timestamp).getTime();
+
+ /**
+ * The timestamp the message was last edited at (if applicable)
+ * @type {?number}
+ */
+ this.editedTimestamp = data.edited_timestamp ? new Date(data.edited_timestamp).getTime() : null;
+
+ /**
+ * A collection of reactions to this message, mapped by the reaction ID
+ * @type {Collection}
+ */
+ this.reactions = new Collection();
+ if (data.reactions && data.reactions.length > 0) {
+ for (const reaction of data.reactions) {
+ const id = reaction.emoji.id ? `${reaction.emoji.name}:${reaction.emoji.id}` : reaction.emoji.name;
+ this.reactions.set(id, new MessageReaction(this, reaction.emoji, reaction.count, reaction.me));
+ }
+ }
+
+ /**
+ * All valid mentions that the message contains
+ * @type {MessageMentions}
+ */
+ this.mentions = new Mentions(this, data.mentions, data.mention_roles, data.mention_everyone);
+
+ /**
+ * ID of the webhook that sent the message, if applicable
+ * @type {?Snowflake}
+ */
+ this.webhookID = data.webhook_id || null;
+
+ /**
+ * Whether this message is a hit in a search
+ * @type {?boolean}
+ */
+ this.hit = typeof data.hit === 'boolean' ? data.hit : null;
+
+ /**
+ * The previous versions of the message, sorted with the most recent first
+ * @type {Message[]}
+ * @private
+ */
+ this._edits = [];
+ }
+
+ /**
+ * Updates the message.
+ * @param {Object} data Raw Discord message update data
+ * @private
+ */
+ patch(data) {
+ const clone = Util.cloneObject(this);
+ this._edits.unshift(clone);
+
+ this.editedTimestamp = new Date(data.edited_timestamp).getTime();
+ if ('content' in data) this.content = data.content;
+ if ('pinned' in data) this.pinned = data.pinned;
+ if ('tts' in data) this.tts = data.tts;
+ if ('embeds' in data) this.embeds = data.embeds.map(e => new Embed(this, e));
+ else this.embeds = this.embeds.slice();
+
+ if ('attachments' in data) {
+ this.attachments = new Collection();
+ for (const attachment of data.attachments) this.attachments.set(attachment.id, new Attachment(this, attachment));
+ } else {
+ this.attachments = new Collection(this.attachments);
+ }
+
+ this.mentions = new Mentions(
+ this,
+ 'mentions' in data ? data.mentions : this.mentions.users,
+ 'mentions_roles' in data ? data.mentions_roles : this.mentions.roles,
+ 'mention_everyone' in data ? data.mention_everyone : this.mentions.everyone
+ );
+ }
+
+ /**
+ * The time the message was sent
+ * @type {Date}
+ * @readonly
+ */
+ get createdAt() {
+ return new Date(this.createdTimestamp);
+ }
+
+ /**
+ * The time the message was last edited at (if applicable)
+ * @type {?Date}
+ * @readonly
+ */
+ get editedAt() {
+ return this.editedTimestamp ? new Date(this.editedTimestamp) : null;
+ }
+
+ /**
+ * The guild the message was sent in (if in a guild channel)
+ * @type {?Guild}
+ * @readonly
+ */
+ get guild() {
+ return this.channel.guild || null;
+ }
+
+ /**
+ * The message contents with all mentions replaced by the equivalent text. If mentions cannot be resolved to a name,
+ * the relevant mention in the message content will not be converted
+ * @type {string}
+ * @readonly
+ */
+ get cleanContent() {
+ return this.content
+ .replace(/@(everyone|here)/g, '@\u200b$1')
+ .replace(/<@!?[0-9]+>/g, input => {
+ const id = input.replace(/<|!|>|@/g, '');
+ if (this.channel.type === 'dm' || this.channel.type === 'group') {
+ return this.client.users.has(id) ? `@${this.client.users.get(id).username}` : input;
+ }
+
+ const member = this.channel.guild.members.get(id);
+ if (member) {
+ if (member.nickname) return `@${member.nickname}`;
+ return `@${member.user.username}`;
+ } else {
+ const user = this.client.users.get(id);
+ if (user) return `@${user.username}`;
+ return input;
+ }
+ })
+ .replace(/<#[0-9]+>/g, input => {
+ const channel = this.client.channels.get(input.replace(/<|#|>/g, ''));
+ if (channel) return `#${channel.name}`;
+ return input;
+ })
+ .replace(/<@&[0-9]+>/g, input => {
+ if (this.channel.type === 'dm' || this.channel.type === 'group') return input;
+ const role = this.guild.roles.get(input.replace(/<|@|>|&/g, ''));
+ if (role) return `@${role.name}`;
+ return input;
+ });
+ }
+
+ /**
+ * Creates a reaction collector.
+ * @param {CollectorFilter} filter The filter to apply
+ * @param {ReactionCollectorOptions} [options={}] Options to send to the collector
+ * @returns {ReactionCollector}
+ * @example
+ * // Create a reaction collector
+ * const collector = message.createReactionCollector(
+ * (reaction, user) => reaction.emoji.name === '👌' && user.id === 'someID',
+ * { time: 15000 }
+ * );
+ * collector.on('collect', r => console.log(`Collected ${r.emoji.name}`));
+ * collector.on('end', collected => console.log(`Collected ${collected.size} items`));
+ */
+ createReactionCollector(filter, options = {}) {
+ return new ReactionCollector(this, filter, options);
+ }
+
+ /**
+ * An object containing the same properties as CollectorOptions, but a few more:
+ * @typedef {ReactionCollectorOptions} AwaitReactionsOptions
+ * @property {string[]} [errors] Stop/end reasons that cause the promise to reject
+ */
+
+ /**
+ * Similar to createCollector but in promise form. Resolves with a collection of reactions that pass the specified
+ * filter.
+ * @param {CollectorFilter} filter The filter function to use
+ * @param {AwaitReactionsOptions} [options={}] Optional options to pass to the internal collector
+ * @returns {Promise>}
+ */
+ awaitReactions(filter, options = {}) {
+ return new Promise((resolve, reject) => {
+ const collector = this.createReactionCollector(filter, options);
+ collector.once('end', (reactions, reason) => {
+ if (options.errors && options.errors.includes(reason)) reject(reactions);
+ else resolve(reactions);
+ });
+ });
+ }
+
+ /**
+ * An array of cached versions of the message, including the current version
+ * Sorted from latest (first) to oldest (last)
+ * @type {Message[]}
+ * @readonly
+ */
+ get edits() {
+ const copy = this._edits.slice();
+ copy.unshift(this);
+ return copy;
+ }
+
+ /**
+ * Whether the message is editable by the client user
+ * @type {boolean}
+ * @readonly
+ */
+ get editable() {
+ return this.author.id === this.client.user.id;
+ }
+
+ /**
+ * Whether the message is deletable by the client user
+ * @type {boolean}
+ * @readonly
+ */
+ get deletable() {
+ return this.author.id === this.client.user.id || (this.guild &&
+ this.channel.permissionsFor(this.client.user).has(Permissions.FLAGS.MANAGE_MESSAGES)
+ );
+ }
+
+ /**
+ * Whether the message is pinnable by the client user
+ * @type {boolean}
+ * @readonly
+ */
+ get pinnable() {
+ return !this.guild ||
+ this.channel.permissionsFor(this.client.user).has(Permissions.FLAGS.MANAGE_MESSAGES);
+ }
+
+ /**
+ * Whether or not a user, channel or role is mentioned in this message.
+ * @param {GuildChannel|User|Role|string} data Either a guild channel, user or a role object, or a string representing
+ * the ID of any of these
+ * @returns {boolean}
+ */
+ isMentioned(data) {
+ data = data && data.id ? data.id : data;
+ return this.mentions.users.has(data) || this.mentions.channels.has(data) || this.mentions.roles.has(data);
+ }
+
+ /**
+ * Whether or not a guild member is mentioned in this message. Takes into account
+ * user mentions, role mentions, and @everyone/@here mentions.
+ * @param {GuildMember|User} member The member/user to check for a mention of
+ * @returns {boolean}
+ */
+ isMemberMentioned(member) {
+ // Lazy-loading is used here to get around a circular dependency that breaks things
+ if (!GuildMember) GuildMember = __webpack_require__(24);
+ if (this.mentions.everyone) return true;
+ if (this.mentions.users.has(member.id)) return true;
+ if (member instanceof GuildMember && member.roles.some(r => this.mentions.roles.has(r.id))) return true;
+ return false;
+ }
+
+ /**
+ * Options that can be passed into editMessage.
+ * @typedef {Object} MessageEditOptions
+ * @property {Object} [embed] An embed to be added/edited
+ * @property {string|boolean} [code] Language for optional codeblock formatting to apply
+ */
+
+ /**
+ * Edit the content of the message.
+ * @param {StringResolvable} [content] The new content for the message
+ * @param {MessageEditOptions} [options] The options to provide
+ * @returns {Promise}
+ * @example
+ * // Update the content of a message
+ * message.edit('This is my new content!')
+ * .then(msg => console.log(`Updated the content of a message from ${msg.author}`))
+ * .catch(console.error);
+ */
+ edit(content, options) {
+ if (!options && typeof content === 'object' && !(content instanceof Array)) {
+ options = content;
+ content = '';
+ } else if (!options) {
+ options = {};
+ }
+ return this.client.rest.methods.updateMessage(this, content, options);
+ }
+
+ /**
+ * Edit the content of the message, with a code block.
+ * @param {string} lang The language for the code block
+ * @param {StringResolvable} content The new content for the message
+ * @returns {Promise}
+ * @deprecated
+ */
+ editCode(lang, content) {
+ content = Util.escapeMarkdown(this.client.resolver.resolveString(content), true);
+ return this.edit(`\`\`\`${lang || ''}\n${content}\n\`\`\``);
+ }
+
+ /**
+ * Pins this message to the channel's pinned messages.
+ * @returns {Promise}
+ */
+ pin() {
+ return this.client.rest.methods.pinMessage(this);
+ }
+
+ /**
+ * Unpins this message from the channel's pinned messages.
+ * @returns {Promise}
+ */
+ unpin() {
+ return this.client.rest.methods.unpinMessage(this);
+ }
+
+ /**
+ * Add a reaction to the message.
+ * @param {string|Emoji|ReactionEmoji} emoji The emoji to react with
+ * @returns {Promise}
+ */
+ react(emoji) {
+ emoji = this.client.resolver.resolveEmojiIdentifier(emoji);
+ if (!emoji) throw new TypeError('Emoji must be a string or Emoji/ReactionEmoji');
+
+ return this.client.rest.methods.addMessageReaction(this, emoji);
+ }
+
+ /**
+ * Remove all reactions from a message.
+ * @returns {Promise}
+ */
+ clearReactions() {
+ return this.client.rest.methods.removeMessageReactions(this);
+ }
+
+ /**
+ * Deletes the message.
+ * @param {number} [timeout=0] How long to wait to delete the message in milliseconds
+ * @returns {Promise}
+ * @example
+ * // Delete a message
+ * message.delete()
+ * .then(msg => console.log(`Deleted message from ${msg.author}`))
+ * .catch(console.error);
+ */
+ delete(timeout = 0) {
+ if (timeout <= 0) {
+ return this.client.rest.methods.deleteMessage(this);
+ } else {
+ return new Promise(resolve => {
+ this.client.setTimeout(() => {
+ resolve(this.delete());
+ }, timeout);
+ });
+ }
+ }
+
+ /**
+ * Reply to the message.
+ * @param {StringResolvable} [content] The content for the message
+ * @param {MessageOptions} [options] The options to provide
+ * @returns {Promise}
+ * @example
+ * // Reply to a message
+ * message.reply('Hey, I\'m a reply!')
+ * .then(msg => console.log(`Sent a reply to ${msg.author}`))
+ * .catch(console.error);
+ */
+ reply(content, options) {
+ if (!options && typeof content === 'object' && !(content instanceof Array)) {
+ options = content;
+ content = '';
+ } else if (!options) {
+ options = {};
+ }
+ return this.channel.send(content, Object.assign(options, { reply: this.member || this.author }));
+ }
+
+ /**
+ * Marks the message as read.
+ * This is only available when using a user account.
+ * @returns {Promise}
+ */
+ acknowledge() {
+ return this.client.rest.methods.ackMessage(this);
+ }
+
+ /**
+ * Fetches the webhook used to create this message.
+ * @returns {Promise}
+ */
+ fetchWebhook() {
+ if (!this.webhookID) return Promise.reject(new Error('The message was not sent by a webhook.'));
+ return this.client.fetchWebhook(this.webhookID);
+ }
+
+ /**
+ * Used mainly internally. Whether two messages are identical in properties. If you want to compare messages
+ * without checking all the properties, use `message.id === message2.id`, which is much more efficient. This
+ * method allows you to see if there are differences in content, embeds, attachments, nonce and tts properties.
+ * @param {Message} message The message to compare it to
+ * @param {Object} rawData Raw data passed through the WebSocket about this message
+ * @returns {boolean}
+ */
+ equals(message, rawData) {
+ if (!message) return false;
+ const embedUpdate = !message.author && !message.attachments;
+ if (embedUpdate) return this.id === message.id && this.embeds.length === message.embeds.length;
+
+ let equal = this.id === message.id &&
+ this.author.id === message.author.id &&
+ this.content === message.content &&
+ this.tts === message.tts &&
+ this.nonce === message.nonce &&
+ this.embeds.length === message.embeds.length &&
+ this.attachments.length === message.attachments.length;
+
+ if (equal && rawData) {
+ equal = this.mentions.everyone === message.mentions.everyone &&
+ this.createdTimestamp === new Date(rawData.timestamp).getTime() &&
+ this.editedTimestamp === new Date(rawData.edited_timestamp).getTime();
+ }
+
+ return equal;
+ }
+
+ /**
+ * When concatenated with a string, this automatically concatenates the message's content instead of the object.
+ * @returns {string}
+ * @example
+ * // Logs: Message: This is a message!
+ * console.log(`Message: ${message}`);
+ */
+ toString() {
+ return this.content;
+ }
+
+ _addReaction(emoji, user) {
+ const emojiID = emoji.id ? `${emoji.name}:${emoji.id}` : encodeURIComponent(emoji.name);
+ let reaction;
+ if (this.reactions.has(emojiID)) {
+ reaction = this.reactions.get(emojiID);
+ if (!reaction.me) reaction.me = user.id === this.client.user.id;
+ } else {
+ reaction = new MessageReaction(this, emoji, 0, user.id === this.client.user.id);
+ this.reactions.set(emojiID, reaction);
+ }
+ if (!reaction.users.has(user.id)) reaction.users.set(user.id, user);
+ reaction.count++;
+ return reaction;
+ }
+
+ _removeReaction(emoji, user) {
+ const emojiID = emoji.id ? `${emoji.name}:${emoji.id}` : encodeURIComponent(emoji.name);
+ if (this.reactions.has(emojiID)) {
+ const reaction = this.reactions.get(emojiID);
+ if (reaction.users.has(user.id)) {
+ reaction.users.delete(user.id);
+ reaction.count--;
+ if (user.id === this.client.user.id) reaction.me = false;
+ if (reaction.count <= 0) this.reactions.delete(emojiID);
+ return reaction;
+ }
+ }
+ return null;
+ }
+
+ _clearReactions() {
+ this.reactions.clear();
+ }
+}
+
+module.exports = Message;
+
+
+/***/ }),
+/* 23 */
+/***/ (function(module, exports, __webpack_require__) {
+
+const Constants = __webpack_require__(0);
+const Collection = __webpack_require__(3);
+const Snowflake = __webpack_require__(8);
+
+/**
+ * Represents a custom emoji.
+ */
+class Emoji {
+ constructor(guild, data) {
+ /**
+ * The client that instantiated this object
+ * @name Emoji#client
+ * @type {Client}
+ * @readonly
+ */
+ Object.defineProperty(this, 'client', { value: guild.client });
+
+ /**
+ * The guild this emoji is part of
+ * @type {Guild}
+ */
+ this.guild = guild;
+
+ this.setup(data);
+ }
+
+ setup(data) {
+ /**
+ * The ID of the emoji
+ * @type {Snowflake}
+ */
+ this.id = data.id;
+
+ /**
+ * The name of the emoji
+ * @type {string}
+ */
+ this.name = data.name;
+
+ /**
+ * Whether or not this emoji requires colons surrounding it
+ * @type {boolean}
+ */
+ this.requiresColons = data.require_colons;
+
+ /**
+ * Whether this emoji is managed by an external service
+ * @type {boolean}
+ */
+ this.managed = data.managed;
+
+ this._roles = data.roles;
+ }
+
+ /**
+ * The timestamp the emoji was created at
+ * @type {number}
+ * @readonly
+ */
+ get createdTimestamp() {
+ return Snowflake.deconstruct(this.id).timestamp;
+ }
+
+ /**
+ * The time the emoji was created
+ * @type {Date}
+ * @readonly
+ */
+ get createdAt() {
+ return new Date(this.createdTimestamp);
+ }
+
+ /**
+ * A collection of roles this emoji is active for (empty if all), mapped by role ID
+ * @type {Collection}
+ * @readonly
+ */
+ get roles() {
+ const roles = new Collection();
+ for (const role of this._roles) {
+ if (this.guild.roles.has(role)) roles.set(role, this.guild.roles.get(role));
+ }
+ return roles;
+ }
+
+ /**
+ * The URL to the emoji file
+ * @type {string}
+ * @readonly
+ */
+ get url() {
+ return Constants.Endpoints.CDN(this.client.options.http.cdn).Emoji(this.id);
+ }
+
+ /**
+ * The identifier of this emoji, used for message reactions
+ * @type {string}
+ * @readonly
+ */
+ get identifier() {
+ if (this.id) return `${this.name}:${this.id}`;
+ return encodeURIComponent(this.name);
+ }
+
+ /**
+ * Data for editing an emoji.
+ * @typedef {Object} EmojiEditData
+ * @property {string} [name] The name of the emoji
+ * @property {Collection|Array} [roles] Roles to restrict emoji to
+ */
+
+ /**
+ * Edits the emoji.
+ * @param {EmojiEditData} data The new data for the emoji
+ * @returns {Promise}
+ * @example
+ * // Edit a emoji
+ * emoji.edit({name: 'newemoji'})
+ * .then(e => console.log(`Edited emoji ${e}`))
+ * .catch(console.error);
+ */
+ edit(data) {
+ return this.client.rest.methods.updateEmoji(this, data);
+ }
+
+ /**
+ * Set the name of the emoji.
+ * @param {string} name The new name for the emoji
+ * @returns {Promise}
+ */
+ setName(name) {
+ return this.edit({ name });
+ }
+
+ /**
+ * Add a role to the list of roles that can use this emoji.
+ * @param {Role} role The role to add
+ * @returns {Promise}
+ */
+ addRestrictedRole(role) {
+ return this.addRestrictedRoles([role]);
+ }
+
+ /**
+ * Add multiple roles to the list of roles that can use this emoji.
+ * @param {Role[]} roles Roles to add
+ * @returns {Promise}
+ */
+ addRestrictedRoles(roles) {
+ const newRoles = new Collection(this.roles);
+ for (const role of roles) {
+ if (this.guild.roles.has(role.id)) newRoles.set(role.id, role);
+ }
+ return this.edit({ roles: newRoles });
+ }
+
+ /**
+ * Remove a role from the list of roles that can use this emoji.
+ * @param {Role} role The role to remove
+ * @returns {Promise}
+ */
+ removeRestrictedRole(role) {
+ return this.removeRestrictedRoles([role]);
+ }
+
+ /**
+ * Remove multiple roles from the list of roles that can use this emoji.
+ * @param {Role[]} roles Roles to remove
+ * @returns {Promise}
+ */
+ removeRestrictedRoles(roles) {
+ const newRoles = new Collection(this.roles);
+ for (const role of roles) {
+ if (newRoles.has(role.id)) newRoles.delete(role.id);
+ }
+ return this.edit({ roles: newRoles });
+ }
+
+ /**
+ * When concatenated with a string, this automatically returns the emoji mention rather than the object.
+ * @returns {string}
+ * @example
+ * // Send an emoji:
+ * const emoji = guild.emojis.first();
+ * msg.reply(`Hello! ${emoji}`);
+ */
+ toString() {
+ return this.requiresColons ? `<:${this.name}:${this.id}>` : this.name;
+ }
+
+ /**
+ * Whether this emoji is the same as another one.
+ * @param {Emoji|Object} other The emoji to compare it to
+ * @returns {boolean} Whether the emoji is equal to the given emoji or not
+ */
+ equals(other) {
+ if (other instanceof Emoji) {
+ return (
+ other.id === this.id &&
+ other.name === this.name &&
+ other.managed === this.managed &&
+ other.requiresColons === this.requiresColons
+ );
+ } else {
+ return (
+ other.id === this.id &&
+ other.name === this.name
+ );
+ }
+ }
+}
+
+module.exports = Emoji;
+
+
/***/ }),
/* 24 */
+/***/ (function(module, exports, __webpack_require__) {
+
+const TextBasedChannel = __webpack_require__(21);
+const Role = __webpack_require__(14);
+const Permissions = __webpack_require__(11);
+const Collection = __webpack_require__(3);
+const Presence = __webpack_require__(15).Presence;
+const util = __webpack_require__(20);
+
+/**
+ * Represents a member of a guild on Discord.
+ * @implements {TextBasedChannel}
+ */
+class GuildMember {
+ constructor(guild, data) {
+ /**
+ * The client that instantiated this GuildMember
+ * @name GuildMember#client
+ * @type {Client}
+ * @readonly
+ */
+ Object.defineProperty(this, 'client', { value: guild.client });
+
+ /**
+ * The guild that this member is part of
+ * @type {Guild}
+ */
+ this.guild = guild;
+
+ /**
+ * The user that this guild member instance Represents
+ * @type {User}
+ */
+ this.user = {};
+
+ this._roles = [];
+ if (data) this.setup(data);
+
+ /**
+ * The ID of the last message sent by the member in their guild, if one was sent
+ * @type {?Snowflake}
+ */
+ this.lastMessageID = null;
+
+ /**
+ * The Message object of the last message sent by the member in their guild, if one was sent
+ * @type {?Message}
+ */
+ this.lastMessage = null;
+ }
+
+ setup(data) {
+ /**
+ * Whether this member is deafened server-wide
+ * @type {boolean}
+ */
+ this.serverDeaf = data.deaf;
+
+ /**
+ * Whether this member is muted server-wide
+ * @type {boolean}
+ */
+ this.serverMute = data.mute;
+
+ /**
+ * Whether this member is self-muted
+ * @type {boolean}
+ */
+ this.selfMute = data.self_mute;
+
+ /**
+ * Whether this member is self-deafened
+ * @type {boolean}
+ */
+ this.selfDeaf = data.self_deaf;
+
+ /**
+ * The voice session ID of this member, if any
+ * @type {?Snowflake}
+ */
+ this.voiceSessionID = data.session_id;
+
+ /**
+ * The voice channel ID of this member, if any
+ * @type {?Snowflake}
+ */
+ this.voiceChannelID = data.channel_id;
+
+ /**
+ * Whether this member is speaking
+ * @type {boolean}
+ */
+ this.speaking = false;
+
+ /**
+ * The nickname of this guild member, if they have one
+ * @type {?string}
+ */
+ this.nickname = data.nick || null;
+
+ /**
+ * The timestamp the member joined the guild at
+ * @type {number}
+ */
+ this.joinedTimestamp = new Date(data.joined_at).getTime();
+
+ this.user = data.user;
+ this._roles = data.roles;
+ }
+
+ /**
+ * The time the member joined the guild
+ * @type {Date}
+ * @readonly
+ */
+ get joinedAt() {
+ return new Date(this.joinedTimestamp);
+ }
+
+ /**
+ * The presence of this guild member
+ * @type {Presence}
+ * @readonly
+ */
+ get presence() {
+ return this.frozenPresence || this.guild.presences.get(this.id) || new Presence();
+ }
+
+ /**
+ * A list of roles that are applied to this GuildMember, mapped by the role ID
+ * @type {Collection}
+ * @readonly
+ */
+ get roles() {
+ const list = new Collection();
+ const everyoneRole = this.guild.roles.get(this.guild.id);
+
+ if (everyoneRole) list.set(everyoneRole.id, everyoneRole);
+
+ for (const roleID of this._roles) {
+ const role = this.guild.roles.get(roleID);
+ if (role) list.set(role.id, role);
+ }
+
+ return list;
+ }
+
+ /**
+ * The role of the member with the highest position
+ * @type {Role}
+ * @readonly
+ */
+ get highestRole() {
+ return this.roles.reduce((prev, role) => !prev || role.comparePositionTo(prev) > 0 ? role : prev);
+ }
+
+ /**
+ * The role of the member used to set their color
+ * @type {?Role}
+ * @readonly
+ */
+ get colorRole() {
+ const coloredRoles = this.roles.filter(role => role.color);
+ if (!coloredRoles.size) return null;
+ return coloredRoles.reduce((prev, role) => !prev || role.comparePositionTo(prev) > 0 ? role : prev);
+ }
+
+ /**
+ * The displayed color of the member in base 10
+ * @type {number}
+ * @readonly
+ */
+ get displayColor() {
+ const role = this.colorRole;
+ return (role && role.color) || 0;
+ }
+
+ /**
+ * The displayed color of the member in hexadecimal
+ * @type {string}
+ * @readonly
+ */
+ get displayHexColor() {
+ const role = this.colorRole;
+ return (role && role.hexColor) || '#000000';
+ }
+
+ /**
+ * The role of the member used to hoist them in a separate category in the users list
+ * @type {?Role}
+ * @readonly
+ */
+ get hoistRole() {
+ const hoistedRoles = this.roles.filter(role => role.hoist);
+ if (!hoistedRoles.size) return null;
+ return hoistedRoles.reduce((prev, role) => !prev || role.comparePositionTo(prev) > 0 ? role : prev);
+ }
+
+ /**
+ * Whether this member is muted in any way
+ * @type {boolean}
+ * @readonly
+ */
+ get mute() {
+ return this.selfMute || this.serverMute;
+ }
+
+ /**
+ * Whether this member is deafened in any way
+ * @type {boolean}
+ * @readonly
+ */
+ get deaf() {
+ return this.selfDeaf || this.serverDeaf;
+ }
+
+ /**
+ * The voice channel this member is in, if any
+ * @type {?VoiceChannel}
+ * @readonly
+ */
+ get voiceChannel() {
+ return this.guild.channels.get(this.voiceChannelID);
+ }
+
+ /**
+ * The ID of this user
+ * @type {Snowflake}
+ * @readonly
+ */
+ get id() {
+ return this.user.id;
+ }
+
+ /**
+ * The nickname of the member, or their username if they don't have one
+ * @type {string}
+ * @readonly
+ */
+ get displayName() {
+ return this.nickname || this.user.username;
+ }
+
+ /**
+ * The overall set of permissions for the guild member, taking only roles into account
+ * @type {Permissions}
+ * @readonly
+ */
+ get permissions() {
+ if (this.user.id === this.guild.ownerID) return new Permissions(this, Permissions.ALL);
+
+ let permissions = 0;
+ const roles = this.roles;
+ for (const role of roles.values()) permissions |= role.permissions;
+
+ return new Permissions(this, permissions);
+ }
+
+ /**
+ * Whether the member is kickable by the client user
+ * @type {boolean}
+ * @readonly
+ */
+ get kickable() {
+ if (this.user.id === this.guild.ownerID) return false;
+ if (this.user.id === this.client.user.id) return false;
+ const clientMember = this.guild.member(this.client.user);
+ if (!clientMember.permissions.has(Permissions.FLAGS.KICK_MEMBERS)) return false;
+ return clientMember.highestRole.comparePositionTo(this.highestRole) > 0;
+ }
+
+ /**
+ * Whether the member is bannable by the client user
+ * @type {boolean}
+ * @readonly
+ */
+ get bannable() {
+ if (this.user.id === this.guild.ownerID) return false;
+ if (this.user.id === this.client.user.id) return false;
+ const clientMember = this.guild.member(this.client.user);
+ if (!clientMember.permissions.has(Permissions.FLAGS.BAN_MEMBERS)) return false;
+ return clientMember.highestRole.comparePositionTo(this.highestRole) > 0;
+ }
+
+ /**
+ * Returns `channel.permissionsFor(guildMember)`. Returns permissions for a member in a guild channel,
+ * taking into account roles and permission overwrites.
+ * @param {ChannelResolvable} channel The guild channel to use as context
+ * @returns {?Permissions}
+ */
+ permissionsIn(channel) {
+ channel = this.client.resolver.resolveChannel(channel);
+ if (!channel || !channel.guild) throw new Error('Could not resolve channel to a guild channel.');
+ return channel.permissionsFor(this);
+ }
+
+ /**
+ * Checks if any of the member's roles have a permission.
+ * @param {PermissionResolvable|PermissionResolvable[]} permission Permission(s) to check for
+ * @param {boolean} [explicit=false] Whether to require the role to explicitly have the exact permission
+ * **(deprecated)**
+ * @param {boolean} [checkAdmin] Whether to allow the administrator permission to override
+ * (takes priority over `explicit`)
+ * @param {boolean} [checkOwner] Whether to allow being the guild's owner to override
+ * (takes priority over `explicit`)
+ * @returns {boolean}
+ */
+ hasPermission(permission, explicit = false, checkAdmin, checkOwner) {
+ if (typeof checkAdmin === 'undefined') checkAdmin = !explicit;
+ if (typeof checkOwner === 'undefined') checkOwner = !explicit;
+ if (checkOwner && this.user.id === this.guild.ownerID) return true;
+ return this.roles.some(r => r.hasPermission(permission, undefined, checkAdmin));
+ }
+
+ /**
+ * Checks whether the roles of the member allows them to perform specific actions.
+ * @param {PermissionResolvable[]} permissions The permissions to check for
+ * @param {boolean} [explicit=false] Whether to require the member to explicitly have the exact permissions
+ * @returns {boolean}
+ * @deprecated
+ */
+ hasPermissions(permissions, explicit = false) {
+ if (!explicit && this.user.id === this.guild.ownerID) return true;
+ return this.hasPermission(permissions, explicit);
+ }
+
+ /**
+ * Checks whether the roles of the member allows them to perform specific actions, and lists any missing permissions.
+ * @param {PermissionResolvable[]} permissions The permissions to check for
+ * @param {boolean} [explicit=false] Whether to require the member to explicitly have the exact permissions
+ * @returns {PermissionResolvable[]}
+ */
+ missingPermissions(permissions, explicit = false) {
+ return permissions.missing(permissions, explicit);
+ }
+
+ /**
+ * The data for editing a guild member.
+ * @typedef {Object} GuildMemberEditData
+ * @property {string} [nick] The nickname to set for the member
+ * @property {Collection|Role[]|Snowflake[]} [roles] The roles or role IDs to apply
+ * @property {boolean} [mute] Whether or not the member should be muted
+ * @property {boolean} [deaf] Whether or not the member should be deafened
+ * @property {ChannelResolvable} [channel] Channel to move member to (if they are connected to voice)
+ */
+
+ /**
+ * Edit a guild member.
+ * @param {GuildMemberEditData} data The data to edit the member with
+ * @returns {Promise}
+ */
+ edit(data) {
+ return this.client.rest.methods.updateGuildMember(this, data);
+ }
+
+ /**
+ * Mute/unmute a user.
+ * @param {boolean} mute Whether or not the member should be muted
+ * @returns {Promise}
+ */
+ setMute(mute) {
+ return this.edit({ mute });
+ }
+
+ /**
+ * Deafen/undeafen a user.
+ * @param {boolean} deaf Whether or not the member should be deafened
+ * @returns {Promise}
+ */
+ setDeaf(deaf) {
+ return this.edit({ deaf });
+ }
+
+ /**
+ * Moves the guild member to the given channel.
+ * @param {ChannelResolvable} channel The channel to move the member to
+ * @returns {Promise}
+ */
+ setVoiceChannel(channel) {
+ return this.edit({ channel });
+ }
+
+ /**
+ * Sets the roles applied to the member.
+ * @param {Collection|Role[]|Snowflake[]} roles The roles or role IDs to apply
+ * @returns {Promise}
+ */
+ setRoles(roles) {
+ return this.edit({ roles });
+ }
+
+ /**
+ * Adds a single role to the member.
+ * @param {Role|Snowflake} role The role or ID of the role to add
+ * @returns {Promise}
+ */
+ addRole(role) {
+ if (!(role instanceof Role)) role = this.guild.roles.get(role);
+ if (!role) return Promise.reject(new TypeError('Supplied parameter was neither a Role nor a Snowflake.'));
+ return this.client.rest.methods.addMemberRole(this, role);
+ }
+
+ /**
+ * Adds multiple roles to the member.
+ * @param {Collection|Role[]|Snowflake[]} roles The roles or role IDs to add
+ * @returns {Promise}
+ */
+ addRoles(roles) {
+ let allRoles;
+ if (roles instanceof Collection) {
+ allRoles = this._roles.slice();
+ for (const role of roles.values()) allRoles.push(role.id);
+ } else {
+ allRoles = this._roles.concat(roles);
+ }
+ return this.edit({ roles: allRoles });
+ }
+
+ /**
+ * Removes a single role from the member.
+ * @param {Role|Snowflake} role The role or ID of the role to remove
+ * @returns {Promise}
+ */
+ removeRole(role) {
+ if (!(role instanceof Role)) role = this.guild.roles.get(role);
+ if (!role) return Promise.reject(new TypeError('Supplied parameter was neither a Role nor a Snowflake.'));
+ return this.client.rest.methods.removeMemberRole(this, role);
+ }
+
+ /**
+ * Removes multiple roles from the member.
+ * @param {Collection|Role[]|Snowflake[]} roles The roles or role IDs to remove
+ * @returns {Promise}
+ */
+ removeRoles(roles) {
+ const allRoles = this._roles.slice();
+ if (roles instanceof Collection) {
+ for (const role of roles.values()) {
+ const index = allRoles.indexOf(role.id);
+ if (index >= 0) allRoles.splice(index, 1);
+ }
+ } else {
+ for (const role of roles) {
+ const index = allRoles.indexOf(role instanceof Role ? role.id : role);
+ if (index >= 0) allRoles.splice(index, 1);
+ }
+ }
+ return this.edit({ roles: allRoles });
+ }
+
+ /**
+ * Set the nickname for the guild member.
+ * @param {string} nick The nickname for the guild member
+ * @returns {Promise}
+ */
+ setNickname(nick) {
+ return this.edit({ nick });
+ }
+
+ /**
+ * Creates a DM channel between the client and the member.
+ * @returns {Promise}
+ */
+ createDM() {
+ return this.user.createDM();
+ }
+
+ /**
+ * Deletes any DMs with this guild member.
+ * @returns {Promise}
+ */
+ deleteDM() {
+ return this.user.deleteDM();
+ }
+
+ /**
+ * Kick this member from the guild.
+ * @param {string} [reason] Reason for kicking user
+ * @returns {Promise}
+ */
+ kick(reason) {
+ return this.client.rest.methods.kickGuildMember(this.guild, this, reason);
+ }
+
+ /**
+ * Ban this guild member
+ * @param {Object|number|string} [options] Ban options. If a number, the number of days to delete messages for, if a
+ * string, the ban reason. Supplying an object allows you to do both.
+ * @param {number} [options.days=0] Number of days of messages to delete
+ * @param {string} [options.reason] Reason for banning
+ * @returns {Promise}
+ * @example
+ * // ban a guild member
+ * guildMember.ban(7);
+ */
+ ban(options) {
+ return this.guild.ban(this, options);
+ }
+
+ /**
+ * When concatenated with a string, this automatically concatenates the user's mention instead of the Member object.
+ * @returns {string}
+ * @example
+ * // Logs: Hello from <@123456789>!
+ * console.log(`Hello from ${member}!`);
+ */
+ toString() {
+ return `<@${this.nickname ? '!' : ''}${this.user.id}>`;
+ }
+
+ // These are here only for documentation purposes - they are implemented by TextBasedChannel
+ /* eslint-disable no-empty-function */
+ send() {}
+ sendMessage() {}
+ sendEmbed() {}
+ sendFile() {}
+ sendCode() {}
+}
+
+TextBasedChannel.applyToClass(GuildMember);
+
+GuildMember.prototype.hasPermissions = util.deprecate(GuildMember.prototype.hasPermissions,
+ 'GuildMember#hasPermissions is deprecated - use GuildMember#hasPermission, it now takes an array');
+
+module.exports = GuildMember;
+
+
+/***/ }),
+/* 25 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+/* WEBPACK VAR INJECTION */(function(process) {
+
+if (!process.version ||
+ process.version.indexOf('v0.') === 0 ||
+ process.version.indexOf('v1.') === 0 && process.version.indexOf('v1.8.') !== 0) {
+ module.exports = nextTick;
+} else {
+ module.exports = process.nextTick;
+}
+
+function nextTick(fn, arg1, arg2, arg3) {
+ if (typeof fn !== 'function') {
+ throw new TypeError('"callback" argument must be a function');
+ }
+ var len = arguments.length;
+ var args, i;
+ switch (len) {
+ case 0:
+ case 1:
+ return process.nextTick(fn);
+ case 2:
+ return process.nextTick(function afterTickOne() {
+ fn.call(null, arg1);
+ });
+ case 3:
+ return process.nextTick(function afterTickTwo() {
+ fn.call(null, arg1, arg2);
+ });
+ case 4:
+ return process.nextTick(function afterTickThree() {
+ fn.call(null, arg1, arg2, arg3);
+ });
+ default:
+ args = new Array(len - 1);
+ i = 0;
+ while (i < args.length) {
+ args[i++] = arguments[i];
+ }
+ return process.nextTick(function afterTick() {
+ fn.apply(null, args);
+ });
+ }
+}
+
+/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7)))
+
+/***/ }),
+/* 26 */
+/***/ (function(module, exports) {
+
+
+
+/***/ }),
+/* 27 */
/***/ (function(module, exports) {
exports.endianness = function () { return 'LE' };
@@ -7573,19 +8000,19 @@ exports.EOL = '\n';
/***/ }),
-/* 25 */
+/* 28 */
/***/ (function(module, exports, __webpack_require__) {
-const Long = __webpack_require__(33);
-const User = __webpack_require__(16);
-const Role = __webpack_require__(15);
-const Emoji = __webpack_require__(17);
-const Presence = __webpack_require__(11).Presence;
-const GuildMember = __webpack_require__(18);
+const Long = __webpack_require__(35);
+const User = __webpack_require__(13);
+const Role = __webpack_require__(14);
+const Emoji = __webpack_require__(23);
+const Presence = __webpack_require__(15).Presence;
+const GuildMember = __webpack_require__(24);
const Constants = __webpack_require__(0);
const Collection = __webpack_require__(3);
const Util = __webpack_require__(4);
-const Snowflake = __webpack_require__(5);
+const Snowflake = __webpack_require__(8);
/**
* Represents a guild (or a server) on Discord.
@@ -8665,8 +9092,8 @@ class Guild {
_sortPositionWithID(collection) {
return collection.sort((a, b) =>
a.position !== b.position ?
- a.position - b.position :
- Long.fromString(a.id).sub(Long.fromString(b.id)).toNumber()
+ a.position - b.position :
+ Long.fromString(a.id).sub(Long.fromString(b.id)).toNumber()
);
}
}
@@ -8675,13 +9102,13 @@ module.exports = Guild;
/***/ }),
-/* 26 */
+/* 29 */
/***/ (function(module, exports, __webpack_require__) {
-const Channel = __webpack_require__(14);
-const Role = __webpack_require__(15);
-const PermissionOverwrites = __webpack_require__(54);
-const Permissions = __webpack_require__(8);
+const Channel = __webpack_require__(16);
+const Role = __webpack_require__(14);
+const PermissionOverwrites = __webpack_require__(68);
+const Permissions = __webpack_require__(11);
const Collection = __webpack_require__(3);
/**
@@ -9021,158 +9448,21 @@ module.exports = GuildChannel;
/***/ }),
-/* 27 */
+/* 30 */
/***/ (function(module, exports, __webpack_require__) {
-const Snowflake = __webpack_require__(5);
+const Snekfetch = __webpack_require__(76);
-/**
- * Represents an OAuth2 Application.
- */
-class OAuth2Application {
- constructor(client, data) {
- /**
- * The client that instantiated the application
- * @name OAuth2Application#client
- * @type {Client}
- * @readonly
- */
- Object.defineProperty(this, 'client', { value: client });
+// Sync stuff might go here
- this.setup(data);
- }
-
- setup(data) {
- /**
- * The ID of the app
- * @type {Snowflake}
- */
- this.id = data.id;
-
- /**
- * The name of the app
- * @type {string}
- */
- this.name = data.name;
-
- /**
- * The app's description
- * @type {string}
- */
- this.description = data.description;
-
- /**
- * The app's icon hash
- * @type {string}
- */
- this.icon = data.icon;
-
- /**
- * The app's icon URL
- * @type {string}
- */
- this.iconURL = `https://cdn.discordapp.com/app-icons/${this.id}/${this.icon}.jpg`;
-
- /**
- * The app's RPC origins
- * @type {?string[]}
- */
- this.rpcOrigins = data.rpc_origins;
-
- /**
- * The app's redirect URIs
- * @type {string[]}
- */
- this.redirectURIs = data.redirect_uris;
-
- /**
- * If this app's bot requires a code grant when using the OAuth2 flow
- * @type {boolean}
- */
- this.botRequireCodeGrant = data.bot_require_code_grant;
-
- /**
- * If this app's bot is public
- * @type {boolean}
- */
- this.botPublic = data.bot_public;
-
- /**
- * If this app can use rpc
- * @type {boolean}
- */
- this.rpcApplicationState = data.rpc_application_state;
-
- /**
- * Object containing basic info about this app's bot
- * @type {Object}
- */
- this.bot = data.bot;
-
- /**
- * The flags for the app
- * @type {number}
- */
- this.flags = data.flags;
-
- /**
- * OAuth2 secret for the application
- * @type {boolean}
- */
- this.secret = data.secret;
-
- if (data.owner) {
- /**
- * The owner of this OAuth application
- * @type {?User}
- */
- this.owner = this.client.dataManager.newUser(data.owner);
- }
- }
-
- /**
- * The timestamp the app was created at
- * @type {number}
- * @readonly
- */
- get createdTimestamp() {
- return Snowflake.deconstruct(this.id).timestamp;
- }
-
- /**
- * The time the app was created
- * @type {Date}
- * @readonly
- */
- get createdAt() {
- return new Date(this.createdTimestamp);
- }
-
- /**
- * Reset the app's secret and bot token.
- * @returns {OAuth2Application}
- */
- reset() {
- return this.client.rest.methods.resetApplication(this.id);
- }
-
- /**
- * When concatenated with a string, this automatically concatenates the app name rather than the app object.
- * @returns {string}
- */
- toString() {
- return this.name;
- }
-}
-
-module.exports = OAuth2Application;
+module.exports = Snekfetch;
/***/ }),
-/* 28 */
+/* 31 */
/***/ (function(module, exports, __webpack_require__) {
-/* WEBPACK VAR INJECTION */(function(process) {// Copyright Joyent, Inc. and other Node contributors.
+// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
@@ -9193,873 +9483,868 @@ module.exports = OAuth2Application;
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
-// resolves . and .. elements in a path array with directory names there
-// must be no slashes, empty elements, or device names (c:\) in the array
-// (so also no leading and trailing slashes - it does not distinguish
-// relative and absolute paths)
-function normalizeArray(parts, allowAboveRoot) {
- // if the path tries to go above the root, `up` ends up > 0
- var up = 0;
- for (var i = parts.length - 1; i >= 0; i--) {
- var last = parts[i];
- if (last === '.') {
- parts.splice(i, 1);
- } else if (last === '..') {
- parts.splice(i, 1);
- up++;
- } else if (up) {
- parts.splice(i, 1);
- up--;
- }
- }
+module.exports = Stream;
- // if the path is allowed to go above the root, restore leading ..s
- if (allowAboveRoot) {
- for (; up--; up) {
- parts.unshift('..');
- }
- }
+var EE = __webpack_require__(9).EventEmitter;
+var inherits = __webpack_require__(10);
- return parts;
+inherits(Stream, EE);
+Stream.Readable = __webpack_require__(17);
+Stream.Writable = __webpack_require__(83);
+Stream.Duplex = __webpack_require__(84);
+Stream.Transform = __webpack_require__(85);
+Stream.PassThrough = __webpack_require__(86);
+
+// Backwards-compat with node 0.4.x
+Stream.Stream = Stream;
+
+
+
+// old-style streams. Note that the pipe method (the only relevant
+// part of this class) is overridden in the Readable class.
+
+function Stream() {
+ EE.call(this);
}
-// Split a filename into [root, dir, basename, ext], unix version
-// 'root' is just a slash, or nothing.
-var splitPathRe =
- /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
-var splitPath = function(filename) {
- return splitPathRe.exec(filename).slice(1);
-};
+Stream.prototype.pipe = function(dest, options) {
+ var source = this;
-// path.resolve([from ...], to)
-// posix version
-exports.resolve = function() {
- var resolvedPath = '',
- resolvedAbsolute = false;
-
- for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
- var path = (i >= 0) ? arguments[i] : process.cwd();
-
- // Skip empty and invalid entries
- if (typeof path !== 'string') {
- throw new TypeError('Arguments to path.resolve must be strings');
- } else if (!path) {
- continue;
- }
-
- resolvedPath = path + '/' + resolvedPath;
- resolvedAbsolute = path.charAt(0) === '/';
- }
-
- // At this point the path should be resolved to a full absolute path, but
- // handle relative paths to be safe (might happen when process.cwd() fails)
-
- // Normalize the path
- resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) {
- return !!p;
- }), !resolvedAbsolute).join('/');
-
- return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
-};
-
-// path.normalize(path)
-// posix version
-exports.normalize = function(path) {
- var isAbsolute = exports.isAbsolute(path),
- trailingSlash = substr(path, -1) === '/';
-
- // Normalize the path
- path = normalizeArray(filter(path.split('/'), function(p) {
- return !!p;
- }), !isAbsolute).join('/');
-
- if (!path && !isAbsolute) {
- path = '.';
- }
- if (path && trailingSlash) {
- path += '/';
- }
-
- return (isAbsolute ? '/' : '') + path;
-};
-
-// posix version
-exports.isAbsolute = function(path) {
- return path.charAt(0) === '/';
-};
-
-// posix version
-exports.join = function() {
- var paths = Array.prototype.slice.call(arguments, 0);
- return exports.normalize(filter(paths, function(p, index) {
- if (typeof p !== 'string') {
- throw new TypeError('Arguments to path.join must be strings');
- }
- return p;
- }).join('/'));
-};
-
-
-// path.relative(from, to)
-// posix version
-exports.relative = function(from, to) {
- from = exports.resolve(from).substr(1);
- to = exports.resolve(to).substr(1);
-
- function trim(arr) {
- var start = 0;
- for (; start < arr.length; start++) {
- if (arr[start] !== '') break;
- }
-
- var end = arr.length - 1;
- for (; end >= 0; end--) {
- if (arr[end] !== '') break;
- }
-
- if (start > end) return [];
- return arr.slice(start, end - start + 1);
- }
-
- var fromParts = trim(from.split('/'));
- var toParts = trim(to.split('/'));
-
- var length = Math.min(fromParts.length, toParts.length);
- var samePartsLength = length;
- for (var i = 0; i < length; i++) {
- if (fromParts[i] !== toParts[i]) {
- samePartsLength = i;
- break;
- }
- }
-
- var outputParts = [];
- for (var i = samePartsLength; i < fromParts.length; i++) {
- outputParts.push('..');
- }
-
- outputParts = outputParts.concat(toParts.slice(samePartsLength));
-
- return outputParts.join('/');
-};
-
-exports.sep = '/';
-exports.delimiter = ':';
-
-exports.dirname = function(path) {
- var result = splitPath(path),
- root = result[0],
- dir = result[1];
-
- if (!root && !dir) {
- // No dirname whatsoever
- return '.';
- }
-
- if (dir) {
- // It has a dirname, strip trailing slash
- dir = dir.substr(0, dir.length - 1);
- }
-
- return root + dir;
-};
-
-
-exports.basename = function(path, ext) {
- var f = splitPath(path)[2];
- // TODO: make this comparison case-insensitive on windows?
- if (ext && f.substr(-1 * ext.length) === ext) {
- f = f.substr(0, f.length - ext.length);
- }
- return f;
-};
-
-
-exports.extname = function(path) {
- return splitPath(path)[3];
-};
-
-function filter (xs, f) {
- if (xs.filter) return xs.filter(f);
- var res = [];
- for (var i = 0; i < xs.length; i++) {
- if (f(xs[i], i, xs)) res.push(xs[i]);
- }
- return res;
-}
-
-// String.prototype.substr - negative index don't work in IE8
-var substr = 'ab'.substr(-1) === 'b'
- ? function (str, start, len) { return str.substr(start, len) }
- : function (str, start, len) {
- if (start < 0) start = str.length + start;
- return str.substr(start, len);
- }
-;
-
-/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7)))
-
-/***/ }),
-/* 29 */
-/***/ (function(module, exports, __webpack_require__) {
-
-const Channel = __webpack_require__(14);
-const TextBasedChannel = __webpack_require__(23);
-const Collection = __webpack_require__(3);
-
-/*
-{ 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);
- this.type = 'group';
- this.messages = new Collection();
- this._typing = new Map();
- }
-
- setup(data) {
- super.setup(data);
-
- /**
- * The name of this Group DM, can be null if one isn't set
- * @type {string}
- */
- this.name = data.name;
-
- /**
- * A hash of the Group DM icon.
- * @type {string}
- */
- this.icon = data.icon;
-
- /**
- * The user ID of this Group DM's owner
- * @type {string}
- */
- 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 {?string}
- */
- this.applicationID = data.application_id;
-
- /**
- * Nicknames for group members
- * @type {?Collection}
- */
- if (data.nicks) 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}
- */
- this.recipients = new Collection();
- }
-
- if (data.recipients) {
- for (const recipient of data.recipients) {
- const user = this.client.dataManager.newUser(recipient);
- this.recipients.set(user.id, user);
+ function ondata(chunk) {
+ if (dest.writable) {
+ if (false === dest.write(chunk) && source.pause) {
+ source.pause();
}
}
-
- this.lastMessageID = data.last_message_id;
}
- /**
- * The owner of this Group DM
- * @type {User}
- * @readonly
- */
- get owner() {
- return this.client.users.get(this.ownerID);
- }
+ source.on('data', ondata);
- /**
- * 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;
- }
-
- /**
- * Add a user to the DM
- * @param {UserResolvable|string} accessTokenOrID Access token or user resolvable
- * @param {string} [nick] Permanent nickname to give the user (only available if a bot is creating the DM)
- */
-
- addUser(accessTokenOrID, nick) {
- return this.client.rest.methods.addUserToGroupDM(this, {
- nick,
- id: this.client.resolver.resolveUserID(accessTokenOrID),
- accessToken: accessTokenOrID,
- });
- }
-
- /**
- * When concatenated with a string, this automatically concatenates the channel's name instead of the Channel object.
- * @returns {string}
- * @example
- * // Logs: Hello from My Group DM!
- * console.log(`Hello from ${channel}!`);
- * @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 */
- send() {}
- sendMessage() {}
- sendEmbed() {}
- sendFile() {}
- sendFiles() {}
- sendCode() {}
- fetchMessage() {}
- fetchMessages() {}
- fetchPinnedMessages() {}
- search() {}
- startTyping() {}
- stopTyping() {}
- get typing() {}
- get typingCount() {}
- createCollector() {}
- awaitMessages() {}
- // Doesn't work on Group DMs; bulkDelete() {}
- acknowledge() {}
- _cacheMessage() {}
-}
-
-TextBasedChannel.applyToClass(GroupDMChannel, true, ['bulkDelete']);
-
-module.exports = GroupDMChannel;
-
-
-/***/ }),
-/* 30 */
-/***/ (function(module, exports) {
-
-/**
- * Represents a limited emoji set used for both custom and unicode emojis. Custom emojis
- * will use this class opposed to the Emoji class when the client doesn't know enough
- * information about them.
- */
-class ReactionEmoji {
- constructor(reaction, name, id) {
- /**
- * The message reaction this emoji refers to
- * @type {MessageReaction}
- */
- this.reaction = reaction;
-
- /**
- * The name of this reaction emoji
- * @type {string}
- */
- this.name = name;
-
- /**
- * The ID of this reaction emoji
- * @type {?Snowflake}
- */
- this.id = id;
- }
-
- /**
- * The identifier of this emoji, used for message reactions
- * @type {string}
- * @readonly
- */
- get identifier() {
- if (this.id) return `${this.name}:${this.id}`;
- return encodeURIComponent(this.name);
- }
-
- /**
- * Creates the text required to form a graphical emoji on Discord.
- * @example
- * // Send the emoji used in a reaction to the channel the reaction is part of
- * reaction.message.channel.sendMessage(`The emoji used is ${reaction.emoji}`);
- * @returns {string}
- */
- toString() {
- return this.id ? `<:${this.name}:${this.id}>` : this.name;
- }
-}
-
-module.exports = ReactionEmoji;
-
-
-/***/ }),
-/* 31 */
-/***/ (function(module, exports, __webpack_require__) {
-
-const path = __webpack_require__(28);
-
-/**
- * Represents a webhook.
- */
-class Webhook {
- constructor(client, dataOrID, token) {
- if (client) {
- /**
- * The client that instantiated the webhook
- * @name Webhook#client
- * @type {Client}
- * @readonly
- */
- Object.defineProperty(this, 'client', { value: client });
- if (dataOrID) this.setup(dataOrID);
- } else {
- this.id = dataOrID;
- this.token = token;
- Object.defineProperty(this, 'client', { value: this });
+ function ondrain() {
+ if (source.readable && source.resume) {
+ source.resume();
}
}
- setup(data) {
- /**
- * The name of the webhook
- * @type {string}
- */
- this.name = data.name;
+ dest.on('drain', ondrain);
- /**
- * The token for the webhook
- * @type {string}
- */
- this.token = data.token;
+ // If the 'end' option is not supplied, dest.end() will be called when
+ // source gets the 'end' or 'close' events. Only dest.end() once.
+ if (!dest._isStdio && (!options || options.end !== false)) {
+ source.on('end', onend);
+ source.on('close', onclose);
+ }
- /**
- * The avatar for the webhook
- * @type {string}
- */
- this.avatar = data.avatar;
+ var didOnEnd = false;
+ function onend() {
+ if (didOnEnd) return;
+ didOnEnd = true;
- /**
- * The ID of the webhook
- * @type {Snowflake}
- */
- this.id = data.id;
+ dest.end();
+ }
- /**
- * The guild the webhook belongs to
- * @type {Snowflake}
- */
- this.guildID = data.guild_id;
- /**
- * The channel the webhook belongs to
- * @type {Snowflake}
- */
- this.channelID = data.channel_id;
+ function onclose() {
+ if (didOnEnd) return;
+ didOnEnd = true;
- if (data.user) {
- /**
- * The owner of the webhook
- * @type {?User|Object}
- */
- this.owner = this.client.users ? this.client.users.get(data.user.id) : data.user;
- } else {
- this.owner = null;
+ if (typeof dest.destroy === 'function') dest.destroy();
+ }
+
+ // don't leave dangling pipes when there are errors.
+ function onerror(er) {
+ cleanup();
+ if (EE.listenerCount(this, 'error') === 0) {
+ throw er; // Unhandled stream error in pipe.
}
}
- /**
- * Options that can be passed into send, sendMessage, sendFile, sendEmbed, and sendCode.
- * @typedef {Object} WebhookMessageOptions
- * @property {string} [username=this.name] Username override for the message
- * @property {string} [avatarURL] Avatar URL override for the message
- * @property {boolean} [tts=false] Whether or not the message should be spoken aloud
- * @property {string} [nonce=''] The nonce for the message
- * @property {Object[]} [embeds] An array of embeds for the message
- * (see [here](https://discordapp.com/developers/docs/resources/channel#embed-object) for more details)
- * @property {boolean} [disableEveryone=this.client.options.disableEveryone] Whether or not @everyone and @here
- * should be replaced with plain-text
- * @property {FileOptions|string} [file] A file to send with the message
- * @property {string|boolean} [code] Language for optional codeblock formatting to apply
- * @property {boolean|SplitOptions} [split=false] Whether or not the message should be split into multiple messages if
- * it exceeds the character limit. If an object is provided, these are the options for splitting the message.
- */
+ source.on('error', onerror);
+ dest.on('error', onerror);
- /**
- * Send a message with this webhook.
- * @param {StringResolvable} content The content to send
- * @param {WebhookMessageOptions} [options={}] The options to provide
- * @returns {Promise}
- * @example
- * // Send a message
- * webhook.send('hello!')
- * .then(message => console.log(`Sent message: ${message.content}`))
- * .catch(console.error);
- */
- send(content, options) {
- if (!options && typeof content === 'object' && !(content instanceof Array)) {
- options = content;
- content = '';
- } else if (!options) {
- options = {};
- }
- if (options.file) {
- if (options.files) options.files.push(options.file);
- else options.files = [options.file];
- }
+ // remove all the event listeners that were added.
+ function cleanup() {
+ source.removeListener('data', ondata);
+ dest.removeListener('drain', ondrain);
- if (options.files) {
- for (let i = 0; i < options.files.length; i++) {
- let file = options.files[i];
- if (typeof file === 'string') file = { attachment: file };
- if (!file.name) {
- if (typeof file.attachment === 'string') {
- file.name = path.basename(file.attachment);
- } else if (file.attachment && file.attachment.path) {
- file.name = path.basename(file.attachment.path);
- } else {
- file.name = 'file.jpg';
- }
- }
- }
- return this.client.resolver.resolveBuffer(options.file.attachment).then(file =>
- this.client.rest.methods.sendWebhookMessage(this, content, options, {
- file,
- name: options.file.name,
- })
- );
- }
- return this.client.rest.methods.sendWebhookMessage(this, content, options);
+ source.removeListener('end', onend);
+ source.removeListener('close', onclose);
+
+ source.removeListener('error', onerror);
+ dest.removeListener('error', onerror);
+
+ source.removeListener('end', cleanup);
+ source.removeListener('close', cleanup);
+
+ dest.removeListener('close', cleanup);
}
- /**
- * Send a message with this webhook
- * @param {StringResolvable} content The content to send
- * @param {WebhookMessageOptions} [options={}] The options to provide
- * @returns {Promise}
- * @deprecated
- * @example
- * // Send a message
- * webhook.sendMessage('hello!')
- * .then(message => console.log(`Sent message: ${message.content}`))
- * .catch(console.error);
- */
- sendMessage(content, options = {}) {
- return this.send(content, options);
- }
+ source.on('end', cleanup);
+ source.on('close', cleanup);
- /**
- * Send a file with this webhook.
- * @param {BufferResolvable} attachment The file to send
- * @param {string} [name='file.jpg'] The name and extension of the file
- * @param {StringResolvable} [content] Text message to send with the attachment
- * @param {WebhookMessageOptions} [options] The options to provide
- * @returns {Promise}
- * @deprecated
- */
- sendFile(attachment, name, content, options = {}) {
- return this.send(content, Object.assign(options, { file: { attachment, name } }));
- }
+ dest.on('close', cleanup);
- /**
- * Send a code block with this webhook.
- * @param {string} lang Language for the code block
- * @param {StringResolvable} content Content of the code block
- * @param {WebhookMessageOptions} options The options to provide
- * @returns {Promise}
- * @deprecated
- */
- sendCode(lang, content, options = {}) {
- return this.send(content, Object.assign(options, { code: lang }));
- }
+ dest.emit('pipe', source);
- /**
- * Send a raw slack message with this webhook.
- * @param {Object} body The raw body to send
- * @returns {Promise}
- * @example
- * // Send a slack message
- * webhook.sendSlackMessage({
- * 'username': 'Wumpus',
- * 'attachments': [{
- * 'pretext': 'this looks pretty cool',
- * 'color': '#F0F',
- * 'footer_icon': 'http://snek.s3.amazonaws.com/topSnek.png',
- * 'footer': 'Powered by sneks',
- * 'ts': Date.now() / 1000
- * }]
- * }).catch(console.error);
- */
- sendSlackMessage(body) {
- return this.client.rest.methods.sendSlackWebhookMessage(this, body);
- }
-
- /**
- * Edit the webhook.
- * @param {string} name The new name for the webhook
- * @param {BufferResolvable} avatar The new avatar for the webhook
- * @returns {Promise}
- */
- edit(name = this.name, avatar) {
- if (avatar) {
- return this.client.resolver.resolveBuffer(avatar).then(file => {
- const dataURI = this.client.resolver.resolveBase64(file);
- return this.client.rest.methods.editWebhook(this, name, dataURI);
- });
- }
- return this.client.rest.methods.editWebhook(this, name).then(data => {
- this.setup(data);
- return this;
- });
- }
-
- /**
- * Delete the webhook.
- * @returns {Promise}
- */
- delete() {
- return this.client.rest.methods.deleteWebhook(this);
- }
-}
-
-module.exports = Webhook;
+ // Allow for unix-like usage: A.pipe(B).pipe(C)
+ return dest;
+};
/***/ }),
/* 32 */
/***/ (function(module, exports, __webpack_require__) {
-const Collection = __webpack_require__(3);
-const EventEmitter = __webpack_require__(12).EventEmitter;
+/* eslint-disable node/no-deprecated-api */
+var buffer = __webpack_require__(5)
+var Buffer = buffer.Buffer
-/**
- * Filter to be applied to the collector.
- * @typedef {Function} CollectorFilter
- * @param {...*} args Any arguments received by the listener
- * @returns {boolean} To collect or not collect
- */
-
-/**
- * Options to be applied to the collector.
- * @typedef {Object} CollectorOptions
- * @property {number} [time] How long to run the collector for
- */
-
-/**
- * Abstract class for defining a new Collector.
- * @abstract
- */
-class Collector extends EventEmitter {
- constructor(client, filter, options = {}) {
- super();
-
- /**
- * The client
- * @name Collector#client
- * @type {Client}
- * @readonly
- */
- Object.defineProperty(this, 'client', { value: client });
-
- /**
- * The filter applied to this collector
- * @type {CollectorFilter}
- */
- this.filter = filter;
-
- /**
- * The options of this collector
- * @type {CollectorOptions}
- */
- this.options = options;
-
- /**
- * The items collected by this collector
- * @type {Collection}
- */
- this.collected = new Collection();
-
- /**
- * Whether this collector has finished collecting
- * @type {boolean}
- */
- this.ended = false;
-
- /**
- * Timeout for cleanup
- * @type {?Timeout}
- * @private
- */
- this._timeout = null;
-
- /**
- * Call this to handle an event as a collectable element
- * Accepts any event data as parameters
- * @type {Function}
- * @private
- */
- this.listener = this._handle.bind(this);
- if (options.time) this._timeout = this.client.setTimeout(() => this.stop('time'), options.time);
+// alternative to using Object.keys for old browsers
+function copyProps (src, dst) {
+ for (var key in src) {
+ dst[key] = src[key]
}
-
- /**
- * @param {...*} args The arguments emitted by the listener
- * @emits Collector#collect
- * @private
- */
- _handle(...args) {
- const collect = this.handle(...args);
- if (!collect || !this.filter(...args)) return;
-
- this.collected.set(collect.key, collect.value);
-
- /**
- * Emitted whenever an element is collected.
- * @event Collector#collect
- * @param {*} element The element that got collected
- * @param {Collector} collector The collector
- */
- this.emit('collect', collect.value, this);
-
- const post = this.postCheck(...args);
- if (post) this.stop(post);
- }
-
- /**
- * Return a promise that resolves with the next collected element;
- * rejects with collected elements if the collector finishes without receving a next element
- * @type {Promise}
- * @readonly
- */
- get next() {
- return new Promise((resolve, reject) => {
- if (this.ended) {
- reject(this.collected);
- return;
- }
-
- const cleanup = () => {
- this.removeListener('collect', onCollect);
- this.removeListener('end', onEnd);
- };
-
- const onCollect = item => {
- cleanup();
- resolve(item);
- };
-
- const onEnd = () => {
- cleanup();
- reject(this.collected); // eslint-disable-line prefer-promise-reject-errors
- };
-
- this.on('collect', onCollect);
- this.on('end', onEnd);
- });
- }
-
- /**
- * Stop this collector and emit the `end` event.
- * @param {string} [reason='user'] The reason this collector is ending
- * @emits Collector#end
- */
- stop(reason = 'user') {
- if (this.ended) return;
-
- if (this._timeout) this.client.clearTimeout(this._timeout);
- this.ended = true;
- this.cleanup();
-
- /**
- * Emitted when the collector is finished collecting.
- * @event Collector#end
- * @param {Collection} collected The elements collected by the collector
- * @param {string} reason The reason the collector ended
- */
- this.emit('end', this.collected, reason);
- }
-
- /* eslint-disable no-empty-function, valid-jsdoc */
- /**
- * Handles incoming events from the `listener` function. Returns null if the event should not be collected,
- * or returns an object describing the data that should be stored.
- * @see Collector#listener
- * @param {...*} args Any args the event listener emits
- * @returns {?{key: string, value}} Data to insert into collection, if any
- * @abstract
- */
- handle() {}
-
- /**
- * This method runs after collection to see if the collector should finish.
- * @param {...*} args Any args the event listener emits
- * @returns {?string} Reason to end the collector, if any
- * @abstract
- */
- postCheck() {}
-
- /**
- * Called when the collector is ending.
- * @abstract
- */
- cleanup() {}
- /* eslint-enable no-empty-function, valid-jsdoc */
+}
+if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) {
+ module.exports = buffer
+} else {
+ // Copy properties from require('buffer')
+ copyProps(buffer, exports)
+ exports.Buffer = SafeBuffer
}
-module.exports = Collector;
+function SafeBuffer (arg, encodingOrOffset, length) {
+ return Buffer(arg, encodingOrOffset, length)
+}
+
+// Copy static methods from Buffer
+copyProps(Buffer, SafeBuffer)
+
+SafeBuffer.from = function (arg, encodingOrOffset, length) {
+ if (typeof arg === 'number') {
+ throw new TypeError('Argument must not be a number')
+ }
+ return Buffer(arg, encodingOrOffset, length)
+}
+
+SafeBuffer.alloc = function (size, fill, encoding) {
+ if (typeof size !== 'number') {
+ throw new TypeError('Argument must be a number')
+ }
+ var buf = Buffer(size)
+ if (fill !== undefined) {
+ if (typeof encoding === 'string') {
+ buf.fill(fill, encoding)
+ } else {
+ buf.fill(fill)
+ }
+ } else {
+ buf.fill(0)
+ }
+ return buf
+}
+
+SafeBuffer.allocUnsafe = function (size) {
+ if (typeof size !== 'number') {
+ throw new TypeError('Argument must be a number')
+ }
+ return Buffer(size)
+}
+
+SafeBuffer.allocUnsafeSlow = function (size) {
+ if (typeof size !== 'number') {
+ throw new TypeError('Argument must be a number')
+ }
+ return buffer.SlowBuffer(size)
+}
/***/ }),
/* 33 */
/***/ (function(module, exports, __webpack_require__) {
+"use strict";
+/* WEBPACK VAR INJECTION */(function(process, setImmediate, global) {// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// A bit simpler than readable streams.
+// Implement an async ._write(chunk, encoding, cb), and it'll handle all
+// the drain event emission and buffering.
+
+
+
+/**/
+
+var processNextTick = __webpack_require__(25);
+/**/
+
+module.exports = Writable;
+
+/* */
+function WriteReq(chunk, encoding, cb) {
+ this.chunk = chunk;
+ this.encoding = encoding;
+ this.callback = cb;
+ this.next = null;
+}
+
+// It seems a linked list but it is not
+// there will be only 2 of these for each stream
+function CorkedRequest(state) {
+ var _this = this;
+
+ this.next = null;
+ this.entry = null;
+ this.finish = function () {
+ onCorkedFinish(_this, state);
+ };
+}
+/* */
+
+/**/
+var asyncWrite = !process.browser && ['v0.10', 'v0.9.'].indexOf(process.version.slice(0, 5)) > -1 ? setImmediate : processNextTick;
+/**/
+
+/**/
+var Duplex;
+/**/
+
+Writable.WritableState = WritableState;
+
+/**/
+var util = __webpack_require__(18);
+util.inherits = __webpack_require__(10);
+/**/
+
+/**/
+var internalUtil = {
+ deprecate: __webpack_require__(81)
+};
+/**/
+
+/**/
+var Stream = __webpack_require__(45);
+/**/
+
+/**/
+var Buffer = __webpack_require__(32).Buffer;
+var OurUint8Array = global.Uint8Array || function () {};
+function _uint8ArrayToBuffer(chunk) {
+ return Buffer.from(chunk);
+}
+function _isUint8Array(obj) {
+ return Buffer.isBuffer(obj) || obj instanceof OurUint8Array;
+}
+/**/
+
+var destroyImpl = __webpack_require__(46);
+
+util.inherits(Writable, Stream);
+
+function nop() {}
+
+function WritableState(options, stream) {
+ Duplex = Duplex || __webpack_require__(12);
+
+ options = options || {};
+
+ // object stream flag to indicate whether or not this stream
+ // contains buffers or objects.
+ this.objectMode = !!options.objectMode;
+
+ if (stream instanceof Duplex) this.objectMode = this.objectMode || !!options.writableObjectMode;
+
+ // the point at which write() starts returning false
+ // Note: 0 is a valid value, means that we always return false if
+ // the entire buffer is not flushed immediately on write()
+ var hwm = options.highWaterMark;
+ var defaultHwm = this.objectMode ? 16 : 16 * 1024;
+ this.highWaterMark = hwm || hwm === 0 ? hwm : defaultHwm;
+
+ // cast to ints.
+ this.highWaterMark = Math.floor(this.highWaterMark);
+
+ // if _final has been called
+ this.finalCalled = false;
+
+ // drain event flag.
+ this.needDrain = false;
+ // at the start of calling end()
+ this.ending = false;
+ // when end() has been called, and returned
+ this.ended = false;
+ // when 'finish' is emitted
+ this.finished = false;
+
+ // has it been destroyed
+ this.destroyed = false;
+
+ // should we decode strings into buffers before passing to _write?
+ // this is here so that some node-core streams can optimize string
+ // handling at a lower level.
+ var noDecode = options.decodeStrings === false;
+ this.decodeStrings = !noDecode;
+
+ // Crypto is kind of old and crusty. Historically, its default string
+ // encoding is 'binary' so we have to make this configurable.
+ // Everything else in the universe uses 'utf8', though.
+ this.defaultEncoding = options.defaultEncoding || 'utf8';
+
+ // not an actual buffer we keep track of, but a measurement
+ // of how much we're waiting to get pushed to some underlying
+ // socket or file.
+ this.length = 0;
+
+ // a flag to see when we're in the middle of a write.
+ this.writing = false;
+
+ // when true all writes will be buffered until .uncork() call
+ this.corked = 0;
+
+ // a flag to be able to tell if the onwrite cb is called immediately,
+ // or on a later tick. We set this to true at first, because any
+ // actions that shouldn't happen until "later" should generally also
+ // not happen before the first write call.
+ this.sync = true;
+
+ // a flag to know if we're processing previously buffered items, which
+ // may call the _write() callback in the same tick, so that we don't
+ // end up in an overlapped onwrite situation.
+ this.bufferProcessing = false;
+
+ // the callback that's passed to _write(chunk,cb)
+ this.onwrite = function (er) {
+ onwrite(stream, er);
+ };
+
+ // the callback that the user supplies to write(chunk,encoding,cb)
+ this.writecb = null;
+
+ // the amount that is being written when _write is called.
+ this.writelen = 0;
+
+ this.bufferedRequest = null;
+ this.lastBufferedRequest = null;
+
+ // number of pending user-supplied write callbacks
+ // this must be 0 before 'finish' can be emitted
+ this.pendingcb = 0;
+
+ // emit prefinish if the only thing we're waiting for is _write cbs
+ // This is relevant for synchronous Transform streams
+ this.prefinished = false;
+
+ // True if the error was already emitted and should not be thrown again
+ this.errorEmitted = false;
+
+ // count buffered requests
+ this.bufferedRequestCount = 0;
+
+ // allocate the first CorkedRequest, there is always
+ // one allocated and free to use, and we maintain at most two
+ this.corkedRequestsFree = new CorkedRequest(this);
+}
+
+WritableState.prototype.getBuffer = function getBuffer() {
+ var current = this.bufferedRequest;
+ var out = [];
+ while (current) {
+ out.push(current);
+ current = current.next;
+ }
+ return out;
+};
+
+(function () {
+ try {
+ Object.defineProperty(WritableState.prototype, 'buffer', {
+ get: internalUtil.deprecate(function () {
+ return this.getBuffer();
+ }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.', 'DEP0003')
+ });
+ } catch (_) {}
+})();
+
+// Test _writableState for inheritance to account for Duplex streams,
+// whose prototype chain only points to Readable.
+var realHasInstance;
+if (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === 'function') {
+ realHasInstance = Function.prototype[Symbol.hasInstance];
+ Object.defineProperty(Writable, Symbol.hasInstance, {
+ value: function (object) {
+ if (realHasInstance.call(this, object)) return true;
+
+ return object && object._writableState instanceof WritableState;
+ }
+ });
+} else {
+ realHasInstance = function (object) {
+ return object instanceof this;
+ };
+}
+
+function Writable(options) {
+ Duplex = Duplex || __webpack_require__(12);
+
+ // Writable ctor is applied to Duplexes, too.
+ // `realHasInstance` is necessary because using plain `instanceof`
+ // would return false, as no `_writableState` property is attached.
+
+ // Trying to use the custom `instanceof` for Writable here will also break the
+ // Node.js LazyTransform implementation, which has a non-trivial getter for
+ // `_writableState` that would lead to infinite recursion.
+ if (!realHasInstance.call(Writable, this) && !(this instanceof Duplex)) {
+ return new Writable(options);
+ }
+
+ this._writableState = new WritableState(options, this);
+
+ // legacy.
+ this.writable = true;
+
+ if (options) {
+ if (typeof options.write === 'function') this._write = options.write;
+
+ if (typeof options.writev === 'function') this._writev = options.writev;
+
+ if (typeof options.destroy === 'function') this._destroy = options.destroy;
+
+ if (typeof options.final === 'function') this._final = options.final;
+ }
+
+ Stream.call(this);
+}
+
+// Otherwise people can pipe Writable streams, which is just wrong.
+Writable.prototype.pipe = function () {
+ this.emit('error', new Error('Cannot pipe, not readable'));
+};
+
+function writeAfterEnd(stream, cb) {
+ var er = new Error('write after end');
+ // TODO: defer error events consistently everywhere, not just the cb
+ stream.emit('error', er);
+ processNextTick(cb, er);
+}
+
+// Checks that a user-supplied chunk is valid, especially for the particular
+// mode the stream is in. Currently this means that `null` is never accepted
+// and undefined/non-string values are only allowed in object mode.
+function validChunk(stream, state, chunk, cb) {
+ var valid = true;
+ var er = false;
+
+ if (chunk === null) {
+ er = new TypeError('May not write null values to stream');
+ } else if (typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) {
+ er = new TypeError('Invalid non-string/buffer chunk');
+ }
+ if (er) {
+ stream.emit('error', er);
+ processNextTick(cb, er);
+ valid = false;
+ }
+ return valid;
+}
+
+Writable.prototype.write = function (chunk, encoding, cb) {
+ var state = this._writableState;
+ var ret = false;
+ var isBuf = _isUint8Array(chunk) && !state.objectMode;
+
+ if (isBuf && !Buffer.isBuffer(chunk)) {
+ chunk = _uint8ArrayToBuffer(chunk);
+ }
+
+ if (typeof encoding === 'function') {
+ cb = encoding;
+ encoding = null;
+ }
+
+ if (isBuf) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding;
+
+ if (typeof cb !== 'function') cb = nop;
+
+ if (state.ended) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) {
+ state.pendingcb++;
+ ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb);
+ }
+
+ return ret;
+};
+
+Writable.prototype.cork = function () {
+ var state = this._writableState;
+
+ state.corked++;
+};
+
+Writable.prototype.uncork = function () {
+ var state = this._writableState;
+
+ if (state.corked) {
+ state.corked--;
+
+ if (!state.writing && !state.corked && !state.finished && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state);
+ }
+};
+
+Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) {
+ // node::ParseEncoding() requires lower case.
+ if (typeof encoding === 'string') encoding = encoding.toLowerCase();
+ if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new TypeError('Unknown encoding: ' + encoding);
+ this._writableState.defaultEncoding = encoding;
+ return this;
+};
+
+function decodeChunk(state, chunk, encoding) {
+ if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') {
+ chunk = Buffer.from(chunk, encoding);
+ }
+ return chunk;
+}
+
+// if we're already writing something, then just put this
+// in the queue, and wait our turn. Otherwise, call _write
+// If we return false, then we need a drain event, so set that flag.
+function writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) {
+ if (!isBuf) {
+ var newChunk = decodeChunk(state, chunk, encoding);
+ if (chunk !== newChunk) {
+ isBuf = true;
+ encoding = 'buffer';
+ chunk = newChunk;
+ }
+ }
+ var len = state.objectMode ? 1 : chunk.length;
+
+ state.length += len;
+
+ var ret = state.length < state.highWaterMark;
+ // we must ensure that previous needDrain will not be reset to false.
+ if (!ret) state.needDrain = true;
+
+ if (state.writing || state.corked) {
+ var last = state.lastBufferedRequest;
+ state.lastBufferedRequest = {
+ chunk: chunk,
+ encoding: encoding,
+ isBuf: isBuf,
+ callback: cb,
+ next: null
+ };
+ if (last) {
+ last.next = state.lastBufferedRequest;
+ } else {
+ state.bufferedRequest = state.lastBufferedRequest;
+ }
+ state.bufferedRequestCount += 1;
+ } else {
+ doWrite(stream, state, false, len, chunk, encoding, cb);
+ }
+
+ return ret;
+}
+
+function doWrite(stream, state, writev, len, chunk, encoding, cb) {
+ state.writelen = len;
+ state.writecb = cb;
+ state.writing = true;
+ state.sync = true;
+ if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite);
+ state.sync = false;
+}
+
+function onwriteError(stream, state, sync, er, cb) {
+ --state.pendingcb;
+
+ if (sync) {
+ // defer the callback if we are being called synchronously
+ // to avoid piling up things on the stack
+ processNextTick(cb, er);
+ // this can emit finish, and it will always happen
+ // after error
+ processNextTick(finishMaybe, stream, state);
+ stream._writableState.errorEmitted = true;
+ stream.emit('error', er);
+ } else {
+ // the caller expect this to happen before if
+ // it is async
+ cb(er);
+ stream._writableState.errorEmitted = true;
+ stream.emit('error', er);
+ // this can emit finish, but finish must
+ // always follow error
+ finishMaybe(stream, state);
+ }
+}
+
+function onwriteStateUpdate(state) {
+ state.writing = false;
+ state.writecb = null;
+ state.length -= state.writelen;
+ state.writelen = 0;
+}
+
+function onwrite(stream, er) {
+ var state = stream._writableState;
+ var sync = state.sync;
+ var cb = state.writecb;
+
+ onwriteStateUpdate(state);
+
+ if (er) onwriteError(stream, state, sync, er, cb);else {
+ // Check if we're actually ready to finish, but don't emit yet
+ var finished = needFinish(state);
+
+ if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) {
+ clearBuffer(stream, state);
+ }
+
+ if (sync) {
+ /**/
+ asyncWrite(afterWrite, stream, state, finished, cb);
+ /**/
+ } else {
+ afterWrite(stream, state, finished, cb);
+ }
+ }
+}
+
+function afterWrite(stream, state, finished, cb) {
+ if (!finished) onwriteDrain(stream, state);
+ state.pendingcb--;
+ cb();
+ finishMaybe(stream, state);
+}
+
+// Must force callback to be called on nextTick, so that we don't
+// emit 'drain' before the write() consumer gets the 'false' return
+// value, and has a chance to attach a 'drain' listener.
+function onwriteDrain(stream, state) {
+ if (state.length === 0 && state.needDrain) {
+ state.needDrain = false;
+ stream.emit('drain');
+ }
+}
+
+// if there's something in the buffer waiting, then process it
+function clearBuffer(stream, state) {
+ state.bufferProcessing = true;
+ var entry = state.bufferedRequest;
+
+ if (stream._writev && entry && entry.next) {
+ // Fast case, write everything using _writev()
+ var l = state.bufferedRequestCount;
+ var buffer = new Array(l);
+ var holder = state.corkedRequestsFree;
+ holder.entry = entry;
+
+ var count = 0;
+ var allBuffers = true;
+ while (entry) {
+ buffer[count] = entry;
+ if (!entry.isBuf) allBuffers = false;
+ entry = entry.next;
+ count += 1;
+ }
+ buffer.allBuffers = allBuffers;
+
+ doWrite(stream, state, true, state.length, buffer, '', holder.finish);
+
+ // doWrite is almost always async, defer these to save a bit of time
+ // as the hot path ends with doWrite
+ state.pendingcb++;
+ state.lastBufferedRequest = null;
+ if (holder.next) {
+ state.corkedRequestsFree = holder.next;
+ holder.next = null;
+ } else {
+ state.corkedRequestsFree = new CorkedRequest(state);
+ }
+ } else {
+ // Slow case, write chunks one-by-one
+ while (entry) {
+ var chunk = entry.chunk;
+ var encoding = entry.encoding;
+ var cb = entry.callback;
+ var len = state.objectMode ? 1 : chunk.length;
+
+ doWrite(stream, state, false, len, chunk, encoding, cb);
+ entry = entry.next;
+ // if we didn't call the onwrite immediately, then
+ // it means that we need to wait until it does.
+ // also, that means that the chunk and cb are currently
+ // being processed, so move the buffer counter past them.
+ if (state.writing) {
+ break;
+ }
+ }
+
+ if (entry === null) state.lastBufferedRequest = null;
+ }
+
+ state.bufferedRequestCount = 0;
+ state.bufferedRequest = entry;
+ state.bufferProcessing = false;
+}
+
+Writable.prototype._write = function (chunk, encoding, cb) {
+ cb(new Error('_write() is not implemented'));
+};
+
+Writable.prototype._writev = null;
+
+Writable.prototype.end = function (chunk, encoding, cb) {
+ var state = this._writableState;
+
+ if (typeof chunk === 'function') {
+ cb = chunk;
+ chunk = null;
+ encoding = null;
+ } else if (typeof encoding === 'function') {
+ cb = encoding;
+ encoding = null;
+ }
+
+ if (chunk !== null && chunk !== undefined) this.write(chunk, encoding);
+
+ // .end() fully uncorks
+ if (state.corked) {
+ state.corked = 1;
+ this.uncork();
+ }
+
+ // ignore unnecessary end() calls.
+ if (!state.ending && !state.finished) endWritable(this, state, cb);
+};
+
+function needFinish(state) {
+ return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing;
+}
+function callFinal(stream, state) {
+ stream._final(function (err) {
+ state.pendingcb--;
+ if (err) {
+ stream.emit('error', err);
+ }
+ state.prefinished = true;
+ stream.emit('prefinish');
+ finishMaybe(stream, state);
+ });
+}
+function prefinish(stream, state) {
+ if (!state.prefinished && !state.finalCalled) {
+ if (typeof stream._final === 'function') {
+ state.pendingcb++;
+ state.finalCalled = true;
+ processNextTick(callFinal, stream, state);
+ } else {
+ state.prefinished = true;
+ stream.emit('prefinish');
+ }
+ }
+}
+
+function finishMaybe(stream, state) {
+ var need = needFinish(state);
+ if (need) {
+ prefinish(stream, state);
+ if (state.pendingcb === 0) {
+ state.finished = true;
+ stream.emit('finish');
+ }
+ }
+ return need;
+}
+
+function endWritable(stream, state, cb) {
+ state.ending = true;
+ finishMaybe(stream, state);
+ if (cb) {
+ if (state.finished) processNextTick(cb);else stream.once('finish', cb);
+ }
+ state.ended = true;
+ stream.writable = false;
+}
+
+function onCorkedFinish(corkReq, state, err) {
+ var entry = corkReq.entry;
+ corkReq.entry = null;
+ while (entry) {
+ var cb = entry.callback;
+ state.pendingcb--;
+ cb(err);
+ entry = entry.next;
+ }
+ if (state.corkedRequestsFree) {
+ state.corkedRequestsFree.next = corkReq;
+ } else {
+ state.corkedRequestsFree = corkReq;
+ }
+}
+
+Object.defineProperty(Writable.prototype, 'destroyed', {
+ get: function () {
+ if (this._writableState === undefined) {
+ return false;
+ }
+ return this._writableState.destroyed;
+ },
+ set: function (value) {
+ // we ignore the value if the stream
+ // has not been initialized yet
+ if (!this._writableState) {
+ return;
+ }
+
+ // backward compatibility, the user is explicitly
+ // managing destroyed
+ this._writableState.destroyed = value;
+ }
+});
+
+Writable.prototype.destroy = destroyImpl.destroy;
+Writable.prototype._undestroy = destroyImpl.undestroy;
+Writable.prototype._destroy = function (err, cb) {
+ this.end();
+ cb(err);
+};
+/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7), __webpack_require__(79).setImmediate, __webpack_require__(6)))
+
+/***/ }),
+/* 34 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+exports.decode = exports.parse = __webpack_require__(87);
+exports.encode = exports.stringify = __webpack_require__(88);
+
+
+/***/ }),
+/* 35 */
+/***/ (function(module, exports, __webpack_require__) {
+
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*
Copyright 2013 Daniel Wirtz
Copyright 2009 The Closure Library Authors. All Rights Reserved.
@@ -11274,714 +11559,879 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
});
-/***/ }),
-/* 34 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-/* WEBPACK VAR INJECTION */(function(process) {
-
-if (!process.version ||
- process.version.indexOf('v0.') === 0 ||
- process.version.indexOf('v1.') === 0 && process.version.indexOf('v1.8.') !== 0) {
- module.exports = nextTick;
-} else {
- module.exports = process.nextTick;
-}
-
-function nextTick(fn, arg1, arg2, arg3) {
- if (typeof fn !== 'function') {
- throw new TypeError('"callback" argument must be a function');
- }
- var len = arguments.length;
- var args, i;
- switch (len) {
- case 0:
- case 1:
- return process.nextTick(fn);
- case 2:
- return process.nextTick(function afterTickOne() {
- fn.call(null, arg1);
- });
- case 3:
- return process.nextTick(function afterTickTwo() {
- fn.call(null, arg1, arg2);
- });
- case 4:
- return process.nextTick(function afterTickThree() {
- fn.call(null, arg1, arg2, arg3);
- });
- default:
- args = new Array(len - 1);
- i = 0;
- while (i < args.length) {
- args[i++] = arguments[i];
- }
- return process.nextTick(function afterTick() {
- fn.apply(null, args);
- });
- }
-}
-
-/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7)))
-
-/***/ }),
-/* 35 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-exports.decode = exports.parse = __webpack_require__(82);
-exports.encode = exports.stringify = __webpack_require__(83);
-
-
/***/ }),
/* 36 */
-/***/ (function(module, exports, __webpack_require__) {
+/***/ (function(module, exports) {
-"use strict";
-/* WEBPACK VAR INJECTION */(function(process, setImmediate) {// A bit simpler than readable streams.
-// Implement an async ._write(chunk, encoding, cb), and it'll handle all
-// the drain event emission and buffering.
+/**
+ * Represents a limited emoji set used for both custom and unicode emojis. Custom emojis
+ * will use this class opposed to the Emoji class when the client doesn't know enough
+ * information about them.
+ */
+class ReactionEmoji {
+ constructor(reaction, name, id) {
+ /**
+ * The message reaction this emoji refers to
+ * @type {MessageReaction}
+ */
+ this.reaction = reaction;
+ /**
+ * The name of this reaction emoji
+ * @type {string}
+ */
+ this.name = name;
-
-module.exports = Writable;
-
-/**/
-var processNextTick = __webpack_require__(34);
-/**/
-
-/**/
-var asyncWrite = !process.browser && ['v0.10', 'v0.9.'].indexOf(process.version.slice(0, 5)) > -1 ? setImmediate : processNextTick;
-/**/
-
-/**/
-var Duplex;
-/**/
-
-Writable.WritableState = WritableState;
-
-/**/
-var util = __webpack_require__(20);
-util.inherits = __webpack_require__(10);
-/**/
-
-/**/
-var internalUtil = {
- deprecate: __webpack_require__(102)
-};
-/**/
-
-/**/
-var Stream = __webpack_require__(61);
-/**/
-
-/**/
-var Buffer = __webpack_require__(37).Buffer;
-/**/
-
-util.inherits(Writable, Stream);
-
-function nop() {}
-
-function WriteReq(chunk, encoding, cb) {
- this.chunk = chunk;
- this.encoding = encoding;
- this.callback = cb;
- this.next = null;
-}
-
-function WritableState(options, stream) {
- Duplex = Duplex || __webpack_require__(13);
-
- options = options || {};
-
- // object stream flag to indicate whether or not this stream
- // contains buffers or objects.
- this.objectMode = !!options.objectMode;
-
- if (stream instanceof Duplex) this.objectMode = this.objectMode || !!options.writableObjectMode;
-
- // the point at which write() starts returning false
- // Note: 0 is a valid value, means that we always return false if
- // the entire buffer is not flushed immediately on write()
- var hwm = options.highWaterMark;
- var defaultHwm = this.objectMode ? 16 : 16 * 1024;
- this.highWaterMark = hwm || hwm === 0 ? hwm : defaultHwm;
-
- // cast to ints.
- this.highWaterMark = ~~this.highWaterMark;
-
- // drain event flag.
- this.needDrain = false;
- // at the start of calling end()
- this.ending = false;
- // when end() has been called, and returned
- this.ended = false;
- // when 'finish' is emitted
- this.finished = false;
-
- // should we decode strings into buffers before passing to _write?
- // this is here so that some node-core streams can optimize string
- // handling at a lower level.
- var noDecode = options.decodeStrings === false;
- this.decodeStrings = !noDecode;
-
- // Crypto is kind of old and crusty. Historically, its default string
- // encoding is 'binary' so we have to make this configurable.
- // Everything else in the universe uses 'utf8', though.
- this.defaultEncoding = options.defaultEncoding || 'utf8';
-
- // not an actual buffer we keep track of, but a measurement
- // of how much we're waiting to get pushed to some underlying
- // socket or file.
- this.length = 0;
-
- // a flag to see when we're in the middle of a write.
- this.writing = false;
-
- // when true all writes will be buffered until .uncork() call
- this.corked = 0;
-
- // a flag to be able to tell if the onwrite cb is called immediately,
- // or on a later tick. We set this to true at first, because any
- // actions that shouldn't happen until "later" should generally also
- // not happen before the first write call.
- this.sync = true;
-
- // a flag to know if we're processing previously buffered items, which
- // may call the _write() callback in the same tick, so that we don't
- // end up in an overlapped onwrite situation.
- this.bufferProcessing = false;
-
- // the callback that's passed to _write(chunk,cb)
- this.onwrite = function (er) {
- onwrite(stream, er);
- };
-
- // the callback that the user supplies to write(chunk,encoding,cb)
- this.writecb = null;
-
- // the amount that is being written when _write is called.
- this.writelen = 0;
-
- this.bufferedRequest = null;
- this.lastBufferedRequest = null;
-
- // number of pending user-supplied write callbacks
- // this must be 0 before 'finish' can be emitted
- this.pendingcb = 0;
-
- // emit prefinish if the only thing we're waiting for is _write cbs
- // This is relevant for synchronous Transform streams
- this.prefinished = false;
-
- // True if the error was already emitted and should not be thrown again
- this.errorEmitted = false;
-
- // count buffered requests
- this.bufferedRequestCount = 0;
-
- // allocate the first CorkedRequest, there is always
- // one allocated and free to use, and we maintain at most two
- this.corkedRequestsFree = new CorkedRequest(this);
-}
-
-WritableState.prototype.getBuffer = function getBuffer() {
- var current = this.bufferedRequest;
- var out = [];
- while (current) {
- out.push(current);
- current = current.next;
- }
- return out;
-};
-
-(function () {
- try {
- Object.defineProperty(WritableState.prototype, 'buffer', {
- get: internalUtil.deprecate(function () {
- return this.getBuffer();
- }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.')
- });
- } catch (_) {}
-})();
-
-// Test _writableState for inheritance to account for Duplex streams,
-// whose prototype chain only points to Readable.
-var realHasInstance;
-if (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === 'function') {
- realHasInstance = Function.prototype[Symbol.hasInstance];
- Object.defineProperty(Writable, Symbol.hasInstance, {
- value: function (object) {
- if (realHasInstance.call(this, object)) return true;
-
- return object && object._writableState instanceof WritableState;
- }
- });
-} else {
- realHasInstance = function (object) {
- return object instanceof this;
- };
-}
-
-function Writable(options) {
- Duplex = Duplex || __webpack_require__(13);
-
- // Writable ctor is applied to Duplexes, too.
- // `realHasInstance` is necessary because using plain `instanceof`
- // would return false, as no `_writableState` property is attached.
-
- // Trying to use the custom `instanceof` for Writable here will also break the
- // Node.js LazyTransform implementation, which has a non-trivial getter for
- // `_writableState` that would lead to infinite recursion.
- if (!realHasInstance.call(Writable, this) && !(this instanceof Duplex)) {
- return new Writable(options);
+ /**
+ * The ID of this reaction emoji
+ * @type {?Snowflake}
+ */
+ this.id = id;
}
- this._writableState = new WritableState(options, this);
-
- // legacy.
- this.writable = true;
-
- if (options) {
- if (typeof options.write === 'function') this._write = options.write;
-
- if (typeof options.writev === 'function') this._writev = options.writev;
+ /**
+ * The identifier of this emoji, used for message reactions
+ * @type {string}
+ * @readonly
+ */
+ get identifier() {
+ if (this.id) return `${this.name}:${this.id}`;
+ return encodeURIComponent(this.name);
}
- Stream.call(this);
-}
-
-// Otherwise people can pipe Writable streams, which is just wrong.
-Writable.prototype.pipe = function () {
- this.emit('error', new Error('Cannot pipe, not readable'));
-};
-
-function writeAfterEnd(stream, cb) {
- var er = new Error('write after end');
- // TODO: defer error events consistently everywhere, not just the cb
- stream.emit('error', er);
- processNextTick(cb, er);
-}
-
-// Checks that a user-supplied chunk is valid, especially for the particular
-// mode the stream is in. Currently this means that `null` is never accepted
-// and undefined/non-string values are only allowed in object mode.
-function validChunk(stream, state, chunk, cb) {
- var valid = true;
- var er = false;
-
- if (chunk === null) {
- er = new TypeError('May not write null values to stream');
- } else if (typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) {
- er = new TypeError('Invalid non-string/buffer chunk');
- }
- if (er) {
- stream.emit('error', er);
- processNextTick(cb, er);
- valid = false;
- }
- return valid;
-}
-
-Writable.prototype.write = function (chunk, encoding, cb) {
- var state = this._writableState;
- var ret = false;
- var isBuf = Buffer.isBuffer(chunk);
-
- if (typeof encoding === 'function') {
- cb = encoding;
- encoding = null;
- }
-
- if (isBuf) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding;
-
- if (typeof cb !== 'function') cb = nop;
-
- if (state.ended) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) {
- state.pendingcb++;
- ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb);
- }
-
- return ret;
-};
-
-Writable.prototype.cork = function () {
- var state = this._writableState;
-
- state.corked++;
-};
-
-Writable.prototype.uncork = function () {
- var state = this._writableState;
-
- if (state.corked) {
- state.corked--;
-
- if (!state.writing && !state.corked && !state.finished && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state);
- }
-};
-
-Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) {
- // node::ParseEncoding() requires lower case.
- if (typeof encoding === 'string') encoding = encoding.toLowerCase();
- if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new TypeError('Unknown encoding: ' + encoding);
- this._writableState.defaultEncoding = encoding;
- return this;
-};
-
-function decodeChunk(state, chunk, encoding) {
- if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') {
- chunk = Buffer.from(chunk, encoding);
- }
- return chunk;
-}
-
-// if we're already writing something, then just put this
-// in the queue, and wait our turn. Otherwise, call _write
-// If we return false, then we need a drain event, so set that flag.
-function writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) {
- if (!isBuf) {
- chunk = decodeChunk(state, chunk, encoding);
- if (Buffer.isBuffer(chunk)) encoding = 'buffer';
- }
- var len = state.objectMode ? 1 : chunk.length;
-
- state.length += len;
-
- var ret = state.length < state.highWaterMark;
- // we must ensure that previous needDrain will not be reset to false.
- if (!ret) state.needDrain = true;
-
- if (state.writing || state.corked) {
- var last = state.lastBufferedRequest;
- state.lastBufferedRequest = new WriteReq(chunk, encoding, cb);
- if (last) {
- last.next = state.lastBufferedRequest;
- } else {
- state.bufferedRequest = state.lastBufferedRequest;
- }
- state.bufferedRequestCount += 1;
- } else {
- doWrite(stream, state, false, len, chunk, encoding, cb);
- }
-
- return ret;
-}
-
-function doWrite(stream, state, writev, len, chunk, encoding, cb) {
- state.writelen = len;
- state.writecb = cb;
- state.writing = true;
- state.sync = true;
- if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite);
- state.sync = false;
-}
-
-function onwriteError(stream, state, sync, er, cb) {
- --state.pendingcb;
- if (sync) processNextTick(cb, er);else cb(er);
-
- stream._writableState.errorEmitted = true;
- stream.emit('error', er);
-}
-
-function onwriteStateUpdate(state) {
- state.writing = false;
- state.writecb = null;
- state.length -= state.writelen;
- state.writelen = 0;
-}
-
-function onwrite(stream, er) {
- var state = stream._writableState;
- var sync = state.sync;
- var cb = state.writecb;
-
- onwriteStateUpdate(state);
-
- if (er) onwriteError(stream, state, sync, er, cb);else {
- // Check if we're actually ready to finish, but don't emit yet
- var finished = needFinish(state);
-
- if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) {
- clearBuffer(stream, state);
- }
-
- if (sync) {
- /**/
- asyncWrite(afterWrite, stream, state, finished, cb);
- /**/
- } else {
- afterWrite(stream, state, finished, cb);
- }
+ /**
+ * Creates the text required to form a graphical emoji on Discord.
+ * @example
+ * // Send the emoji used in a reaction to the channel the reaction is part of
+ * reaction.message.channel.sendMessage(`The emoji used is ${reaction.emoji}`);
+ * @returns {string}
+ */
+ toString() {
+ return this.id ? `<:${this.name}:${this.id}>` : this.name;
}
}
-function afterWrite(stream, state, finished, cb) {
- if (!finished) onwriteDrain(stream, state);
- state.pendingcb--;
- cb();
- finishMaybe(stream, state);
-}
+module.exports = ReactionEmoji;
-// Must force callback to be called on nextTick, so that we don't
-// emit 'drain' before the write() consumer gets the 'false' return
-// value, and has a chance to attach a 'drain' listener.
-function onwriteDrain(stream, state) {
- if (state.length === 0 && state.needDrain) {
- state.needDrain = false;
- stream.emit('drain');
- }
-}
-
-// if there's something in the buffer waiting, then process it
-function clearBuffer(stream, state) {
- state.bufferProcessing = true;
- var entry = state.bufferedRequest;
-
- if (stream._writev && entry && entry.next) {
- // Fast case, write everything using _writev()
- var l = state.bufferedRequestCount;
- var buffer = new Array(l);
- var holder = state.corkedRequestsFree;
- holder.entry = entry;
-
- var count = 0;
- while (entry) {
- buffer[count] = entry;
- entry = entry.next;
- count += 1;
- }
-
- doWrite(stream, state, true, state.length, buffer, '', holder.finish);
-
- // doWrite is almost always async, defer these to save a bit of time
- // as the hot path ends with doWrite
- state.pendingcb++;
- state.lastBufferedRequest = null;
- if (holder.next) {
- state.corkedRequestsFree = holder.next;
- holder.next = null;
- } else {
- state.corkedRequestsFree = new CorkedRequest(state);
- }
- } else {
- // Slow case, write chunks one-by-one
- while (entry) {
- var chunk = entry.chunk;
- var encoding = entry.encoding;
- var cb = entry.callback;
- var len = state.objectMode ? 1 : chunk.length;
-
- doWrite(stream, state, false, len, chunk, encoding, cb);
- entry = entry.next;
- // if we didn't call the onwrite immediately, then
- // it means that we need to wait until it does.
- // also, that means that the chunk and cb are currently
- // being processed, so move the buffer counter past them.
- if (state.writing) {
- break;
- }
- }
-
- if (entry === null) state.lastBufferedRequest = null;
- }
-
- state.bufferedRequestCount = 0;
- state.bufferedRequest = entry;
- state.bufferProcessing = false;
-}
-
-Writable.prototype._write = function (chunk, encoding, cb) {
- cb(new Error('_write() is not implemented'));
-};
-
-Writable.prototype._writev = null;
-
-Writable.prototype.end = function (chunk, encoding, cb) {
- var state = this._writableState;
-
- if (typeof chunk === 'function') {
- cb = chunk;
- chunk = null;
- encoding = null;
- } else if (typeof encoding === 'function') {
- cb = encoding;
- encoding = null;
- }
-
- if (chunk !== null && chunk !== undefined) this.write(chunk, encoding);
-
- // .end() fully uncorks
- if (state.corked) {
- state.corked = 1;
- this.uncork();
- }
-
- // ignore unnecessary end() calls.
- if (!state.ending && !state.finished) endWritable(this, state, cb);
-};
-
-function needFinish(state) {
- return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing;
-}
-
-function prefinish(stream, state) {
- if (!state.prefinished) {
- state.prefinished = true;
- stream.emit('prefinish');
- }
-}
-
-function finishMaybe(stream, state) {
- var need = needFinish(state);
- if (need) {
- if (state.pendingcb === 0) {
- prefinish(stream, state);
- state.finished = true;
- stream.emit('finish');
- } else {
- prefinish(stream, state);
- }
- }
- return need;
-}
-
-function endWritable(stream, state, cb) {
- state.ending = true;
- finishMaybe(stream, state);
- if (cb) {
- if (state.finished) processNextTick(cb);else stream.once('finish', cb);
- }
- state.ended = true;
- stream.writable = false;
-}
-
-// It seems a linked list but it is not
-// there will be only 2 of these for each stream
-function CorkedRequest(state) {
- var _this = this;
-
- this.next = null;
- this.entry = null;
- this.finish = function (err) {
- var entry = _this.entry;
- _this.entry = null;
- while (entry) {
- var cb = entry.callback;
- state.pendingcb--;
- cb(err);
- entry = entry.next;
- }
- if (state.corkedRequestsFree) {
- state.corkedRequestsFree.next = _this;
- } else {
- state.corkedRequestsFree = _this;
- }
- };
-}
-/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7), __webpack_require__(99).setImmediate))
/***/ }),
/* 37 */
/***/ (function(module, exports, __webpack_require__) {
-module.exports = __webpack_require__(6)
+const Collection = __webpack_require__(3);
+const EventEmitter = __webpack_require__(9).EventEmitter;
+
+/**
+ * Filter to be applied to the collector.
+ * @typedef {Function} CollectorFilter
+ * @param {...*} args Any arguments received by the listener
+ * @returns {boolean} To collect or not collect
+ */
+
+/**
+ * Options to be applied to the collector.
+ * @typedef {Object} CollectorOptions
+ * @property {number} [time] How long to run the collector for
+ */
+
+/**
+ * Abstract class for defining a new Collector.
+ * @abstract
+ */
+class Collector extends EventEmitter {
+ constructor(client, filter, options = {}) {
+ super();
+
+ /**
+ * The client
+ * @name Collector#client
+ * @type {Client}
+ * @readonly
+ */
+ Object.defineProperty(this, 'client', { value: client });
+
+ /**
+ * The filter applied to this collector
+ * @type {CollectorFilter}
+ */
+ this.filter = filter;
+
+ /**
+ * The options of this collector
+ * @type {CollectorOptions}
+ */
+ this.options = options;
+
+ /**
+ * The items collected by this collector
+ * @type {Collection}
+ */
+ this.collected = new Collection();
+
+ /**
+ * Whether this collector has finished collecting
+ * @type {boolean}
+ */
+ this.ended = false;
+
+ /**
+ * Timeout for cleanup
+ * @type {?Timeout}
+ * @private
+ */
+ this._timeout = null;
+
+ /**
+ * Call this to handle an event as a collectable element
+ * Accepts any event data as parameters
+ * @type {Function}
+ * @private
+ */
+ this.listener = this._handle.bind(this);
+ if (options.time) this._timeout = this.client.setTimeout(() => this.stop('time'), options.time);
+ }
+
+ /**
+ * @param {...*} args The arguments emitted by the listener
+ * @emits Collector#collect
+ * @private
+ */
+ _handle(...args) {
+ const collect = this.handle(...args);
+ if (!collect || !this.filter(...args)) return;
+
+ this.collected.set(collect.key, collect.value);
+
+ /**
+ * Emitted whenever an element is collected.
+ * @event Collector#collect
+ * @param {*} element The element that got collected
+ * @param {Collector} collector The collector
+ */
+ this.emit('collect', collect.value, this);
+
+ const post = this.postCheck(...args);
+ if (post) this.stop(post);
+ }
+
+ /**
+ * Return a promise that resolves with the next collected element;
+ * rejects with collected elements if the collector finishes without receving a next element
+ * @type {Promise}
+ * @readonly
+ */
+ get next() {
+ return new Promise((resolve, reject) => {
+ if (this.ended) {
+ reject(this.collected);
+ return;
+ }
+
+ const cleanup = () => {
+ this.removeListener('collect', onCollect);
+ this.removeListener('end', onEnd);
+ };
+
+ const onCollect = item => {
+ cleanup();
+ resolve(item);
+ };
+
+ const onEnd = () => {
+ cleanup();
+ reject(this.collected); // eslint-disable-line prefer-promise-reject-errors
+ };
+
+ this.on('collect', onCollect);
+ this.on('end', onEnd);
+ });
+ }
+
+ /**
+ * Stop this collector and emit the `end` event.
+ * @param {string} [reason='user'] The reason this collector is ending
+ * @emits Collector#end
+ */
+ stop(reason = 'user') {
+ if (this.ended) return;
+
+ if (this._timeout) this.client.clearTimeout(this._timeout);
+ this.ended = true;
+ this.cleanup();
+
+ /**
+ * Emitted when the collector is finished collecting.
+ * @event Collector#end
+ * @param {Collection} collected The elements collected by the collector
+ * @param {string} reason The reason the collector ended
+ */
+ this.emit('end', this.collected, reason);
+ }
+
+ /* eslint-disable no-empty-function, valid-jsdoc */
+ /**
+ * Handles incoming events from the `listener` function. Returns null if the event should not be collected,
+ * or returns an object describing the data that should be stored.
+ * @see Collector#listener
+ * @param {...*} args Any args the event listener emits
+ * @returns {?{key: string, value}} Data to insert into collection, if any
+ * @abstract
+ */
+ handle() {}
+
+ /**
+ * This method runs after collection to see if the collector should finish.
+ * @param {...*} args Any args the event listener emits
+ * @returns {?string} Reason to end the collector, if any
+ * @abstract
+ */
+ postCheck() {}
+
+ /**
+ * Called when the collector is ending.
+ * @abstract
+ */
+ cleanup() {}
+ /* eslint-enable no-empty-function, valid-jsdoc */
+}
+
+module.exports = Collector;
/***/ }),
/* 38 */
/***/ (function(module, exports, __webpack_require__) {
-const Snekfetch = __webpack_require__(93);
+const path = __webpack_require__(19);
-// const ENV_VAR = '__SNEKFETCH_SYNC_REQUEST';
-// let first = true;
-//
-// for (let method of Snekfetch.METHODS) {
-// method = method === 'M-SEARCH' ? 'msearch' : method.toLowerCase();
-// Snekfetch[`${method}Sync`] = (url, options = {}) => {
-// if (first) {
-// first = false;
-// console.error(
-// 'Performing sync requests is a really stupid thing to do. ' +
-// 'https://www.google.com/search?q=why+sync+requests+are+bad+nodejs'
-// );
-// }
-// options.url = url;
-// options.method = method;
-// const cp = require('child_process');
-// const result = JSON.parse(
-// cp.execSync(`node ${__dirname}/index.js`, {
-// env: { [ENV_VAR]: JSON.stringify(options) },
-// }).toString(),
-// (k, v) => {
-// if (v === null) return v;
-// if (v.type === 'Buffer' && Array.isArray(v.data)) return new Buffer(v.data);
-// if (v.__CONVERT_TO_ERROR) {
-// const e = new Error();
-// for (const key of Object.keys(v)) {
-// if (key === '__CONVERT_TO_ERROR') continue;
-// e[key] = v[key];
-// }
-// return e;
-// }
-// return v;
-// }
-// );
-// if (result.error) throw result.error;
-// return result;
-// };
-// }
-//
-// if (process.env[ENV_VAR]) {
-// const options = JSON.parse(process.env[ENV_VAR]);
-// const request = Snekfetch[options.method](options.url);
-// if (options.headers) request.set(options.headers);
-// if (options.body) request.send(options.body);
-// request.end((err, res = {}) => {
-// if (err) {
-// const alt = {};
-// for (const name of Object.getOwnPropertyNames(err)) alt[name] = err[name];
-// res.error = alt;
-// res.error.__CONVERT_TO_ERROR = true;
-// }
-// // circulars
-// res.request = null;
-// process.stdout.write(JSON.stringify(res));
-// });
-// }
+/**
+ * Represents a webhook.
+ */
+class Webhook {
+ constructor(client, dataOrID, token) {
+ if (client) {
+ /**
+ * The client that instantiated the webhook
+ * @name Webhook#client
+ * @type {Client}
+ * @readonly
+ */
+ Object.defineProperty(this, 'client', { value: client });
+ if (dataOrID) this.setup(dataOrID);
+ } else {
+ this.id = dataOrID;
+ this.token = token;
+ Object.defineProperty(this, 'client', { value: this });
+ }
+ }
-module.exports = Snekfetch;
+ setup(data) {
+ /**
+ * The name of the webhook
+ * @type {string}
+ */
+ this.name = data.name;
+
+ /**
+ * The token for the webhook
+ * @type {string}
+ */
+ this.token = data.token;
+
+ /**
+ * The avatar for the webhook
+ * @type {string}
+ */
+ this.avatar = data.avatar;
+
+ /**
+ * The ID of the webhook
+ * @type {Snowflake}
+ */
+ this.id = data.id;
+
+ /**
+ * The guild the webhook belongs to
+ * @type {Snowflake}
+ */
+ this.guildID = data.guild_id;
+
+ /**
+ * The channel the webhook belongs to
+ * @type {Snowflake}
+ */
+ this.channelID = data.channel_id;
+
+ if (data.user) {
+ /**
+ * The owner of the webhook
+ * @type {?User|Object}
+ */
+ this.owner = this.client.users ? this.client.users.get(data.user.id) : data.user;
+ } else {
+ this.owner = null;
+ }
+ }
+
+ /**
+ * Options that can be passed into send, sendMessage, sendFile, sendEmbed, and sendCode.
+ * @typedef {Object} WebhookMessageOptions
+ * @property {string} [username=this.name] Username override for the message
+ * @property {string} [avatarURL] Avatar URL override for the message
+ * @property {boolean} [tts=false] Whether or not the message should be spoken aloud
+ * @property {string} [nonce=''] The nonce for the message
+ * @property {Object[]} [embeds] An array of embeds for the message
+ * (see [here](https://discordapp.com/developers/docs/resources/channel#embed-object) for more details)
+ * @property {boolean} [disableEveryone=this.client.options.disableEveryone] Whether or not @everyone and @here
+ * should be replaced with plain-text
+ * @property {FileOptions|string} [file] A file to send with the message
+ * @property {string|boolean} [code] Language for optional codeblock formatting to apply
+ * @property {boolean|SplitOptions} [split=false] Whether or not the message should be split into multiple messages if
+ * it exceeds the character limit. If an object is provided, these are the options for splitting the message.
+ */
+
+ /**
+ * Send a message with this webhook.
+ * @param {StringResolvable} content The content to send
+ * @param {WebhookMessageOptions} [options={}] The options to provide
+ * @returns {Promise}
+ * @example
+ * // Send a message
+ * webhook.send('hello!')
+ * .then(message => console.log(`Sent message: ${message.content}`))
+ * .catch(console.error);
+ */
+ send(content, options) {
+ if (!options && typeof content === 'object' && !(content instanceof Array)) {
+ options = content;
+ content = '';
+ } else if (!options) {
+ options = {};
+ }
+ if (options.file) {
+ if (options.files) options.files.push(options.file);
+ else options.files = [options.file];
+ }
+
+ if (options.files) {
+ for (let i = 0; i < options.files.length; i++) {
+ let file = options.files[i];
+ if (typeof file === 'string') file = { attachment: file };
+ if (!file.name) {
+ if (typeof file.attachment === 'string') {
+ file.name = path.basename(file.attachment);
+ } else if (file.attachment && file.attachment.path) {
+ file.name = path.basename(file.attachment.path);
+ } else {
+ file.name = 'file.jpg';
+ }
+ }
+ }
+ return this.client.resolver.resolveBuffer(options.file.attachment).then(file =>
+ this.client.rest.methods.sendWebhookMessage(this, content, options, {
+ file,
+ name: options.file.name,
+ })
+ );
+ }
+ return this.client.rest.methods.sendWebhookMessage(this, content, options);
+ }
+
+ /**
+ * Send a message with this webhook
+ * @param {StringResolvable} content The content to send
+ * @param {WebhookMessageOptions} [options={}] The options to provide
+ * @returns {Promise}
+ * @deprecated
+ * @example
+ * // Send a message
+ * webhook.sendMessage('hello!')
+ * .then(message => console.log(`Sent message: ${message.content}`))
+ * .catch(console.error);
+ */
+ sendMessage(content, options = {}) {
+ return this.send(content, options);
+ }
+
+ /**
+ * Send a file with this webhook.
+ * @param {BufferResolvable} attachment The file to send
+ * @param {string} [name='file.jpg'] The name and extension of the file
+ * @param {StringResolvable} [content] Text message to send with the attachment
+ * @param {WebhookMessageOptions} [options] The options to provide
+ * @returns {Promise}
+ * @deprecated
+ */
+ sendFile(attachment, name, content, options = {}) {
+ return this.send(content, Object.assign(options, { file: { attachment, name } }));
+ }
+
+ /**
+ * Send a code block with this webhook.
+ * @param {string} lang Language for the code block
+ * @param {StringResolvable} content Content of the code block
+ * @param {WebhookMessageOptions} options The options to provide
+ * @returns {Promise}
+ * @deprecated
+ */
+ sendCode(lang, content, options = {}) {
+ return this.send(content, Object.assign(options, { code: lang }));
+ }
+
+ /**
+ * Send a raw slack message with this webhook.
+ * @param {Object} body The raw body to send
+ * @returns {Promise}
+ * @example
+ * // Send a slack message
+ * webhook.sendSlackMessage({
+ * 'username': 'Wumpus',
+ * 'attachments': [{
+ * 'pretext': 'this looks pretty cool',
+ * 'color': '#F0F',
+ * 'footer_icon': 'http://snek.s3.amazonaws.com/topSnek.png',
+ * 'footer': 'Powered by sneks',
+ * 'ts': Date.now() / 1000
+ * }]
+ * }).catch(console.error);
+ */
+ sendSlackMessage(body) {
+ return this.client.rest.methods.sendSlackWebhookMessage(this, body);
+ }
+
+ /**
+ * Edit the webhook.
+ * @param {string} name The new name for the webhook
+ * @param {BufferResolvable} avatar The new avatar for the webhook
+ * @returns {Promise}
+ */
+ edit(name = this.name, avatar) {
+ if (avatar) {
+ return this.client.resolver.resolveBuffer(avatar).then(file => {
+ const dataURI = this.client.resolver.resolveBase64(file);
+ return this.client.rest.methods.editWebhook(this, name, dataURI);
+ });
+ }
+ return this.client.rest.methods.editWebhook(this, name).then(data => {
+ this.setup(data);
+ return this;
+ });
+ }
+
+ /**
+ * Delete the webhook.
+ * @returns {Promise}
+ */
+ delete() {
+ return this.client.rest.methods.deleteWebhook(this);
+ }
+}
+
+module.exports = Webhook;
/***/ }),
/* 39 */
-/***/ (function(module, exports) {
+/***/ (function(module, exports, __webpack_require__) {
+const Snowflake = __webpack_require__(8);
+
+/**
+ * Represents an OAuth2 Application.
+ */
+class OAuth2Application {
+ constructor(client, data) {
+ /**
+ * The client that instantiated the application
+ * @name OAuth2Application#client
+ * @type {Client}
+ * @readonly
+ */
+ Object.defineProperty(this, 'client', { value: client });
+
+ this.setup(data);
+ }
+
+ setup(data) {
+ /**
+ * The ID of the app
+ * @type {Snowflake}
+ */
+ this.id = data.id;
+
+ /**
+ * The name of the app
+ * @type {string}
+ */
+ this.name = data.name;
+
+ /**
+ * The app's description
+ * @type {string}
+ */
+ this.description = data.description;
+
+ /**
+ * The app's icon hash
+ * @type {string}
+ */
+ this.icon = data.icon;
+
+ /**
+ * The app's icon URL
+ * @type {string}
+ */
+ this.iconURL = `https://cdn.discordapp.com/app-icons/${this.id}/${this.icon}.jpg`;
+
+ /**
+ * The app's RPC origins
+ * @type {?string[]}
+ */
+ this.rpcOrigins = data.rpc_origins;
+
+ /**
+ * The app's redirect URIs
+ * @type {string[]}
+ */
+ this.redirectURIs = data.redirect_uris;
+
+ /**
+ * If this app's bot requires a code grant when using the OAuth2 flow
+ * @type {boolean}
+ */
+ this.botRequireCodeGrant = data.bot_require_code_grant;
+
+ /**
+ * If this app's bot is public
+ * @type {boolean}
+ */
+ this.botPublic = data.bot_public;
+
+ /**
+ * If this app can use rpc
+ * @type {boolean}
+ */
+ this.rpcApplicationState = data.rpc_application_state;
+
+ /**
+ * Object containing basic info about this app's bot
+ * @type {Object}
+ */
+ this.bot = data.bot;
+
+ /**
+ * The flags for the app
+ * @type {number}
+ */
+ this.flags = data.flags;
+
+ /**
+ * OAuth2 secret for the application
+ * @type {boolean}
+ */
+ this.secret = data.secret;
+
+ if (data.owner) {
+ /**
+ * The owner of this OAuth application
+ * @type {?User}
+ */
+ this.owner = this.client.dataManager.newUser(data.owner);
+ }
+ }
+
+ /**
+ * The timestamp the app was created at
+ * @type {number}
+ * @readonly
+ */
+ get createdTimestamp() {
+ return Snowflake.deconstruct(this.id).timestamp;
+ }
+
+ /**
+ * The time the app was created
+ * @type {Date}
+ * @readonly
+ */
+ get createdAt() {
+ return new Date(this.createdTimestamp);
+ }
+
+ /**
+ * Reset the app's secret and bot token.
+ * @returns {OAuth2Application}
+ */
+ reset() {
+ return this.client.rest.methods.resetApplication(this.id);
+ }
+
+ /**
+ * When concatenated with a string, this automatically concatenates the app name rather than the app object.
+ * @returns {string}
+ */
+ toString() {
+ return this.name;
+ }
+}
+
+module.exports = OAuth2Application;
/***/ }),
/* 40 */
/***/ (function(module, exports, __webpack_require__) {
-/* WEBPACK VAR INJECTION */(function(Buffer) {const path = __webpack_require__(28);
-const fs = __webpack_require__(39);
-const snekfetch = __webpack_require__(38);
+const Channel = __webpack_require__(16);
+const TextBasedChannel = __webpack_require__(21);
+const Collection = __webpack_require__(3);
+
+/*
+{ 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);
+ this.type = 'group';
+ this.messages = new Collection();
+ this._typing = new Map();
+ }
+
+ setup(data) {
+ super.setup(data);
+
+ /**
+ * The name of this Group DM, can be null if one isn't set
+ * @type {string}
+ */
+ this.name = data.name;
+
+ /**
+ * A hash of the Group DM icon.
+ * @type {string}
+ */
+ this.icon = data.icon;
+
+ /**
+ * The user ID of this Group DM's owner
+ * @type {string}
+ */
+ 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 {?string}
+ */
+ this.applicationID = data.application_id;
+
+ /**
+ * Nicknames for group members
+ * @type {?Collection}
+ */
+ if (data.nicks) 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}
+ */
+ this.recipients = new Collection();
+ }
+
+ if (data.recipients) {
+ for (const recipient of data.recipients) {
+ const user = this.client.dataManager.newUser(recipient);
+ this.recipients.set(user.id, user);
+ }
+ }
+
+ this.lastMessageID = data.last_message_id;
+ }
+
+ /**
+ * The owner of this Group DM
+ * @type {User}
+ * @readonly
+ */
+ get owner() {
+ return this.client.users.get(this.ownerID);
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Add a user to the DM
+ * @param {UserResolvable|string} accessTokenOrID Access token or user resolvable
+ * @param {string} [nick] Permanent nickname to give the user (only available if a bot is creating the DM)
+ */
+
+ addUser(accessTokenOrID, nick) {
+ return this.client.rest.methods.addUserToGroupDM(this, {
+ nick,
+ id: this.client.resolver.resolveUserID(accessTokenOrID),
+ accessToken: accessTokenOrID,
+ });
+ }
+
+ /**
+ * When concatenated with a string, this automatically concatenates the channel's name instead of the Channel object.
+ * @returns {string}
+ * @example
+ * // Logs: Hello from My Group DM!
+ * console.log(`Hello from ${channel}!`);
+ * @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 */
+ send() {}
+ sendMessage() {}
+ sendEmbed() {}
+ sendFile() {}
+ sendFiles() {}
+ sendCode() {}
+ fetchMessage() {}
+ fetchMessages() {}
+ fetchPinnedMessages() {}
+ search() {}
+ startTyping() {}
+ stopTyping() {}
+ get typing() {}
+ get typingCount() {}
+ createCollector() {}
+ awaitMessages() {}
+ // Doesn't work on Group DMs; bulkDelete() {}
+ acknowledge() {}
+ _cacheMessage() {}
+}
+
+TextBasedChannel.applyToClass(GroupDMChannel, true, ['bulkDelete']);
+
+module.exports = GroupDMChannel;
+
+
+/***/ }),
+/* 41 */
+/***/ (function(module, exports) {
+
+/**
+ * Represents an error from the Discord API.
+ * @extends Error
+ */
+class DiscordAPIError extends Error {
+ constructor(error) {
+ super();
+ const flattened = error.errors ? `\n${this.constructor.flattenErrors(error.errors).join('\n')}` : '';
+ this.name = 'DiscordAPIError';
+ this.message = `${error.message}${flattened}`;
+
+ /**
+ * HTTP error code returned by Discord
+ * @type {number}
+ */
+ this.code = error.code;
+ }
+
+ /**
+ * Flattens an errors object returned from the API into an array.
+ * @param {Object} obj Discord errors object
+ * @param {string} [key] Used internally to determine key names of nested fields
+ * @returns {string[]}
+ * @private
+ */
+ static flattenErrors(obj, key = '') {
+ let messages = [];
+
+ for (const k of Object.keys(obj)) {
+ const newKey = key ? isNaN(k) ? `${key}.${k}` : `${key}[${k}]` : k;
+
+ if (obj[k]._errors) {
+ messages.push(`${newKey}: ${obj[k]._errors.map(e => e.message).join(' ')}`);
+ } else if (obj[k].code && obj[k].message) {
+ messages.push(`${obj[k].code}: ${obj[k].message}`);
+ } else {
+ messages = messages.concat(this.flattenErrors(obj[k], newKey));
+ }
+ }
+
+ return messages;
+ }
+}
+
+module.exports = DiscordAPIError;
+
+
+/***/ }),
+/* 42 */
+/***/ (function(module, exports, __webpack_require__) {
+
+/* WEBPACK VAR INJECTION */(function(Buffer) {const path = __webpack_require__(19);
+const fs = __webpack_require__(26);
+const snekfetch = __webpack_require__(30);
const Constants = __webpack_require__(0);
const convertToBuffer = __webpack_require__(4).convertToBuffer;
-const User = __webpack_require__(16);
-const Message = __webpack_require__(19);
-const Guild = __webpack_require__(25);
-const Channel = __webpack_require__(14);
-const GuildMember = __webpack_require__(18);
-const Emoji = __webpack_require__(17);
-const ReactionEmoji = __webpack_require__(30);
+const User = __webpack_require__(13);
+const Message = __webpack_require__(22);
+const Guild = __webpack_require__(28);
+const Channel = __webpack_require__(16);
+const GuildMember = __webpack_require__(24);
+const Emoji = __webpack_require__(23);
+const ReactionEmoji = __webpack_require__(36);
/**
* The DataResolver identifies different objects and tries to resolve a specific piece of information from them, e.g.
@@ -12183,11 +12633,11 @@ class ClientDataResolver {
return new Promise((resolve, reject) => {
if (/^https?:\/\//.test(resource)) {
snekfetch.get(resource)
- .end((err, res) => {
- if (err) return reject(err);
- if (!(res.body instanceof Buffer)) return reject(new TypeError('The response body isn\'t a Buffer.'));
- return resolve(res.body);
- });
+ .end((err, res) => {
+ if (err) return reject(err);
+ if (!(res.body instanceof Buffer)) return reject(new TypeError('The response body isn\'t a Buffer.'));
+ return resolve(res.body);
+ });
} else {
const file = path.resolve(resource);
fs.stat(file, (err, stats) => {
@@ -12298,2401 +12748,10 @@ class ClientDataResolver {
module.exports = ClientDataResolver;
-/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(6).Buffer))
-
-/***/ }),
-/* 41 */
-/***/ (function(module, exports) {
-
-module.exports = {
- "name": "discord.js",
- "version": "11.2.0",
- "description": "A powerful library for interacting with the Discord API",
- "main": "./src/index",
- "types": "./typings/index.d.ts",
- "scripts": {
- "test": "npm run lint && npm run docs:test",
- "docs": "docgen --source src --custom docs/index.yml --output docs/docs.json",
- "docs:test": "docgen --source src --custom docs/index.yml",
- "lint": "eslint src",
- "lint:fix": "eslint --fix src",
- "webpack": "parallel-webpack"
- },
- "repository": {
- "type": "git",
- "url": "git+https://github.com/hydrabolt/discord.js.git"
- },
- "keywords": [
- "discord",
- "api",
- "bot",
- "client",
- "node",
- "discordapp"
- ],
- "author": "Amish Shah ",
- "license": "Apache-2.0",
- "bugs": {
- "url": "https://github.com/hydrabolt/discord.js/issues"
- },
- "homepage": "https://github.com/hydrabolt/discord.js#readme",
- "runkitExampleFilename": "./docs/examples/ping.js",
- "dependencies": {
- "long": "^3.2.0",
- "prism-media": "^0.0.1",
- "snekfetch": "^3.1.0",
- "tweetnacl": "^0.14.0",
- "ws": "^2.0.0"
- },
- "peerDependencies": {
- "bufferutil": "^3.0.0",
- "erlpack": "hammerandchisel/erlpack",
- "node-opus": "^0.2.5",
- "opusscript": "^0.0.3",
- "sodium": "^2.0.1",
- "libsodium-wrappers": "^0.5.1",
- "uws": "^0.14.1"
- },
- "devDependencies": {
- "@types/node": "^7.0.0",
- "discord.js-docgen": "hydrabolt/discord.js-docgen",
- "eslint": "^3.19.0",
- "parallel-webpack": "^1.6.0",
- "uglify-js": "mishoo/UglifyJS2#harmony-v2.8.22",
- "uglifyjs-webpack-plugin": "^0.4.3",
- "webpack": "^2.2.0"
- },
- "engines": {
- "node": ">=6.0.0"
- },
- "browser": {
- "ws": false,
- "uws": false,
- "erlpack": false,
- "prism-media": false,
- "opusscript": false,
- "node-opus": false,
- "tweetnacl": false,
- "sodium": false,
- "src/sharding/Shard.js": false,
- "src/sharding/ShardClientUtil.js": false,
- "src/sharding/ShardingManager.js": false,
- "src/client/voice/dispatcher/StreamDispatcher.js": false,
- "src/client/voice/opus/BaseOpusEngine.js": false,
- "src/client/voice/opus/NodeOpusEngine.js": false,
- "src/client/voice/opus/OpusEngineList.js": false,
- "src/client/voice/opus/OpusScriptEngine.js": false,
- "src/client/voice/pcm/ConverterEngine.js": false,
- "src/client/voice/pcm/ConverterEngineList.js": false,
- "src/client/voice/pcm/FfmpegConverterEngine.js": false,
- "src/client/voice/player/AudioPlayer.js": false,
- "src/client/voice/receiver/VoiceReadable.js": false,
- "src/client/voice/receiver/VoiceReceiver.js": false,
- "src/client/voice/util/Secretbox.js": false,
- "src/client/voice/util/SecretKey.js": false,
- "src/client/voice/util/VolumeInterface.js": false,
- "src/client/voice/ClientVoiceManager.js": false,
- "src/client/voice/VoiceBroadcast.js": false,
- "src/client/voice/VoiceConnection.js": false,
- "src/client/voice/VoiceUDPClient.js": false,
- "src/client/voice/VoiceWebSocket.js": false
- }
-};
-
-/***/ }),
-/* 42 */
-/***/ (function(module, exports, __webpack_require__) {
-
-const User = __webpack_require__(16);
-const Collection = __webpack_require__(3);
-const ClientUserSettings = __webpack_require__(43);
-const Constants = __webpack_require__(0);
-
-/**
- * Represents the logged in client's Discord user.
- * @extends {User}
- */
-class ClientUser extends User {
- setup(data) {
- super.setup(data);
-
- /**
- * Whether or not this account has been verified
- * @type {boolean}
- */
- this.verified = data.verified;
-
- /**
- * The email of this account
- * @type {string}
- */
- this.email = data.email;
- this.localPresence = {};
- this._typing = new Map();
-
- /**
- * A Collection of friends for the logged in user
- * This is only filled when using a user account.
- * @type {Collection}
- */
- this.friends = new Collection();
-
- /**
- * A Collection of blocked users for the logged in user
- * This is only filled when using a user account.
- * @type {Collection}
- */
- this.blocked = new Collection();
-
- /**
- * A Collection of notes for the logged in user
- * This is only filled when using a user account.
- * @type {Collection}
- */
- this.notes = new Collection();
-
- /**
- * If the user has Discord premium (nitro)
- * This is only filled when using a user account.
- * @type {?boolean}
- */
- this.premium = typeof data.premium === 'boolean' ? data.premium : null;
-
- /**
- * If the user has MFA enabled on their account
- * This is only filled when using a user account.
- * @type {?boolean}
- */
- this.mfaEnabled = typeof data.mfa_enabled === 'boolean' ? data.mfa_enabled : null;
-
- /**
- * If the user has ever used a mobile device on Discord
- * This is only filled when using a user account.
- * @type {?boolean}
- */
- this.mobile = typeof data.mobile === 'boolean' ? data.mobile : null;
-
- /**
- * Various settings for this user
- * This is only filled when using a user account.
- * @type {?ClientUserSettings}
- */
- if (data.user_settings) this.settings = new ClientUserSettings(this, data.user_settings);
- }
-
- edit(data) {
- return this.client.rest.methods.updateCurrentUser(data);
- }
-
- /**
- * Set the username of the logged in client.
- * Changing usernames in Discord is heavily rate limited, with only 2 requests
- * every hour. Use this sparingly!
- * @param {string} username The new username
- * @param {string} [password] Current password (only for user accounts)
- * @returns {Promise}
- * @example
- * // Set username
- * client.user.setUsername('discordjs')
- * .then(user => console.log(`My new username is ${user.username}`))
- * .catch(console.error);
- */
- setUsername(username, password) {
- return this.client.rest.methods.updateCurrentUser({ username }, password);
- }
-
- /**
- * Changes the email for the client user's account.
- * This is only available when using a user account.
- * @param {string} email New email to change to
- * @param {string} password Current password
- * @returns {Promise}
- * @example
- * // Set email
- * client.user.setEmail('bob@gmail.com', 'some amazing password 123')
- * .then(user => console.log(`My new email is ${user.email}`))
- * .catch(console.error);
- */
- setEmail(email, password) {
- return this.client.rest.methods.updateCurrentUser({ email }, password);
- }
-
- /**
- * Changes the password for the client user's account.
- * This is only available when using a user account.
- * @param {string} newPassword New password to change to
- * @param {string} oldPassword Current password
- * @returns {Promise}
- * @example
- * // Set password
- * client.user.setPassword('some new amazing password 456', 'some amazing password 123')
- * .then(user => console.log('New password set!'))
- * .catch(console.error);
- */
- setPassword(newPassword, oldPassword) {
- return this.client.rest.methods.updateCurrentUser({ password: newPassword }, oldPassword);
- }
-
- /**
- * Set the avatar of the logged in client.
- * @param {BufferResolvable|Base64Resolvable} avatar The new avatar
- * @returns {Promise}
- * @example
- * // Set avatar
- * client.user.setAvatar('./avatar.png')
- * .then(user => console.log(`New avatar set!`))
- * .catch(console.error);
- */
- setAvatar(avatar) {
- if (typeof avatar === 'string' && avatar.startsWith('data:')) {
- return this.client.rest.methods.updateCurrentUser({ avatar });
- } else {
- return this.client.resolver.resolveBuffer(avatar).then(data =>
- this.client.rest.methods.updateCurrentUser({ avatar: data })
- );
- }
- }
-
- /**
- * Data resembling a raw Discord presence.
- * @typedef {Object} PresenceData
- * @property {PresenceStatus} [status] Status of the user
- * @property {boolean} [afk] Whether the user is AFK
- * @property {Object} [game] Game the user is playing
- * @property {string} [game.name] Name of the game
- * @property {string} [game.url] Twitch stream URL
- */
-
- /**
- * Sets the full presence of the client user.
- * @param {PresenceData} data Data for the presence
- * @returns {Promise}
- */
- setPresence(data) {
- // {"op":3,"d":{"status":"dnd","since":0,"game":null,"afk":false}}
- return new Promise(resolve => {
- let status = this.localPresence.status || this.presence.status;
- let game = this.localPresence.game;
- let afk = this.localPresence.afk || this.presence.afk;
-
- if (!game && this.presence.game) {
- game = {
- name: this.presence.game.name,
- type: this.presence.game.type,
- url: this.presence.game.url,
- };
- }
-
- if (data.status) {
- if (typeof data.status !== 'string') throw new TypeError('Status must be a string');
- if (this.bot) {
- status = data.status;
- } else {
- this.settings.update(Constants.UserSettingsMap.status, data.status);
- status = 'invisible';
- }
- }
-
- if (data.game) {
- game = data.game;
- if (game.url) game.type = 1;
- } else if (typeof data.game !== 'undefined') {
- game = null;
- }
-
- if (typeof data.afk !== 'undefined') afk = data.afk;
- afk = Boolean(afk);
-
- this.localPresence = { status, game, afk };
- this.localPresence.since = 0;
- this.localPresence.game = this.localPresence.game || null;
-
- this.client.ws.send({
- op: 3,
- d: this.localPresence,
- });
-
- this.client._setPresence(this.id, this.localPresence);
-
- resolve(this);
- });
- }
-
- /**
- * A user's status. Must be one of:
- * - `online`
- * - `idle`
- * - `invisible`
- * - `dnd` (do not disturb)
- * @typedef {string} PresenceStatus
- */
-
- /**
- * Sets the status of the client user.
- * @param {PresenceStatus} status Status to change to
- * @returns {Promise}
- */
- setStatus(status) {
- return this.setPresence({ status });
- }
-
- /**
- * Sets the game the client user is playing.
- * @param {?string} game Game being played
- * @param {string} [streamingURL] Twitch stream URL
- * @returns {Promise}
- */
- setGame(game, streamingURL) {
- if (!game) return this.setPresence({ game: null });
- return this.setPresence({
- game: {
- name: game,
- url: streamingURL,
- },
- });
- }
-
- /**
- * Sets/removes the AFK flag for the client user.
- * @param {boolean} afk Whether or not the user is AFK
- * @returns {Promise}
- */
- setAFK(afk) {
- return this.setPresence({ afk });
- }
-
- /**
- * Fetches messages that mentioned the client's user.
- * @param {Object} [options] Options for the fetch
- * @param {number} [options.limit=25] Maximum number of mentions to retrieve
- * @param {boolean} [options.roles=true] Whether to include role mentions
- * @param {boolean} [options.everyone=true] Whether to include everyone/here mentions
- * @param {Guild|Snowflake} [options.guild] Limit the search to a specific guild
- * @returns {Promise}
- */
- fetchMentions(options = {}) {
- return this.client.rest.methods.fetchMentions(options);
- }
-
- /**
- * Send a friend request.
- * This is only available when using a user account.
- * @param {UserResolvable} user The user to send the friend request to
- * @returns {Promise} The user the friend request was sent to
- */
- addFriend(user) {
- user = this.client.resolver.resolveUser(user);
- return this.client.rest.methods.addFriend(user);
- }
-
- /**
- * Remove a friend.
- * This is only available when using a user account.
- * @param {UserResolvable} user The user to remove from your friends
- * @returns {Promise} The user that was removed
- */
- removeFriend(user) {
- user = this.client.resolver.resolveUser(user);
- return this.client.rest.methods.removeFriend(user);
- }
-
- /**
- * Creates a guild.
- * This is only available when using a user account.
- * @param {string} name The name of the guild
- * @param {string} region The region for the server
- * @param {BufferResolvable|Base64Resolvable} [icon=null] The icon for the guild
- * @returns {Promise} The guild that was created
- */
-
- createGuild(name, { region, icon = null } = {}) {
- if (!icon || (typeof icon === 'string' && icon.startsWith('data:'))) {
- return new Promise((resolve, reject) =>
- this.client.api.guilds.post({ data: { name, region, icon } })
- .then(data => {
- if (this.client.guilds.has(data.id)) return resolve(this.client.guilds.get(data.id));
-
- const handleGuild = guild => {
- if (guild.id === data.id) {
- this.client.removeListener(Constants.Events.GUILD_CREATE, handleGuild);
- this.client.clearTimeout(timeout);
- resolve(guild);
- }
- };
- this.client.on(Constants.Events.GUILD_CREATE, handleGuild);
-
- const timeout = this.client.setTimeout(() => {
- this.client.removeListener(Constants.Events.GUILD_CREATE, handleGuild);
- resolve(this.client.dataManager.newGuild(data));
- }, 10000);
- return undefined;
- }, reject)
- );
- } else {
- return this.client.resolver.resolveBuffer(icon)
- .then(data => this.createGuild(name, { region, icon: this.client.resolver.resolveBase64(data) || null }));
- }
- }
-
- /**
- * An object containing either a user or access token, and an optional nickname.
- * @typedef {Object} GroupDMRecipientOptions
- * @property {UserResolvable|Snowflake} [user] User to add to the Group DM
- * (only available if a user is creating the 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)
- */
-
- /**
- * Creates a Group DM.
- * @param {GroupDMRecipientOptions[]} recipients The recipients
- * @returns {Promise}
- */
- createGroupDM(recipients) {
- return this.client.rest.methods.createGroupDM({
- recipients: recipients.map(u => this.client.resolver.resolveUserID(u.user)),
- accessTokens: recipients.map(u => u.accessToken),
- nicks: recipients.map(u => u.nick),
- });
- }
-
- /**
- * Accepts an invite to join a guild.
- * This is only available when using a user account.
- * @param {Invite|string} invite Invite or code to accept
- * @returns {Promise} Joined guild
- */
- acceptInvite(invite) {
- return this.client.rest.methods.acceptInvite(invite);
- }
-}
-
-module.exports = ClientUser;
-
+/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(5).Buffer))
/***/ }),
/* 43 */
-/***/ (function(module, exports, __webpack_require__) {
-
-const Constants = __webpack_require__(0);
-const Util = __webpack_require__(4);
-
-/**
- * A wrapper around the ClientUser's settings.
- */
-class ClientUserSettings {
- constructor(user, data) {
- this.user = user;
- this.patch(data);
- }
-
- /**
- * Patch the data contained in this class with new partial data.
- * @param {Object} data Data to patch this with
- */
- patch(data) {
- for (const key of Object.keys(Constants.UserSettingsMap)) {
- const value = Constants.UserSettingsMap[key];
- if (!data.hasOwnProperty(key)) continue;
- if (typeof value === 'function') {
- this[value.name] = value(data[key]);
- } else {
- this[value] = data[key];
- }
- }
- }
-
- /**
- * Update a specific property of of user settings.
- * @param {string} name Name of property
- * @param {value} value Value to patch
- * @returns {Promise