diff --git a/discord.master.js b/discord.master.js
index ed40718e..b3ee078d 100644
--- a/discord.master.js
+++ b/discord.master.js
@@ -63,14 +63,14 @@
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
-/******/ return __webpack_require__(__webpack_require__.s = 178);
+/******/ return __webpack_require__(__webpack_require__.s = 183);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
-/* WEBPACK VAR INJECTION */(function(process) {exports.Package = __webpack_require__(40);
+/* WEBPACK VAR INJECTION */(function(process) {exports.Package = __webpack_require__(41);
/**
* Options for a client.
@@ -125,7 +125,7 @@ exports.DefaultOptions = {
*/
ws: {
large_threshold: 250,
- compress: __webpack_require__(23).platform() !== 'browser',
+ compress: __webpack_require__(25).platform() !== 'browser',
properties: {
$os: process ? process.platform : 'discord.js',
$browser: 'discord.js',
@@ -178,101 +178,7 @@ const AllowedImageSizes = [
2048,
];
-const Endpoints = exports.Endpoints = {
- User: userID => {
- if (userID.id) userID = userID.id;
- const base = `/users/${userID}`;
- return {
- toString: () => base,
- channels: `${base}/channels`,
- profile: `${base}/profile`,
- relationships: `${base}/relationships`,
- settings: `${base}/settings`,
- Relationship: uID => `${base}/relationships/${uID}`,
- Guild: guildID => `${base}/guilds/${guildID}`,
- Note: id => `${base}/notes/${id}`,
- Mentions: (limit, roles, everyone, guildID) =>
- `${base}/mentions?limit=${limit}&roles=${roles}&everyone=${everyone}${guildID ? `&guild_id=${guildID}` : ''}`,
- Avatar: (root, hash, format, size) => {
- if (userID === '1') return hash;
- return Endpoints.CDN(root).Avatar(userID, hash, format, size);
- },
- };
- },
- guilds: '/guilds',
- Guild: guildID => {
- if (guildID.id) guildID = guildID.id;
- const base = `/guilds/${guildID}`;
- return {
- toString: () => base,
- prune: `${base}/prune`,
- embed: `${base}/embed`,
- bans: `${base}/bans`,
- integrations: `${base}/integrations`,
- members: `${base}/members`,
- channels: `${base}/channels`,
- invites: `${base}/invites`,
- roles: `${base}/roles`,
- emojis: `${base}/emojis`,
- search: `${base}/messages/search`,
- voiceRegions: `${base}/regions`,
- webhooks: `${base}/webhooks`,
- ack: `${base}/ack`,
- settings: `${base}/settings`,
- auditLogs: `${base}/audit-logs`,
- Emoji: emojiID => `${base}/emojis/${emojiID}`,
- Icon: (root, hash, format, size) => Endpoints.CDN(root).Icon(guildID, hash, format, size),
- Splash: (root, hash) => Endpoints.CDN(root).Splash(guildID, hash),
- Role: roleID => `${base}/roles/${roleID}`,
- Member: memberID => {
- if (memberID.id) memberID = memberID.id;
- const mbase = `${base}/members/${memberID}`;
- return {
- toString: () => mbase,
- Role: roleID => `${mbase}/roles/${roleID}`,
- nickname: `${base}/members/@me/nick`,
- };
- },
- };
- },
- channels: '/channels',
- Channel: channelID => {
- if (channelID.id) channelID = channelID.id;
- const base = `/channels/${channelID}`;
- return {
- toString: () => base,
- messages: {
- toString: () => `${base}/messages`,
- bulkDelete: `${base}/messages/bulk-delete`,
- },
- invites: `${base}/invites`,
- typing: `${base}/typing`,
- permissions: `${base}/permissions`,
- webhooks: `${base}/webhooks`,
- search: `${base}/messages/search`,
- pins: `${base}/pins`,
- Pin: messageID => `${base}/pins/${messageID}`,
- Recipient: recipientID => `${base}/recipients/${recipientID}`,
- Message: messageID => {
- if (messageID.id) messageID = messageID.id;
- const mbase = `${base}/messages/${messageID}`;
- return {
- toString: () => mbase,
- reactions: `${mbase}/reactions`,
- ack: `${mbase}/ack`,
- Reaction: (emoji, limit) => {
- const rbase = `${mbase}/reactions/${emoji}${limit ? `?limit=${limit}` : ''}`;
- return {
- toString: () => rbase,
- User: userID => `${rbase}/${userID}`,
- };
- },
- };
- },
- };
- },
- Message: m => exports.Endpoints.Channel(m.channel).Message(m),
- Member: m => exports.Endpoints.Guild(m.guild).Member(m),
+exports.Endpoints = {
CDN(root) {
return {
Emoji: emojiID => `${root}/emojis/${emojiID}.png`,
@@ -299,26 +205,7 @@ const Endpoints = exports.Endpoints = {
Splash: (guildID, hash) => `${root}/splashes/${guildID}/${hash}.jpg`,
};
},
- OAUTH2: {
- Application: appID => {
- const base = `/oauth2/applications/${appID}`;
- return {
- toString: () => base,
- reset: `${base}/reset`,
- };
- },
- App: appID => `/oauth2/authorize?client_id=${appID}`,
- },
- login: '/auth/login',
- logout: '/auth/logout',
- voiceRegions: '/voice/regions',
- gateway: {
- toString: () => '/gateway',
- bot: '/gateway/bot',
- },
- Invite: inviteID => `/invite/${inviteID}?with_counts=true`,
- inviteLink: id => `https://discord.gg/${id}`,
- Webhook: (webhookID, token) => `/webhooks/${webhookID}${token ? `/${token}` : ''}`,
+ invite: code => `https://discord.gg/${code}`,
};
@@ -1135,7 +1022,7 @@ module.exports = Collection;
/* 4 */
/***/ (function(module, exports, __webpack_require__) {
-/* WEBPACK VAR INJECTION */(function(Buffer) {const snekfetch = __webpack_require__(37);
+/* WEBPACK VAR INJECTION */(function(Buffer) {const snekfetch = __webpack_require__(38);
const Constants = __webpack_require__(0);
const ConstantsHttp = Constants.DefaultOptions.http;
@@ -1167,7 +1054,7 @@ class Util {
}
messages[msg] += (messages[msg].length > 0 && messages[msg] !== prepend ? char : '') + splitText[i];
}
- return messages;
+ return messages.filter(m => m);
}
/**
@@ -1365,8 +1252,8 @@ module.exports = Util;
-var base64 = __webpack_require__(76)
-var ieee754 = __webpack_require__(79)
+var base64 = __webpack_require__(78)
+var ieee754 = __webpack_require__(81)
var isArray = __webpack_require__(57)
exports.Buffer = Buffer
@@ -3151,7 +3038,7 @@ function isnan (val) {
/* 6 */
/***/ (function(module, exports, __webpack_require__) {
-const Long = __webpack_require__(33);
+const Long = __webpack_require__(34);
// Discord epoch (2015-01-01T00:00:00.000Z)
const EPOCH = 1420070400000;
@@ -3422,2197 +3309,6 @@ process.umask = function() { return 0; };
/* 8 */
/***/ (function(module, exports, __webpack_require__) {
-const Constants = __webpack_require__(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.
- */
-class Permissions {
- /**
- * @param {number|PermissionResolvable[]} permissions Permissions or bitfield to read from
- */
- constructor(permissions) {
- /**
- * Bitfield of the packed permissions
- * @type {number}
- */
- this.bitfield = typeof permissions === 'number' ? permissions : this.constructor.resolve(permissions);
- }
-
- /**
- * 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;
- }
-
- /**
- * 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)
- * - `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_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,
- 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_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;
-
-module.exports = Permissions;
-
-
-/***/ }),
-/* 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
-// 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.
-
-function EventEmitter() {
- this._events = this._events || {};
- this._maxListeners = this._maxListeners || undefined;
-}
-module.exports = EventEmitter;
-
-// Backwards-compat with node 0.10.x
-EventEmitter.EventEmitter = EventEmitter;
-
-EventEmitter.prototype._events = undefined;
-EventEmitter.prototype._maxListeners = undefined;
-
-// By default EventEmitters will print a warning if more than 10 listeners are
-// added to it. This is a useful default which helps finding memory leaks.
-EventEmitter.defaultMaxListeners = 10;
-
-// Obviously not all Emitters should be limited to 10. This function allows
-// that to be increased. Set to zero for unlimited.
-EventEmitter.prototype.setMaxListeners = function(n) {
- if (!isNumber(n) || n < 0 || isNaN(n))
- throw TypeError('n must be a positive number');
- this._maxListeners = n;
- return this;
-};
-
-EventEmitter.prototype.emit = function(type) {
- var er, handler, len, args, i, listeners;
-
- if (!this._events)
- this._events = {};
-
- // If there is no 'error' event listener then throw.
- if (type === 'error') {
- if (!this._events.error ||
- (isObject(this._events.error) && !this._events.error.length)) {
- er = arguments[1];
- if (er instanceof Error) {
- throw er; // Unhandled 'error' event
- } else {
- // At least give some kind of context to the user
- var err = new Error('Uncaught, unspecified "error" event. (' + er + ')');
- err.context = er;
- throw err;
- }
- }
- }
-
- handler = this._events[type];
-
- if (isUndefined(handler))
- return false;
-
- if (isFunction(handler)) {
- switch (arguments.length) {
- // fast cases
- case 1:
- handler.call(this);
- break;
- case 2:
- handler.call(this, arguments[1]);
- break;
- case 3:
- handler.call(this, arguments[1], arguments[2]);
- break;
- // slower
- default:
- args = Array.prototype.slice.call(arguments, 1);
- handler.apply(this, args);
- }
- } else if (isObject(handler)) {
- args = Array.prototype.slice.call(arguments, 1);
- listeners = handler.slice();
- len = listeners.length;
- for (i = 0; i < len; i++)
- listeners[i].apply(this, args);
- }
-
- return true;
-};
-
-EventEmitter.prototype.addListener = function(type, listener) {
- var m;
-
- if (!isFunction(listener))
- throw TypeError('listener must be a function');
-
- if (!this._events)
- this._events = {};
-
- // To avoid recursion in the case that type === "newListener"! Before
- // adding it to the listeners, first emit "newListener".
- if (this._events.newListener)
- this.emit('newListener', type,
- isFunction(listener.listener) ?
- listener.listener : listener);
-
- if (!this._events[type])
- // Optimize the case of one listener. Don't need the extra array object.
- this._events[type] = listener;
- else if (isObject(this._events[type]))
- // If we've already got an array, just append.
- this._events[type].push(listener);
- else
- // Adding the second element, need to change to array.
- this._events[type] = [this._events[type], listener];
-
- // Check for listener leak
- if (isObject(this._events[type]) && !this._events[type].warned) {
- if (!isUndefined(this._maxListeners)) {
- m = this._maxListeners;
- } else {
- m = EventEmitter.defaultMaxListeners;
- }
-
- if (m && m > 0 && this._events[type].length > m) {
- this._events[type].warned = true;
- console.error('(node) warning: possible EventEmitter memory ' +
- 'leak detected. %d listeners added. ' +
- 'Use emitter.setMaxListeners() to increase limit.',
- this._events[type].length);
- if (typeof console.trace === 'function') {
- // not supported in IE 10
- console.trace();
- }
- }
- }
-
- return this;
-};
-
-EventEmitter.prototype.on = EventEmitter.prototype.addListener;
-
-EventEmitter.prototype.once = function(type, listener) {
- if (!isFunction(listener))
- throw TypeError('listener must be a function');
-
- var fired = false;
-
- function g() {
- this.removeListener(type, g);
-
- if (!fired) {
- fired = true;
- listener.apply(this, arguments);
- }
- }
-
- g.listener = listener;
- this.on(type, g);
-
- return this;
-};
-
-// emits a 'removeListener' event iff the listener was removed
-EventEmitter.prototype.removeListener = function(type, listener) {
- var list, position, length, i;
-
- if (!isFunction(listener))
- throw TypeError('listener must be a function');
-
- if (!this._events || !this._events[type])
- return this;
-
- list = this._events[type];
- length = list.length;
- position = -1;
-
- if (list === listener ||
- (isFunction(list.listener) && list.listener === listener)) {
- delete this._events[type];
- if (this._events.removeListener)
- this.emit('removeListener', type, listener);
-
- } else if (isObject(list)) {
- for (i = length; i-- > 0;) {
- if (list[i] === listener ||
- (list[i].listener && list[i].listener === listener)) {
- position = i;
- break;
- }
- }
-
- if (position < 0)
- return this;
-
- if (list.length === 1) {
- list.length = 0;
- delete this._events[type];
- } else {
- list.splice(position, 1);
- }
-
- if (this._events.removeListener)
- this.emit('removeListener', type, listener);
- }
-
- return this;
-};
-
-EventEmitter.prototype.removeAllListeners = function(type) {
- var key, listeners;
-
- if (!this._events)
- return this;
-
- // not listening for removeListener, no need to emit
- if (!this._events.removeListener) {
- if (arguments.length === 0)
- this._events = {};
- else if (this._events[type])
- delete this._events[type];
- return this;
- }
-
- // emit removeListener for all listeners on all events
- if (arguments.length === 0) {
- for (key in this._events) {
- if (key === 'removeListener') continue;
- this.removeAllListeners(key);
- }
- this.removeAllListeners('removeListener');
- this._events = {};
- return this;
- }
-
- listeners = this._events[type];
-
- if (isFunction(listeners)) {
- this.removeListener(type, listeners);
- } else if (listeners) {
- // LIFO order
- while (listeners.length)
- this.removeListener(type, listeners[listeners.length - 1]);
- }
- delete this._events[type];
-
- return this;
-};
-
-EventEmitter.prototype.listeners = function(type) {
- var ret;
- if (!this._events || !this._events[type])
- ret = [];
- else if (isFunction(this._events[type]))
- ret = [this._events[type]];
- else
- ret = this._events[type].slice();
- return ret;
-};
-
-EventEmitter.prototype.listenerCount = function(type) {
- if (this._events) {
- var evlistener = this._events[type];
-
- if (isFunction(evlistener))
- return 1;
- else if (evlistener)
- return evlistener.length;
- }
- return 0;
-};
-
-EventEmitter.listenerCount = function(emitter, type) {
- return emitter.listenerCount(type);
-};
-
-function isFunction(arg) {
- return typeof arg === 'function';
-}
-
-function isNumber(arg) {
- return typeof arg === 'number';
-}
-
-function isObject(arg) {
- return typeof arg === 'object' && arg !== null;
-}
-
-function isUndefined(arg) {
- return arg === void 0;
-}
-
-
-/***/ }),
-/* 13 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-// 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
-// Writable.
-
-
-
-/**/
-
-var objectKeys = Object.keys || function (obj) {
- var keys = [];
- for (var key in obj) {
- keys.push(key);
- }return keys;
-};
-/**/
-
-module.exports = Duplex;
-
-/**/
-var processNextTick = __webpack_require__(34);
-/**/
-
-/**/
-var util = __webpack_require__(20);
-util.inherits = __webpack_require__(10);
-/**/
-
-var Readable = __webpack_require__(58);
-var Writable = __webpack_require__(36);
-
-util.inherits(Duplex, Readable);
-
-var keys = objectKeys(Writable.prototype);
-for (var v = 0; v < keys.length; v++) {
- var method = keys[v];
- if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];
-}
-
-function Duplex(options) {
- if (!(this instanceof Duplex)) return new Duplex(options);
-
- Readable.call(this, options);
- Writable.call(this, options);
-
- if (options && options.readable === false) this.readable = false;
-
- if (options && options.writable === false) this.writable = false;
-
- this.allowHalfOpen = true;
- if (options && options.allowHalfOpen === false) this.allowHalfOpen = false;
-
- this.once('end', onend);
-}
-
-// the no-half-open enforcer
-function onend() {
- // if we allow half-open state, or if the writable side ended,
- // then we're ok.
- if (this.allowHalfOpen || this._writableState.ended) return;
-
- // no more data can be written.
- // But allow more writes to happen in this tick.
- processNextTick(onEndNT, this);
-}
-
-function onEndNT(self) {
- self.end();
-}
-
-function forEach(xs, f) {
- for (var i = 0, l = xs.length; i < l; i++) {
- f(xs[i], i);
- }
-}
-
-/***/ }),
-/* 14 */
-/***/ (function(module, exports, __webpack_require__) {
-
-const Snowflake = __webpack_require__(6);
-
-/**
- * Represents any channel on Discord.
- */
-class Channel {
- constructor(client, data) {
- /**
- * 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 unique ID of the channel
- * @type {Snowflake}
- */
- this.id = data.id;
- }
-
- /**
- * The timestamp the channel was created at
- * @type {number}
- * @readonly
- */
- get createdTimestamp() {
- return Snowflake.deconstruct(this.id).timestamp;
- }
-
- /**
- * The time the channel was created
- * @type {Date}
- * @readonly
- */
- get createdAt() {
- return new Date(this.createdTimestamp);
- }
-
- /**
- * Deletes the channel.
- * @returns {Promise}
- * @example
- * // Delete the channel
- * channel.delete()
- * .then() // Success
- * .catch(console.error); // Log error
- */
- delete() {
- return this.client.rest.methods.deleteChannel(this);
- }
-}
-
-module.exports = Channel;
-
-
-/***/ }),
-/* 15 */
-/***/ (function(module, exports, __webpack_require__) {
-
-const Snowflake = __webpack_require__(6);
-const Permissions = __webpack_require__(8);
-
-/**
- * Represents a role on Discord.
- */
-class Role {
- constructor(guild, data) {
- /**
- * The client that instantiated the role
- * @name Role#client
- * @type {Client}
- * @readonly
- */
- Object.defineProperty(this, 'client', { value: guild.client });
-
- /**
- * The guild that the role belongs to
- * @type {Guild}
- */
- this.guild = guild;
-
- if (data) this.setup(data);
- }
-
- setup(data) {
- /**
- * The ID of the role (unique to the guild it is part of)
- * @type {Snowflake}
- */
- this.id = data.id;
-
- /**
- * The name of the role
- * @type {string}
- */
- this.name = data.name;
-
- /**
- * The base 10 color of the role
- * @type {number}
- */
- this.color = data.color;
-
- /**
- * If true, users that are part of this role will appear in a separate category in the users list
- * @type {boolean}
- */
- this.hoist = data.hoist;
-
- /**
- * The position of the role from the API
- * @type {number}
- */
- this.position = data.position;
-
- /**
- * The permissions bitfield of the role
- * @type {number}
- */
- this.permissions = data.permissions;
-
- /**
- * Whether or not the role is managed by an external service
- * @type {boolean}
- */
- this.managed = data.managed;
-
- /**
- * Whether or not the role can be mentioned by anyone
- * @type {boolean}
- */
- this.mentionable = data.mentionable;
- }
-
- /**
- * The timestamp the role was created at
- * @type {number}
- * @readonly
- */
- get createdTimestamp() {
- return Snowflake.deconstruct(this.id).timestamp;
- }
-
- /**
- * The time the role was created
- * @type {Date}
- * @readonly
- */
- get createdAt() {
- return new Date(this.createdTimestamp);
- }
-
- /**
- * The hexadecimal version of the role color, with a leading hashtag
- * @type {string}
- * @readonly
- */
- get hexColor() {
- let col = this.color.toString(16);
- while (col.length < 6) col = `0${col}`;
- return `#${col}`;
- }
-
- /**
- * The cached guild members that have this role
- * @type {Collection}
- * @readonly
- */
- get members() {
- return this.guild.members.filter(m => m.roles.has(this.id));
- }
-
- /**
- * Whether the role is editable by the client user
- * @type {boolean}
- * @readonly
- */
- get editable() {
- if (this.managed) return false;
- const clientMember = this.guild.member(this.client.user);
- if (!clientMember.permissions.has(Permissions.FLAGS.MANAGE_ROLES_OR_PERMISSIONS)) return false;
- return clientMember.highestRole.comparePositionTo(this) > 0;
- }
-
- /**
- * The position of the role in the role manager
- * @type {number}
- * @readonly
- */
- get calculatedPosition() {
- const sorted = this.guild._sortedRoles;
- return sorted.array().indexOf(sorted.get(this.id));
- }
-
- /**
- * Get an object mapping permission names to whether or not the role enables that permission
- * @returns {Object}
- * @example
- * // Print the serialized role permissions
- * console.log(role.serialize());
- */
- serialize() {
- return new Permissions(this.permissions).serialize();
- }
-
- /**
- * Checks if the role has 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`)
- * @returns {boolean}
- * @example
- * // See if a role can ban a member
- * if (role.hasPermission('BAN_MEMBERS')) {
- * console.log('This role can ban members');
- * } else {
- * console.log('This role can\'t ban members');
- * }
- */
- hasPermission(permission, explicit = false, checkAdmin) {
- return new Permissions(this.permissions).has(
- permission, typeof checkAdmin !== 'undefined' ? checkAdmin : !explicit
- );
- }
-
- /**
- * Compares this role's position to another role's.
- * @param {Role} role Role to compare to this one
- * @returns {number} Negative number if the this role's position is lower (other role's is higher),
- * positive number if the this one is higher (other's is lower), 0 if equal
- */
- comparePositionTo(role) {
- return this.constructor.comparePositions(this, role);
- }
-
- /**
- * The data for a role.
- * @typedef {Object} RoleData
- * @property {string} [name] The name of the role
- * @property {ColorResolvable} [color] The color of the role, either a hex string or a base 10 number
- * @property {boolean} [hoist] Whether or not the role should be hoisted
- * @property {number} [position] The position of the role
- * @property {string[]} [permissions] The permissions of the role
- * @property {boolean} [mentionable] Whether or not the role should be mentionable
- */
-
- /**
- * Edits the role.
- * @param {RoleData} data The new data for the role
- * @returns {Promise}
- * @example
- * // Edit a role
- * role.edit({name: 'new role'})
- * .then(r => console.log(`Edited role ${r}`))
- * .catch(console.error);
- */
- edit(data) {
- return this.client.rest.methods.updateGuildRole(this, data);
- }
-
- /**
- * Set a new name for the role.
- * @param {string} name The new name of the role
- * @returns {Promise}
- * @example
- * // Set the name of the role
- * role.setName('new role')
- * .then(r => console.log(`Edited name of role ${r}`))
- * .catch(console.error);
- */
- setName(name) {
- return this.edit({ name });
- }
-
- /**
- * Set a new color for the role.
- * @param {ColorResolvable} color The color of the role
- * @returns {Promise}
- * @example
- * // Set the color of a role
- * role.setColor('#FF0000')
- * .then(r => console.log(`Set color of role ${r}`))
- * .catch(console.error);
- */
- setColor(color) {
- return this.edit({ color });
- }
-
- /**
- * Set whether or not the role should be hoisted.
- * @param {boolean} hoist Whether or not to hoist the role
- * @returns {Promise}
- * @example
- * // Set the hoist of the role
- * role.setHoist(true)
- * .then(r => console.log(`Role hoisted: ${r.hoist}`))
- * .catch(console.error);
- */
- setHoist(hoist) {
- return this.edit({ hoist });
- }
-
- /**
- * Set the position of the role.
- * @param {number} position The position of the role
- * @param {boolean} [relative=false] Move the position relative to its current value
- * @returns {Promise}
- * @example
- * // Set the position of the role
- * role.setPosition(1)
- * .then(r => console.log(`Role position: ${r.position}`))
- * .catch(console.error);
- */
- setPosition(position, relative) {
- return this.guild.setRolePosition(this, position, relative).then(() => this);
- }
-
- /**
- * Set the permissions of the role.
- * @param {string[]} permissions The permissions of the role
- * @returns {Promise}
- * @example
- * // Set the permissions of the role
- * role.setPermissions(['KICK_MEMBERS', 'BAN_MEMBERS'])
- * .then(r => console.log(`Role updated ${r}`))
- * .catch(console.error);
- */
- setPermissions(permissions) {
- return this.edit({ permissions });
- }
-
- /**
- * Set whether this role is mentionable.
- * @param {boolean} mentionable Whether this role should be mentionable
- * @returns {Promise}
- * @example
- * // Make the role mentionable
- * role.setMentionable(true)
- * .then(r => console.log(`Role updated ${r}`))
- * .catch(console.error);
- */
- setMentionable(mentionable) {
- return this.edit({ mentionable });
- }
-
- /**
- * Deletes the role.
- * @returns {Promise}
- * @example
- * // Delete a role
- * role.delete()
- * .then(r => console.log(`Deleted role ${r}`))
- * .catch(console.error);
- */
- delete() {
- return this.client.rest.methods.deleteGuildRole(this);
- }
-
- /**
- * Whether this role equals another role. It compares all properties, so for most operations
- * it is advisable to just compare `role.id === role2.id` as it is much faster and is often
- * what most users need.
- * @param {Role} role Role to compare with
- * @returns {boolean}
- */
- equals(role) {
- return role &&
- this.id === role.id &&
- this.name === role.name &&
- this.color === role.color &&
- this.hoist === role.hoist &&
- this.position === role.position &&
- this.permissions === role.permissions &&
- this.managed === role.managed;
- }
-
- /**
- * When concatenated with a string, this automatically concatenates the role mention rather than the Role object.
- * @returns {string}
- */
- toString() {
- if (this.id === this.guild.id) return '@everyone';
- return `<@&${this.id}>`;
- }
-
- /**
- * Compares the positions of two roles.
- * @param {Role} role1 First role to compare
- * @param {Role} role2 Second role to compare
- * @returns {number} Negative number if the first role's position is lower (second role's is higher),
- * positive number if the first's is higher (second's is lower), 0 if equal
- */
- static comparePositions(role1, role2) {
- if (role1.position === role2.position) return role2.id - role1.id;
- return role1.position - role2.position;
- }
-}
-
-module.exports = Role;
-
-
-/***/ }),
-/* 16 */
-/***/ (function(module, exports, __webpack_require__) {
-
-const TextBasedChannel = __webpack_require__(22);
-const Constants = __webpack_require__(0);
-const Presence = __webpack_require__(11).Presence;
-const Snowflake = __webpack_require__(6);
-
-/**
- * Represents a user on Discord.
- * @implements {TextBasedChannel}
- */
-class User {
- constructor(client, data) {
- /**
- * The client that created the instance of the the user
- * @name User#client
- * @type {}
- * @readonly
- */
- Object.defineProperty(this, 'client', { value: client });
-
- if (data) this.setup(data);
- }
-
- setup(data) {
- /**
- * 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 user was created at
- * @type {number}
- * @readonly
- */
- get createdTimestamp() {
- return Snowflake.deconstruct(this.id).timestamp;
- }
-
- /**
- * The time the user was created
- * @type {Date}
- * @readonly
- */
- get createdAt() {
- return new Date(this.createdTimestamp);
- }
-
- /**
- * The presence of this user
- * @type {Presence}
- * @readonly
- */
- 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
- * @param {string} [format='webp'] One of `webp`, `png`, `jpg`, `gif`. If no format is provided, it will be `gif`
- * for animated avatars or otherwise `webp`
- * @param {number} [size=128] One of `128`, '256', `512`, `1024`, `2048`
- * @returns {?string} avatarURL
- */
- avatarURL(format, size) {
- if (!this.avatar) return null;
- if (typeof format === 'number') {
- size = format;
- format = 'default';
- }
- return Constants.Endpoints.User(this).Avatar(this.client.options.http.cdn, this.avatar, format, size);
- }
-
- /**
- * A link to the user's default avatar
- * @type {string}
- * @readonly
- */
- get defaultAvatarURL() {
- return Constants.Endpoints.CDN(this.client.options.http.host).DefaultAvatar(this.discriminator % 5);
- }
-
- /**
- * 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() {}
-}
-
-TextBasedChannel.applyToClass(User);
-
-module.exports = User;
-
-
-/***/ }),
-/* 17 */
-/***/ (function(module, exports, __webpack_require__) {
-
-const Constants = __webpack_require__(0);
-const Collection = __webpack_require__(3);
-const Snowflake = __webpack_require__(6);
-
-/**
- * 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;
-
-
-/***/ }),
-/* 18 */
-/***/ (function(module, exports, __webpack_require__) {
-
-const TextBasedChannel = __webpack_require__(22);
-const Role = __webpack_require__(15);
-const Permissions = __webpack_require__(8);
-const Collection = __webpack_require__(3);
-const Presence = __webpack_require__(11).Presence;
-
-/**
- * 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(Permissions.ALL);
-
- let permissions = 0;
- const roles = this.roles;
- for (const role of roles.values()) permissions |= role.permissions;
-
- return new Permissions(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, 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() {}
-}
-
-TextBasedChannel.applyToClass(GuildMember);
-
-module.exports = GuildMember;
-
-
-/***/ }),
-/* 19 */
-/***/ (function(module, exports, __webpack_require__) {
-
const Mentions = __webpack_require__(49);
const Attachment = __webpack_require__(46);
const Embed = __webpack_require__(48);
@@ -5621,7 +3317,7 @@ const ReactionCollector = __webpack_require__(54);
const Util = __webpack_require__(4);
const Collection = __webpack_require__(3);
const Constants = __webpack_require__(0);
-const Permissions = __webpack_require__(8);
+const Permissions = __webpack_require__(10);
let GuildMember;
/**
@@ -5963,7 +3659,7 @@ class Message {
*/
isMemberMentioned(member) {
// Lazy-loading is used here to get around a circular dependency that breaks things
- if (!GuildMember) GuildMember = __webpack_require__(18);
+ if (!GuildMember) GuildMember = __webpack_require__(19);
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;
@@ -5995,7 +3691,27 @@ class Message {
} else if (!options) {
options = {};
}
- return this.client.rest.methods.updateMessage(this, content, options);
+
+ if (typeof content !== 'undefined') content = this.client.resolver.resolveString(content);
+
+ const { embed, code, reply } = options;
+
+ // Wrap everything in a code block
+ if (typeof code !== 'undefined' && (typeof code !== 'boolean' || code === true)) {
+ content = Util.escapeMarkdown(this.client.resolver.resolveString(content), true);
+ content = `\`\`\`${typeof code !== 'boolean' ? code || '' : ''}\n${content}\n\`\`\``;
+ }
+
+ // Add the reply prefix
+ if (reply && this.channel.type !== 'dm') {
+ const id = this.client.resolver.resolveUserID(reply);
+ const mention = `<@${reply instanceof GuildMember && reply.nickname ? '!' : ''}${id}>`;
+ content = `${mention}${content ? `, ${content}` : ''}`;
+ }
+
+ return this.client.api.channels(this.channel.id).messages(this.id)
+ .patch({ data: { content, embed } })
+ .then(data => this.client.actions.MessageUpdate.handle(data).updated);
}
/**
@@ -6003,7 +3719,8 @@ class Message {
* @returns {Promise}
*/
pin() {
- return this.client.rest.methods.pinMessage(this);
+ return this.client.api.channels(this.channel.id).pins(this.id).put()
+ .then(() => this);
}
/**
@@ -6011,7 +3728,8 @@ class Message {
* @returns {Promise}
*/
unpin() {
- return this.client.rest.methods.unpinMessage(this);
+ return this.client.api.channels(this.channel.id).pins(this.id).delete()
+ .then(() => this);
}
/**
@@ -6023,7 +3741,9 @@ class Message {
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);
+ return this.client.api.channels(this.channel.id).messages(this.id).reactions(emoji)['@me']
+ .put()
+ .then(() => this._addReaction(Util.parseEmoji(emoji), this.client.user));
}
/**
@@ -6031,12 +3751,15 @@ class Message {
* @returns {Promise}
*/
clearReactions() {
- return this.client.rest.methods.removeMessageReactions(this);
+ return this.client.api.channels(this.channel.id).messages(this.id).reactions.delete()
+ .then(() => this);
}
/**
* Deletes the message.
- * @param {number} [timeout=0] How long to wait to delete the message in milliseconds
+ * @param {Object} [options] Options
+ * @param {number} [options.timeout=0] How long to wait to delete the message in milliseconds
+ * @param {string} [options.reason] Reason for deleting this message, if it does not belong to the client user
* @returns {Promise}
* @example
* // Delete a message
@@ -6044,13 +3767,19 @@ class Message {
* .then(msg => console.log(`Deleted message from ${msg.author}`))
* .catch(console.error);
*/
- delete(timeout = 0) {
+ delete({ timeout = 0, reason } = {}) {
if (timeout <= 0) {
- return this.client.rest.methods.deleteMessage(this);
+ return this.client.api.channels(this.channel.id).messages(this.id)
+ .delete({ reason })
+ .then(() =>
+ this.client.actions.MessageDelete.handle({
+ id: this.id,
+ channel_id: this.channel.id,
+ }).message);
} else {
return new Promise(resolve => {
this.client.setTimeout(() => {
- resolve(this.delete());
+ resolve(this.delete({ reason }));
}, timeout);
});
}
@@ -6083,7 +3812,12 @@ class Message {
* @returns {Promise}
*/
acknowledge() {
- return this.client.rest.methods.ackMessage(this);
+ return this.client.api.channels(this.channel.id).messages(this.id).ack
+ .post({ data: { token: this.client.rest._ackToken } })
+ .then(res => {
+ if (res.token) this.client.rest._ackToken = res.token;
+ return this;
+ });
}
/**
@@ -6175,10 +3909,634 @@ module.exports = Message;
/***/ }),
-/* 20 */
+/* 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, __webpack_require__) {
-/* WEBPACK VAR INJECTION */(function(Buffer) {// Copyright Joyent, Inc. and other Node contributors.
+const Constants = __webpack_require__(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.
+ */
+class Permissions {
+ /**
+ * @param {number|PermissionResolvable[]} permissions Permissions or bitfield to read from
+ */
+ constructor(permissions) {
+ /**
+ * Bitfield of the packed permissions
+ * @type {number}
+ */
+ this.bitfield = typeof permissions === 'number' ? permissions : this.constructor.resolve(permissions);
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * 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)
+ * - `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_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,
+ 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_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;
+
+module.exports = Permissions;
+
+
+/***/ }),
+/* 11 */
+/***/ (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
+ }
+}
+
+
+/***/ }),
+/* 12 */
+/***/ (function(module, exports, __webpack_require__) {
+
+const TextBasedChannel = __webpack_require__(24);
+const Constants = __webpack_require__(0);
+const Presence = __webpack_require__(13).Presence;
+const UserProfile = __webpack_require__(185);
+const Snowflake = __webpack_require__(6);
+
+/**
+ * Represents a user on Discord.
+ * @implements {TextBasedChannel}
+ */
+class User {
+ constructor(client, data) {
+ /**
+ * The client that created the instance of the the user
+ * @name User#client
+ * @type {}
+ * @readonly
+ */
+ Object.defineProperty(this, 'client', { value: client });
+
+ if (data) this.setup(data);
+ }
+
+ setup(data) {
+ /**
+ * 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 user was created at
+ * @type {number}
+ * @readonly
+ */
+ get createdTimestamp() {
+ return Snowflake.deconstruct(this.id).timestamp;
+ }
+
+ /**
+ * The time the user was created
+ * @type {Date}
+ * @readonly
+ */
+ get createdAt() {
+ return new Date(this.createdTimestamp);
+ }
+
+ /**
+ * The presence of this user
+ * @type {Presence}
+ * @readonly
+ */
+ 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
+ * @param {string} [format='webp'] One of `webp`, `png`, `jpg`, `gif`. If no format is provided, it will be `gif`
+ * for animated avatars or otherwise `webp`
+ * @param {number} [size=128] One of `128`, '256', `512`, `1024`, `2048`
+ * @returns {?string} avatarURL
+ */
+ avatarURL(format, size) {
+ if (!this.avatar) return null;
+ if (typeof format === 'number') {
+ size = format;
+ format = 'default';
+ }
+ return Constants.Endpoints.CDN(this.client.options.http.cdn).Avatar(this.id, this.avatar, format, size);
+ }
+
+ /**
+ * A link to the user's default avatar
+ * @type {string}
+ * @readonly
+ */
+ get defaultAvatarURL() {
+ return Constants.Endpoints.CDN(this.client.options.http.host).DefaultAvatar(this.discriminator % 5);
+ }
+
+ /**
+ * 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() {
+ if (this.dmChannel) return Promise.resolve(this.dmChannel);
+ return this.client.api.users(this.client.user.id).channels.post({ data: {
+ recipient_id: this.id,
+ } })
+ .then(data => this.client.actions.ChannelCreate.handle(data).channel);
+ }
+
+ /**
+ * Deletes a DM channel (if one exists) between the client and the user. Resolves with the channel if successful.
+ * @returns {Promise}
+ */
+ deleteDM() {
+ if (!this.dmChannel) return Promise.reject(new Error('No DM Channel exists!'));
+ return this.client.api.channels(this.dmChannel.id).delete().then(data =>
+ this.client.actions.ChannelDelete.handle(data).channel
+ );
+ }
+
+ /**
+ * Get the profile of the user.
+ * This is only available when using a user account.
+ * @returns {Promise}
+ */
+ fetchProfile() {
+ return this.client.api.users(this.id).profile.get().then(data => new UserProfile(data));
+ }
+
+ /**
+ * 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.api.users('@me').notes(this.id).put({ data: { note } })
+ .then(() => this);
+ }
+
+ /**
+ * 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() {}
+}
+
+TextBasedChannel.applyToClass(User);
+
+module.exports = User;
+
+
+/***/ }),
+/* 13 */
+/***/ (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;
+
+
+/***/ }),
+/* 14 */
+/***/ (function(module, exports) {
+
+// 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
@@ -6199,590 +4557,690 @@ module.exports = Message;
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
-// NOTE: These type checking functions intentionally don't use `instanceof`
-// because it is fragile and can be easily faked with `Object.create()`.
+function EventEmitter() {
+ this._events = this._events || {};
+ this._maxListeners = this._maxListeners || undefined;
+}
+module.exports = EventEmitter;
-function isArray(arg) {
- if (Array.isArray) {
- return Array.isArray(arg);
+// Backwards-compat with node 0.10.x
+EventEmitter.EventEmitter = EventEmitter;
+
+EventEmitter.prototype._events = undefined;
+EventEmitter.prototype._maxListeners = undefined;
+
+// By default EventEmitters will print a warning if more than 10 listeners are
+// added to it. This is a useful default which helps finding memory leaks.
+EventEmitter.defaultMaxListeners = 10;
+
+// Obviously not all Emitters should be limited to 10. This function allows
+// that to be increased. Set to zero for unlimited.
+EventEmitter.prototype.setMaxListeners = function(n) {
+ if (!isNumber(n) || n < 0 || isNaN(n))
+ throw TypeError('n must be a positive number');
+ this._maxListeners = n;
+ return this;
+};
+
+EventEmitter.prototype.emit = function(type) {
+ var er, handler, len, args, i, listeners;
+
+ if (!this._events)
+ this._events = {};
+
+ // If there is no 'error' event listener then throw.
+ if (type === 'error') {
+ if (!this._events.error ||
+ (isObject(this._events.error) && !this._events.error.length)) {
+ er = arguments[1];
+ if (er instanceof Error) {
+ throw er; // Unhandled 'error' event
+ } else {
+ // At least give some kind of context to the user
+ var err = new Error('Uncaught, unspecified "error" event. (' + er + ')');
+ err.context = er;
+ throw err;
+ }
+ }
}
- return objectToString(arg) === '[object Array]';
-}
-exports.isArray = isArray;
-function isBoolean(arg) {
- return typeof arg === 'boolean';
-}
-exports.isBoolean = isBoolean;
+ handler = this._events[type];
-function isNull(arg) {
- return arg === null;
-}
-exports.isNull = isNull;
+ if (isUndefined(handler))
+ return false;
-function isNullOrUndefined(arg) {
- return arg == null;
-}
-exports.isNullOrUndefined = isNullOrUndefined;
+ if (isFunction(handler)) {
+ switch (arguments.length) {
+ // fast cases
+ case 1:
+ handler.call(this);
+ break;
+ case 2:
+ handler.call(this, arguments[1]);
+ break;
+ case 3:
+ handler.call(this, arguments[1], arguments[2]);
+ break;
+ // slower
+ default:
+ args = Array.prototype.slice.call(arguments, 1);
+ handler.apply(this, args);
+ }
+ } else if (isObject(handler)) {
+ args = Array.prototype.slice.call(arguments, 1);
+ listeners = handler.slice();
+ len = listeners.length;
+ for (i = 0; i < len; i++)
+ listeners[i].apply(this, args);
+ }
-function isNumber(arg) {
- return typeof arg === 'number';
-}
-exports.isNumber = isNumber;
+ return true;
+};
-function isString(arg) {
- return typeof arg === 'string';
-}
-exports.isString = isString;
+EventEmitter.prototype.addListener = function(type, listener) {
+ var m;
-function isSymbol(arg) {
- return typeof arg === 'symbol';
-}
-exports.isSymbol = isSymbol;
+ if (!isFunction(listener))
+ throw TypeError('listener must be a function');
-function isUndefined(arg) {
- return arg === void 0;
-}
-exports.isUndefined = isUndefined;
+ if (!this._events)
+ this._events = {};
-function isRegExp(re) {
- return objectToString(re) === '[object RegExp]';
-}
-exports.isRegExp = isRegExp;
+ // To avoid recursion in the case that type === "newListener"! Before
+ // adding it to the listeners, first emit "newListener".
+ if (this._events.newListener)
+ this.emit('newListener', type,
+ isFunction(listener.listener) ?
+ listener.listener : listener);
-function isObject(arg) {
- return typeof arg === 'object' && arg !== null;
-}
-exports.isObject = isObject;
+ if (!this._events[type])
+ // Optimize the case of one listener. Don't need the extra array object.
+ this._events[type] = listener;
+ else if (isObject(this._events[type]))
+ // If we've already got an array, just append.
+ this._events[type].push(listener);
+ else
+ // Adding the second element, need to change to array.
+ this._events[type] = [this._events[type], listener];
-function isDate(d) {
- return objectToString(d) === '[object Date]';
-}
-exports.isDate = isDate;
+ // Check for listener leak
+ if (isObject(this._events[type]) && !this._events[type].warned) {
+ if (!isUndefined(this._maxListeners)) {
+ m = this._maxListeners;
+ } else {
+ m = EventEmitter.defaultMaxListeners;
+ }
-function isError(e) {
- return (objectToString(e) === '[object Error]' || e instanceof Error);
-}
-exports.isError = isError;
+ if (m && m > 0 && this._events[type].length > m) {
+ this._events[type].warned = true;
+ console.error('(node) warning: possible EventEmitter memory ' +
+ 'leak detected. %d listeners added. ' +
+ 'Use emitter.setMaxListeners() to increase limit.',
+ this._events[type].length);
+ if (typeof console.trace === 'function') {
+ // not supported in IE 10
+ console.trace();
+ }
+ }
+ }
+
+ return this;
+};
+
+EventEmitter.prototype.on = EventEmitter.prototype.addListener;
+
+EventEmitter.prototype.once = function(type, listener) {
+ if (!isFunction(listener))
+ throw TypeError('listener must be a function');
+
+ var fired = false;
+
+ function g() {
+ this.removeListener(type, g);
+
+ if (!fired) {
+ fired = true;
+ listener.apply(this, arguments);
+ }
+ }
+
+ g.listener = listener;
+ this.on(type, g);
+
+ return this;
+};
+
+// emits a 'removeListener' event iff the listener was removed
+EventEmitter.prototype.removeListener = function(type, listener) {
+ var list, position, length, i;
+
+ if (!isFunction(listener))
+ throw TypeError('listener must be a function');
+
+ if (!this._events || !this._events[type])
+ return this;
+
+ list = this._events[type];
+ length = list.length;
+ position = -1;
+
+ if (list === listener ||
+ (isFunction(list.listener) && list.listener === listener)) {
+ delete this._events[type];
+ if (this._events.removeListener)
+ this.emit('removeListener', type, listener);
+
+ } else if (isObject(list)) {
+ for (i = length; i-- > 0;) {
+ if (list[i] === listener ||
+ (list[i].listener && list[i].listener === listener)) {
+ position = i;
+ break;
+ }
+ }
+
+ if (position < 0)
+ return this;
+
+ if (list.length === 1) {
+ list.length = 0;
+ delete this._events[type];
+ } else {
+ list.splice(position, 1);
+ }
+
+ if (this._events.removeListener)
+ this.emit('removeListener', type, listener);
+ }
+
+ return this;
+};
+
+EventEmitter.prototype.removeAllListeners = function(type) {
+ var key, listeners;
+
+ if (!this._events)
+ return this;
+
+ // not listening for removeListener, no need to emit
+ if (!this._events.removeListener) {
+ if (arguments.length === 0)
+ this._events = {};
+ else if (this._events[type])
+ delete this._events[type];
+ return this;
+ }
+
+ // emit removeListener for all listeners on all events
+ if (arguments.length === 0) {
+ for (key in this._events) {
+ if (key === 'removeListener') continue;
+ this.removeAllListeners(key);
+ }
+ this.removeAllListeners('removeListener');
+ this._events = {};
+ return this;
+ }
+
+ listeners = this._events[type];
+
+ if (isFunction(listeners)) {
+ this.removeListener(type, listeners);
+ } else if (listeners) {
+ // LIFO order
+ while (listeners.length)
+ this.removeListener(type, listeners[listeners.length - 1]);
+ }
+ delete this._events[type];
+
+ return this;
+};
+
+EventEmitter.prototype.listeners = function(type) {
+ var ret;
+ if (!this._events || !this._events[type])
+ ret = [];
+ else if (isFunction(this._events[type]))
+ ret = [this._events[type]];
+ else
+ ret = this._events[type].slice();
+ return ret;
+};
+
+EventEmitter.prototype.listenerCount = function(type) {
+ if (this._events) {
+ var evlistener = this._events[type];
+
+ if (isFunction(evlistener))
+ return 1;
+ else if (evlistener)
+ return evlistener.length;
+ }
+ return 0;
+};
+
+EventEmitter.listenerCount = function(emitter, type) {
+ return emitter.listenerCount(type);
+};
function isFunction(arg) {
return typeof arg === 'function';
}
-exports.isFunction = isFunction;
-function isPrimitive(arg) {
- return arg === null ||
- typeof arg === 'boolean' ||
- typeof arg === 'number' ||
- typeof arg === 'string' ||
- typeof arg === 'symbol' || // ES6 symbol
- typeof arg === 'undefined';
-}
-exports.isPrimitive = isPrimitive;
-
-exports.isBuffer = Buffer.isBuffer;
-
-function objectToString(o) {
- return Object.prototype.toString.call(o);
+function isNumber(arg) {
+ return typeof arg === 'number';
}
-/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(5).Buffer))
+function isObject(arg) {
+ return typeof arg === 'object' && arg !== null;
+}
-/***/ }),
-/* 21 */
-/***/ (function(module, exports, __webpack_require__) {
-
-exports = module.exports = __webpack_require__(58);
-exports.Stream = exports;
-exports.Readable = exports;
-exports.Writable = __webpack_require__(36);
-exports.Duplex = __webpack_require__(13);
-exports.Transform = __webpack_require__(59);
-exports.PassThrough = __webpack_require__(84);
+function isUndefined(arg) {
+ return arg === void 0;
+}
/***/ }),
-/* 22 */
+/* 15 */
/***/ (function(module, exports, __webpack_require__) {
-const path = __webpack_require__(27);
-const Message = __webpack_require__(19);
-const MessageCollector = __webpack_require__(47);
-const Collection = __webpack_require__(3);
+"use strict";
+// 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
+// Writable.
+
+
+
+/**/
+
+var objectKeys = Object.keys || function (obj) {
+ var keys = [];
+ for (var key in obj) {
+ keys.push(key);
+ }return keys;
+};
+/**/
+
+module.exports = Duplex;
+
+/**/
+var processNextTick = __webpack_require__(35);
+/**/
+
+/**/
+var util = __webpack_require__(22);
+util.inherits = __webpack_require__(11);
+/**/
+
+var Readable = __webpack_require__(58);
+var Writable = __webpack_require__(37);
+
+util.inherits(Duplex, Readable);
+
+var keys = objectKeys(Writable.prototype);
+for (var v = 0; v < keys.length; v++) {
+ var method = keys[v];
+ if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];
+}
+
+function Duplex(options) {
+ if (!(this instanceof Duplex)) return new Duplex(options);
+
+ Readable.call(this, options);
+ Writable.call(this, options);
+
+ if (options && options.readable === false) this.readable = false;
+
+ if (options && options.writable === false) this.writable = false;
+
+ this.allowHalfOpen = true;
+ if (options && options.allowHalfOpen === false) this.allowHalfOpen = false;
+
+ this.once('end', onend);
+}
+
+// the no-half-open enforcer
+function onend() {
+ // if we allow half-open state, or if the writable side ended,
+ // then we're ok.
+ if (this.allowHalfOpen || this._writableState.ended) return;
+
+ // no more data can be written.
+ // But allow more writes to happen in this tick.
+ processNextTick(onEndNT, this);
+}
+
+function onEndNT(self) {
+ self.end();
+}
+
+function forEach(xs, f) {
+ for (var i = 0, l = xs.length; i < l; i++) {
+ f(xs[i], i);
+ }
+}
+
+/***/ }),
+/* 16 */
+/***/ (function(module, exports, __webpack_require__) {
+
+const Snowflake = __webpack_require__(6);
/**
- * Interface for classes that have text-channel-like features.
- * @interface
+ * Represents any channel on Discord.
*/
-class TextBasedChannel {
- constructor() {
+class Channel {
+ constructor(client, data) {
/**
- * A collection containing the messages sent to this channel
- * @type {Collection}
+ * The client that instantiated the Channel
+ * @name Channel#client
+ * @type {Client}
+ * @readonly
*/
- this.messages = new Collection();
+ Object.defineProperty(this, 'client', { value: client });
/**
- * The ID of the last message in the channel, if one was sent
- * @type {?Snowflake}
+ * 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.lastMessageID = null;
+ this.type = null;
+ if (data) this.setup(data);
+ }
+
+ setup(data) {
/**
- * The Message object of the last message in the channel, if one was sent
- * @type {?Message}
+ * The unique ID of the channel
+ * @type {Snowflake}
*/
- this.lastMessage = null;
+ this.id = data.id;
}
/**
- * Options provided when sending or editing a message.
- * @typedef {Object} MessageOptions
- * @property {boolean} [tts=false] Whether or not the message should be spoken aloud
- * @property {string} [nonce=''] The nonce for the message
- * @property {RichEmbed|Object} [embed] An embed 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[]} [files] Files 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
- * @property {UserResolvable} [reply] User to reply to (prefixes the message with a mention, except in DMs)
- */
-
- /**
- * @typedef {Object} FileOptions
- * @property {BufferResolvable} attachment File to attach
- * @property {string} [name='file.jpg'] Filename of the attachment
- */
-
- /**
- * Options for splitting a message.
- * @typedef {Object} SplitOptions
- * @property {number} [maxLength=1950] Maximum character length per message piece
- * @property {string} [char='\n'] Character to split the message with
- * @property {string} [prepend=''] Text to prepend to every piece except the first
- * @property {string} [append=''] Text to append to every piece except the last
- */
-
- /**
- * Send a message to this channel.
- * @param {StringResolvable} [content] Text for the message
- * @param {MessageOptions} [options={}] Options for the message
- * @returns {Promise}
- * @example
- * // Send a message
- * channel.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.embed && options.embed.file) options.file = options.embed.file;
-
- 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';
- }
- }
- options.files[i] = file;
- }
-
- return Promise.all(options.files.map(file =>
- this.client.resolver.resolveBuffer(file.attachment).then(buffer => {
- file.file = buffer;
- return file;
- })
- )).then(files => this.client.rest.methods.sendMessage(this, content, options, files));
- }
-
- return this.client.rest.methods.sendMessage(this, content, options);
- }
-
- /**
- * Gets a single message from this channel, regardless of it being cached or not. Since the single message fetching
- * endpoint is reserved for bot accounts, this abstracts the `fetchMessages` method to obtain the single message when
- * using a user account.
- * @param {Snowflake} messageID ID of the message to get
- * @returns {Promise}
- * @example
- * // Get message
- * channel.fetchMessage('99539446449315840')
- * .then(message => console.log(message.content))
- * .catch(console.error);
- */
- fetchMessage(messageID) {
- if (!this.client.user.bot) {
- return this.fetchMessages({ limit: 1, around: messageID }).then(messages => {
- const msg = messages.get(messageID);
- if (!msg) throw new Error('Message not found.');
- return msg;
- });
- }
- return this.client.rest.methods.getChannelMessage(this, messageID).then(data => {
- const msg = data instanceof Message ? data : new Message(this, data, this.client);
- this._cacheMessage(msg);
- return msg;
- });
- }
-
- /**
- * The parameters to pass in when requesting previous messages from a channel. `around`, `before` and
- * `after` are mutually exclusive. All the parameters are optional.
- * @typedef {Object} ChannelLogsQueryOptions
- * @property {number} [limit=50] Number of messages to acquire
- * @property {Snowflake} [before] ID of a message to get the messages that were posted before it
- * @property {Snowflake} [after] ID of a message to get the messages that were posted after it
- * @property {Snowflake} [around] ID of a message to get the messages that were posted around it
- */
-
- /**
- * Gets the past messages sent in this channel. Resolves with a collection mapping message ID's to Message objects.
- * @param {ChannelLogsQueryOptions} [options={}] Query parameters to pass in
- * @returns {Promise>}
- * @example
- * // Get messages
- * channel.fetchMessages({limit: 10})
- * .then(messages => console.log(`Received ${messages.size} messages`))
- * .catch(console.error);
- */
- fetchMessages(options = {}) {
- return this.client.rest.methods.getChannelMessages(this, options).then(data => {
- const messages = new Collection();
- for (const message of data) {
- const msg = new Message(this, message, this.client);
- messages.set(message.id, msg);
- this._cacheMessage(msg);
- }
- return messages;
- });
- }
-
- /**
- * Fetches the pinned messages of this channel and returns a collection of them.
- * @returns {Promise>}
- */
- fetchPinnedMessages() {
- return this.client.rest.methods.getChannelPinnedMessages(this).then(data => {
- const messages = new Collection();
- for (const message of data) {
- const msg = new Message(this, message, this.client);
- messages.set(message.id, msg);
- this._cacheMessage(msg);
- }
- return messages;
- });
- }
-
- /**
- * @typedef {Object} MessageSearchOptions
- * @property {string} [content] Message content
- * @property {Snowflake} [maxID] Maximum ID for the filter
- * @property {Snowflake} [minID] Minimum ID for the filter
- * @property {string} [has] One of `link`, `embed`, `file`, `video`, `image`, or `sound`,
- * or add `-` to negate (e.g. `-file`)
- * @property {ChannelResolvable} [channel] Channel to limit search to (only for guild search endpoint)
- * @property {UserResolvable} [author] Author to limit search
- * @property {string} [authorType] One of `user`, `bot`, `webhook`, or add `-` to negate (e.g. `-webhook`)
- * @property {string} [sortBy='recent'] `recent` or `relevant`
- * @property {string} [sortOrder='desc'] `asc` or `desc`
- * @property {number} [contextSize=2] How many messages to get around the matched message (0 to 2)
- * @property {number} [limit=25] Maximum number of results to get (1 to 25)
- * @property {number} [offset=0] Offset the "pages" of results (since you can only see 25 at a time)
- * @property {UserResolvable} [mentions] Mentioned user filter
- * @property {boolean} [mentionsEveryone] If everyone is mentioned
- * @property {string} [linkHostname] Filter links by hostname
- * @property {string} [embedProvider] The name of an embed provider
- * @property {string} [embedType] one of `image`, `video`, `url`, `rich`
- * @property {string} [attachmentFilename] The name of an attachment
- * @property {string} [attachmentExtension] The extension of an attachment
- * @property {Date} [before] Date to find messages before
- * @property {Date} [after] Date to find messages before
- * @property {Date} [during] Date to find messages during (range of date to date + 24 hours)
- */
-
- /**
- * Performs a search within the channel.
- * This is only available when using a user account.
- * @param {MessageSearchOptions} [options={}] Options to pass to the search
- * @returns {Promise>}
- * An array containing arrays of messages. Each inner array is a search context cluster
- * The message which has triggered the result will have the `hit` property set to `true`
- * @example
- * channel.search({
- * content: 'discord.js',
- * before: '2016-11-17'
- * }).then(res => {
- * const hit = res.messages[0].find(m => m.hit).content;
- * console.log(`I found: **${hit}**, total results: ${res.totalResults}`);
- * }).catch(console.error);
- */
- search(options = {}) {
- return this.client.rest.methods.search(this, options);
- }
-
- /**
- * Starts a typing indicator in the channel.
- * @param {number} [count] The number of times startTyping should be considered to have been called
- * @example
- * // Start typing in a channel
- * channel.startTyping();
- */
- startTyping(count) {
- if (typeof count !== 'undefined' && count < 1) throw new RangeError('Count must be at least 1.');
- if (!this.client.user._typing.has(this.id)) {
- this.client.user._typing.set(this.id, {
- count: count || 1,
- interval: this.client.setInterval(() => {
- this.client.rest.methods.sendTyping(this.id);
- }, 9000),
- });
- this.client.rest.methods.sendTyping(this.id);
- } else {
- const entry = this.client.user._typing.get(this.id);
- entry.count = count || entry.count + 1;
- }
- }
-
- /**
- * Stops the typing indicator in the channel.
- * The indicator will only stop if this is called as many times as startTyping().
- * It can take a few seconds for the client user to stop typing.
- * @param {boolean} [force=false] Whether or not to reset the call count and force the indicator to stop
- * @example
- * // Stop typing in a channel
- * channel.stopTyping();
- * @example
- * // Force typing to fully stop in a channel
- * channel.stopTyping(true);
- */
- stopTyping(force = false) {
- if (this.client.user._typing.has(this.id)) {
- const entry = this.client.user._typing.get(this.id);
- entry.count--;
- if (entry.count <= 0 || force) {
- this.client.clearInterval(entry.interval);
- this.client.user._typing.delete(this.id);
- }
- }
- }
-
- /**
- * Whether or not the typing indicator is being shown in the channel
- * @type {boolean}
- * @readonly
- */
- get typing() {
- return this.client.user._typing.has(this.id);
- }
-
- /**
- * Number of times `startTyping` has been called
+ * The timestamp the channel was created at
* @type {number}
* @readonly
*/
- get typingCount() {
- if (this.client.user._typing.has(this.id)) return this.client.user._typing.get(this.id).count;
- return 0;
+ get createdTimestamp() {
+ return Snowflake.deconstruct(this.id).timestamp;
}
/**
- * Creates a Message Collector.
- * @param {CollectorFilter} filter The filter to create the collector with
- * @param {MessageCollectorOptions} [options={}] The options to pass to the collector
- * @returns {MessageCollector}
+ * The time the channel was created
+ * @type {Date}
+ * @readonly
+ */
+ get createdAt() {
+ return new Date(this.createdTimestamp);
+ }
+
+ /**
+ * Deletes this channel.
+ * @returns {Promise}
* @example
- * // Create a message collector
- * const collector = channel.createCollector(
- * m => m.content.includes('discord'),
- * { time: 15000 }
- * );
- * collector.on('message', m => console.log(`Collected ${m.content}`));
- * collector.on('end', collected => console.log(`Collected ${collected.size} items`));
+ * // Delete the channel
+ * channel.delete()
+ * .then() // Success
+ * .catch(console.error); // Log error
*/
- createMessageCollector(filter, options = {}) {
- return new MessageCollector(this, filter, options);
- }
-
- /**
- * An object containing the same properties as CollectorOptions, but a few more:
- * @typedef {MessageCollectorOptions} AwaitMessagesOptions
- * @property {string[]} [errors] Stop/end reasons that cause the promise to reject
- */
-
- /**
- * Similar to createCollector but in promise form. Resolves with a collection of messages that pass the specified
- * filter.
- * @param {CollectorFilter} filter The filter function to use
- * @param {AwaitMessagesOptions} [options={}] Optional options to pass to the internal collector
- * @returns {Promise>}
- * @example
- * // Await !vote messages
- * const filter = m => m.content.startsWith('!vote');
- * // Errors: ['time'] treats ending because of the time limit as an error
- * channel.awaitMessages(filter, { max: 4, time: 60000, errors: ['time'] })
- * .then(collected => console.log(collected.size))
- * .catch(collected => console.log(`After a minute, only ${collected.size} out of 4 voted.`));
- */
- awaitMessages(filter, options = {}) {
- return new Promise((resolve, reject) => {
- const collector = this.createMessageCollector(filter, options);
- collector.once('end', (collection, reason) => {
- if (options.errors && options.errors.includes(reason)) {
- reject(collection);
- } else {
- resolve(collection);
- }
- });
- });
- }
-
- /**
- * Bulk delete given messages that are newer than two weeks.
- * This is only available when using a bot account.
- * @param {Collection|Message[]|number} messages Messages or number of messages to delete
- * @param {boolean} [filterOld=false] Filter messages to remove those which are older than two weeks automatically
- * @returns {Promise>} Deleted messages
- */
- bulkDelete(messages, filterOld = false) {
- if (!isNaN(messages)) return this.fetchMessages({ limit: messages }).then(msgs => this.bulkDelete(msgs, filterOld));
- if (messages instanceof Array || messages instanceof Collection) {
- const messageIDs = messages instanceof Collection ? messages.keyArray() : messages.map(m => m.id);
- return this.client.rest.methods.bulkDeleteMessages(this, messageIDs, filterOld);
- }
- throw new TypeError('The messages must be an Array, Collection, or number.');
- }
-
- /**
- * Marks all messages in this channel as read.
- * This is only available when using a user account.
- * @returns {Promise}
- */
- acknowledge() {
- if (!this.lastMessageID) return Promise.resolve(this);
- return this.client.rest.methods.ackTextChannel(this);
- }
-
- _cacheMessage(message) {
- const maxSize = this.client.options.messageCacheMaxSize;
- if (maxSize === 0) return null;
- if (this.messages.size >= maxSize && maxSize > 0) this.messages.delete(this.messages.firstKey());
- this.messages.set(message.id, message);
- return message;
+ delete() {
+ return this.client.api.channels(this.id).delete().then(() => this);
}
}
-exports.applyToClass = (structure, full = false, ignore = []) => {
- const props = ['send'];
- if (full) {
- props.push(
- '_cacheMessage',
- 'acknowledge',
- 'fetchMessages',
- 'fetchMessage',
- 'search',
- 'bulkDelete',
- 'startTyping',
- 'stopTyping',
- 'typing',
- 'typingCount',
- 'fetchPinnedMessages',
- 'createMessageCollector',
- 'awaitMessages'
- );
- }
- for (const prop of props) {
- if (ignore.includes(prop)) continue;
- Object.defineProperty(structure.prototype, prop, Object.getOwnPropertyDescriptor(TextBasedChannel.prototype, prop));
- }
-};
+module.exports = Channel;
/***/ }),
-/* 23 */
-/***/ (function(module, exports) {
-
-exports.endianness = function () { return 'LE' };
-
-exports.hostname = function () {
- if (typeof location !== 'undefined') {
- return location.hostname
- }
- else return '';
-};
-
-exports.loadavg = function () { return [] };
-
-exports.uptime = function () { return 0 };
-
-exports.freemem = function () {
- return Number.MAX_VALUE;
-};
-
-exports.totalmem = function () {
- return Number.MAX_VALUE;
-};
-
-exports.cpus = function () { return [] };
-
-exports.type = function () { return 'Browser' };
-
-exports.release = function () {
- if (typeof navigator !== 'undefined') {
- return navigator.appVersion;
- }
- return '';
-};
-
-exports.networkInterfaces
-= exports.getNetworkInterfaces
-= function () { return {} };
-
-exports.arch = function () { return 'javascript' };
-
-exports.platform = function () { return 'browser' };
-
-exports.tmpdir = exports.tmpDir = function () {
- return '/tmp';
-};
-
-exports.EOL = '\n';
-
-
-/***/ }),
-/* 24 */
+/* 17 */
/***/ (function(module, exports, __webpack_require__) {
-const Long = __webpack_require__(33);
-const User = __webpack_require__(16);
-const Role = __webpack_require__(15);
+const Constants = __webpack_require__(0);
+const Collection = __webpack_require__(3);
+const Snowflake = __webpack_require__(6);
+
+/**
+ * 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
+ * @param {string} [reason] Reason for editing this emoji
+ * @returns {Promise}
+ * @example
+ * // Edit a emoji
+ * emoji.edit({name: 'newemoji'})
+ * .then(e => console.log(`Edited emoji ${e}`))
+ * .catch(console.error);
+ */
+ edit(data, reason) {
+ return this.client.api.guilds(this.guild.id).emojis(this.id)
+ .patch({ data: {
+ name: data.name,
+ roles: data.roles ? data.roles.map(r => r.id ? r.id : r) : [],
+ }, reason })
+ .then(() => this);
+ }
+
+ /**
+ * 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;
+
+
+/***/ }),
+/* 18 */
+/***/ (function(module, exports, __webpack_require__) {
+
+const Long = __webpack_require__(34);
+const User = __webpack_require__(12);
+const Role = __webpack_require__(20);
const Emoji = __webpack_require__(17);
-const Presence = __webpack_require__(11).Presence;
-const GuildMember = __webpack_require__(18);
+const Invite = __webpack_require__(27);
+const GuildAuditLogs = __webpack_require__(45);
+const Webhook = __webpack_require__(21);
+const Presence = __webpack_require__(13).Presence;
+const GuildMember = __webpack_require__(19);
+const VoiceRegion = __webpack_require__(70);
const Constants = __webpack_require__(0);
const Collection = __webpack_require__(3);
const Util = __webpack_require__(4);
const Snowflake = __webpack_require__(6);
+const Permissions = __webpack_require__(10);
+const Shared = __webpack_require__(71);
/**
* Represents a guild (or a server) on Discord.
@@ -7039,7 +5497,7 @@ class Guild {
size = format;
format = 'default';
}
- return Constants.Endpoints.Guild(this).Icon(this.client.options.http.cdn, this.icon, format, size);
+ return Constants.Endpoints.CDN(this.client.options.http.cdn).Icon(this.id, this.icon, format, size);
}
/**
@@ -7058,7 +5516,7 @@ class Guild {
*/
get splashURL() {
if (!this.splash) return null;
- return Constants.Endpoints.Guild(this).Splash(this.client.options.http.cdn, this.splash);
+ return Constants.Endpoints.CDN(this.client.options.http.cdn).Splash(this.id, this.splash);
}
/**
@@ -7145,13 +5603,15 @@ class Guild {
* @returns {Promise>}
*/
fetchBans() {
- return this.client.rest.methods.getGuildBans(this)
- // This entire re-mapping can be removed in the next major release
- .then(bans => {
- const users = new Collection();
- for (const ban of bans.values()) users.set(ban.user.id, ban.user);
- return users;
- });
+ return this.client.api.guilds(this.id).bans.get().then(bans =>
+ bans.reduce((collection, ban) => {
+ collection.set(ban.user.id, {
+ reason: ban.reason,
+ user: this.client.dataManager.newUser(ban.user),
+ });
+ return collection;
+ }, new Collection())
+ );
}
/**
@@ -7159,7 +5619,15 @@ class Guild {
* @returns {Promise>}
*/
fetchInvites() {
- return this.client.rest.methods.getGuildInvites(this);
+ return this.client.api.guilds(this.id).invites.get()
+ .then(inviteItems => {
+ const invites = new Collection();
+ for (const inviteItem of inviteItems) {
+ const invite = new Invite(this.client, inviteItem);
+ invites.set(invite.code, invite);
+ }
+ return invites;
+ });
}
/**
@@ -7167,7 +5635,11 @@ class Guild {
* @returns {Collection}
*/
fetchWebhooks() {
- return this.client.rest.methods.getGuildWebhooks(this);
+ return this.client.api.guilds(this.id).webhooks.get().then(data => {
+ const hooks = new Collection();
+ for (const hook of data) hooks.set(hook.id, new Webhook(this.client, hook));
+ return hooks;
+ });
}
/**
@@ -7175,7 +5647,11 @@ class Guild {
* @returns {Collection}
*/
fetchVoiceRegions() {
- return this.client.rest.methods.fetchVoiceRegions(this.id);
+ return this.client.api.guilds(this.id).regions.get().then(res => {
+ const regions = new Collection();
+ for (const region of res) regions.set(region.id, new VoiceRegion(region));
+ return regions;
+ });
}
/**
@@ -7188,8 +5664,19 @@ class Guild {
* @param {string|number} [options.type] Only show entries involving this action type
* @returns {Promise}
*/
- fetchAuditLogs(options) {
- return this.client.rest.methods.getGuildAuditLogs(this, options);
+ fetchAuditLogs(options = {}) {
+ if (options.before && options.before instanceof GuildAuditLogs.Entry) options.before = options.before.id;
+ if (options.after && options.after instanceof GuildAuditLogs.Entry) options.after = options.after.id;
+ if (typeof options.type === 'string') options.type = GuildAuditLogs.Actions[options.type];
+
+ return this.client.api.guilds(this.id)['audit-logs'].get({ query: {
+ before: options.before,
+ after: options.after,
+ limit: options.limit,
+ user_id: this.client.resolver.resolveUserID(options.user),
+ action_type: options.type,
+ } })
+ .then(data => GuildAuditLogs.build(this, data));
}
/**
@@ -7207,7 +5694,15 @@ class Guild {
*/
addMember(user, options) {
if (this.members.has(user.id)) return Promise.resolve(this.members.get(user.id));
- return this.client.rest.methods.putGuildMember(this, user, options);
+ options.access_token = options.accessToken;
+ if (options.roles) {
+ const roles = options.roles;
+ if (roles instanceof Collection || (roles instanceof Array && roles[0] instanceof Role)) {
+ options.roles = roles.map(role => role.id);
+ }
+ }
+ return this.client.api.guilds(this.id).members(user.id).put({ data: options })
+ .then(data => this.client.actions.GuildMemberGet.handle(this, data).member);
}
/**
@@ -7220,7 +5715,11 @@ class Guild {
user = this.client.resolver.resolveUser(user);
if (!user) return Promise.reject(new Error('User is not cached. Use Client.fetchUser first.'));
if (this.members.has(user.id)) return Promise.resolve(this.members.get(user.id));
- return this.client.rest.methods.getGuildMember(this, user, cache);
+ return this.client.api.guilds(this.id).members(user.id).get()
+ .then(data => {
+ if (cache) return this.client.actions.GuildMemberGet.handle(this, data).member;
+ else return new GuildMember(this, data);
+ });
}
/**
@@ -7277,7 +5776,7 @@ class Guild {
* }).catch(console.error);
*/
search(options = {}) {
- return this.client.rest.methods.search(this, options);
+ return Shared.search(this, options);
}
/**
@@ -7296,6 +5795,7 @@ class Guild {
/**
* Updates the guild with new information - e.g. a new name.
* @param {GuildEditData} data The data to update the guild with
+ * @param {string} [reason] Reason for editing this guild
* @returns {Promise}
* @example
* // Set the guild name and region
@@ -7306,8 +5806,18 @@ class Guild {
* .then(updated => console.log(`New guild name ${updated.name} in region ${updated.region}`))
* .catch(console.error);
*/
- edit(data) {
- return this.client.rest.methods.updateGuild(this, data);
+ edit(data, reason) {
+ const _data = {};
+ if (data.name) _data.name = data.name;
+ if (data.region) _data.region = data.region;
+ if (data.verificationLevel) _data.verification_level = Number(data.verificationLevel);
+ if (data.afkChannel) _data.afk_channel_id = this.client.resolver.resolveChannel(data.afkChannel).id;
+ if (data.afkTimeout) _data.afk_timeout = Number(data.afkTimeout);
+ if (data.icon) _data.icon = this.client.resolver.resolveBase64(data.icon);
+ if (data.owner) _data.owner_id = this.client.resolver.resolveUser(data.owner).id;
+ if (data.splash) _data.splash = this.client.resolver.resolveBase64(data.splash);
+ return this.client.api.guilds(this.id).patch({ data: _data, reason })
+ .then(newData => this.client.actions.GuildUpdate.handle(newData).updated);
}
/**
@@ -7442,7 +5952,12 @@ class Guild {
* @returns {Promise}
*/
acknowledge() {
- return this.client.rest.methods.ackGuild(this);
+ return this.client.api.guilds(this.id).ack
+ .post({ data: { token: this.client.rest._ackToken } })
+ .then(res => {
+ if (res.token) this.client.rest._ackToken = res.token;
+ return this;
+ });
}
/**
@@ -7472,19 +5987,26 @@ class Guild {
* .then(user => console.log(`Banned ${user.username || user.id || user} from ${guild.name}`))
* .catch(console.error);
*/
- ban(user, options = {}) {
- if (typeof options === 'number') {
- options = { reason: null, 'delete-message-days': options };
- } else if (typeof options === 'string') {
- options = { reason: options, 'delete-message-days': 0 };
- }
+ ban(user, options = { days: 0 }) {
if (options.days) options['delete-message-days'] = options.days;
- return this.client.rest.methods.banGuildMember(this, user, options);
+ const id = this.client.resolver.resolveUserID(user);
+ if (!id) return Promise.reject(new Error('Couldn\'t resolve the user ID to ban.'));
+ return this.client.api.guilds(this.id).bans(id).put({ query: options })
+ .then(() => {
+ if (user instanceof GuildMember) return user;
+ const _user = this.client.resolver.resolveUser(id);
+ if (_user) {
+ const member = this.client.resolver.resolveGuildMember(this, _user);
+ return member || _user;
+ }
+ return id;
+ });
}
/**
* Unbans a user from the guild.
* @param {UserResolvable} user The user to unban
+ * @param {string} [reason] Reason for unbanning user
* @returns {Promise}
* @example
* // Unban a user by ID (or with a user/guild member object)
@@ -7492,29 +6014,35 @@ class Guild {
* .then(user => console.log(`Unbanned ${user.username} from ${guild.name}`))
* .catch(console.error);
*/
- unban(user) {
- return this.client.rest.methods.unbanGuildMember(this, user);
+ unban(user, reason) {
+ const id = this.client.resolver.resolveUserID(user);
+ if (!id) throw new Error('Couldn\'t resolve the user ID to unban.');
+
+ return this.client.api.guilds(this.id).bans(id).delete({ reason })
+ .then(() => user);
}
/**
* Prunes members from the guild based on how long they have been inactive.
- * @param {number} days Number of days of inactivity required to kick
- * @param {boolean} [dry=false] If true, will return number of users that will be kicked, without actually doing it
+ * @param {number} [options.days=7] Number of days of inactivity required to kick
+ * @param {boolean} [options.dry=false] Get number of users that will be kicked, without actually kicking them
+ * @param {string} [options.reason] Reason for this prune
* @returns {Promise} The number of members that were/will be kicked
* @example
* // See how many members will be pruned
- * guild.pruneMembers(12, true)
+ * guild.pruneMembers({ dry: true })
* .then(pruned => console.log(`This will prune ${pruned} people!`))
* .catch(console.error);
* @example
* // Actually prune the members
- * guild.pruneMembers(12)
+ * guild.pruneMembers({ days: 1, reason: 'too many people!' })
* .then(pruned => console.log(`I just pruned ${pruned} people!`))
* .catch(console.error);
*/
- pruneMembers(days, dry = false) {
+ pruneMembers({ days = 7, dry = false, reason } = {}) {
if (typeof days !== 'number') throw new TypeError('Days must be a number.');
- return this.client.rest.methods.pruneGuildMembers(this, days, dry);
+ return this.client.api.guilds(this.id).prune[dry ? 'get' : 'post']({ query: { days }, reason })
+ .then(data => data.pruned);
}
/**
@@ -7529,7 +6057,9 @@ class Guild {
* Creates a new channel in the guild.
* @param {string} name The name of the new channel
* @param {string} type The type of the new channel, either `text` or `voice`
- * @param {Array} overwrites Permission overwrites to apply to the new channel
+ * @param {Object} options Options
+ * @param {Array} [options.overwrites] Permission overwrites to apply to the new channel
+ * @param {string} [options.reason] Reason for creating this channel
* @returns {Promise}
* @example
* // Create a new text channel
@@ -7537,8 +6067,14 @@ class Guild {
* .then(channel => console.log(`Created new channel ${channel}`))
* .catch(console.error);
*/
- createChannel(name, type, overwrites) {
- return this.client.rest.methods.createChannel(this, name, type, overwrites);
+ createChannel(name, type, { overwrites, reason } = {}) {
+ if (overwrites instanceof Collection) overwrites = overwrites.array();
+ return this.client.api.guilds(this.id).channels.post({
+ data: {
+ name, type, permission_overwrites: overwrites,
+ },
+ reason,
+ }).then(data => this.client.actions.ChannelCreate.handle(data).channel);
}
/**
@@ -7558,12 +6094,30 @@ class Guild {
* .catch(console.error);
*/
setChannelPositions(channelPositions) {
- return this.client.rest.methods.updateChannelPositions(this.id, channelPositions);
+ const data = new Array(channelPositions.length);
+ for (let i = 0; i < channelPositions.length; i++) {
+ data[i] = {
+ id: this.client.resolver.resolveChannelID(channelPositions[i].channel),
+ position: channelPositions[i].position,
+ };
+ }
+
+ return this.client.api.guilds(this.id).channels.patch({ data: {
+ guild_id: this.id,
+ channels: channelPositions,
+ } }).then(() =>
+ this.client.actions.GuildChannelsPositionUpdate.handle({
+ guild_id: this.id,
+ channels: channelPositions,
+ }).guild
+ );
}
/**
* Creates a new role in the guild with given information
- * @param {RoleData} [data] The data to update the role with
+ * @param {Object} [options] Options
+ * @param {RoleData} [options.data] The data to update the role with
+ * @param {string} [options.reason] Reason for creating this role
* @returns {Promise}
* @example
* // Create a new role
@@ -7571,16 +6125,27 @@ class Guild {
* .then(role => console.log(`Created role ${role}`))
* .catch(console.error);
* @example
- * // Create a new role with data
+ * // Create a new role with data and a reason
* guild.createRole({
- * name: 'Super Cool People',
- * color: 'BLUE',
+ * data: {
+ * name: 'Super Cool People',
+ * color: 'BLUE',
+ * },
+ * reason: 'we needed a role for Super Cool People',
* })
* .then(role => console.log(`Created role ${role}`))
* .catch(console.error)
*/
- createRole(data = {}) {
- return this.client.rest.methods.createGuildRole(this, data);
+ createRole({ data = {}, reason } = {}) {
+ if (data.color) data.color = this.client.resolver.resolveColor(data.color);
+ if (data.permissions) data.permissions = Permissions.resolve(data.permissions);
+
+ return this.client.api.guilds(this.id).roles.post({ data, reason }).then(role =>
+ this.client.actions.GuildRoleCreate.handle({
+ guild_id: this.id,
+ role,
+ }).role
+ );
}
/**
@@ -7601,16 +6166,18 @@ class Guild {
* .catch(console.error);
*/
createEmoji(attachment, name, roles) {
- return new Promise(resolve => {
- if (typeof attachment === 'string' && attachment.startsWith('data:')) {
- resolve(this.client.rest.methods.createEmoji(this, attachment, name, roles));
- } else {
- this.client.resolver.resolveBuffer(attachment).then(data => {
- const dataURI = this.client.resolver.resolveBase64(data);
- resolve(this.client.rest.methods.createEmoji(this, dataURI, name, roles));
- });
- }
- });
+ if (typeof attahment === 'string' && attachment.startsWith('data:')) {
+ const data = { image: attachment, name };
+ if (roles) data.roles = roles.map(r => r.id ? r.id : r);
+ return this.client.api.guilds(this.id).emojis.post({ data })
+ .then(emoji => this.client.actions.GuildEmojiCreate.handle(this, emoji).emoji);
+ } else {
+ return this.client.resolver.resolveBuffer(attachment)
+ .then(data => {
+ const dataURI = this.client.resolver.resolveBase64(data);
+ return this.createEmoji(dataURI, name, roles);
+ });
+ }
}
/**
@@ -7620,7 +6187,8 @@ class Guild {
*/
deleteEmoji(emoji) {
if (!(emoji instanceof Emoji)) emoji = this.emojis.get(emoji);
- return this.client.rest.methods.deleteEmoji(emoji);
+ return this.client.api.guilds(this.id).emojis(this.id).delete()
+ .then(() => this.client.actions.GuildEmojiDelete.handle(emoji).data);
}
/**
@@ -7633,7 +6201,9 @@ class Guild {
* .catch(console.error);
*/
leave() {
- return this.client.rest.methods.leaveGuild(this);
+ if (this.ownerID === this.client.user.id) return Promise.reject(new Error('Guild is owned by the client.'));
+ return this.rest.api.users('@me').guilds(this.id).delete()
+ .then(() => this.client.actions.GuildDelete.handle({ id: this.id }).guild);
}
/**
@@ -7646,7 +6216,8 @@ class Guild {
* .catch(console.error);
*/
delete() {
- return this.client.rest.methods.deleteGuild(this);
+ return this.client.api.guilds(this.id).delete()
+ .then(() => this.client.actions.GuildDelete.handle({ id: this.id }).guild);
}
/**
@@ -7803,7 +6374,13 @@ class Guild {
Util.moveElementInArray(updatedRoles, role, position, relative);
updatedRoles = updatedRoles.map((r, i) => ({ id: r.id, position: i }));
- return this.client.rest.methods.setRolePositions(this.id, updatedRoles);
+ return this.client.api.guilds(this.id).roles.patch({ data: updatedRoles })
+ .then(() =>
+ this.client.actions.GuildRolesPositionUpdate.handle({
+ guild_id: this.id,
+ roles: updatedRoles,
+ }).guild
+ );
}
/**
@@ -7827,7 +6404,13 @@ class Guild {
Util.moveElementInArray(updatedChannels, channel, position, relative);
updatedChannels = updatedChannels.map((r, i) => ({ id: r.id, position: i }));
- return this.client.rest.methods.setChannelPositions(this.id, updatedChannels);
+ return this.client.api.guilds(this.id).channels.patch({ data: updatedChannels })
+ .then(() =>
+ this.client.actions.GuildChannelsPositionUpdate.handle({
+ guild_id: this.id,
+ roles: updatedChannels,
+ }).guild
+ );
}
/**
@@ -7864,13 +6447,1779 @@ module.exports = Guild;
/***/ }),
-/* 25 */
+/* 19 */
/***/ (function(module, exports, __webpack_require__) {
-const Channel = __webpack_require__(14);
-const Role = __webpack_require__(15);
+const TextBasedChannel = __webpack_require__(24);
+const Role = __webpack_require__(20);
+const Permissions = __webpack_require__(10);
+const Collection = __webpack_require__(3);
+const Presence = __webpack_require__(13).Presence;
+
+/**
+ * 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(Permissions.ALL);
+
+ let permissions = 0;
+ const roles = this.roles;
+ for (const role of roles.values()) permissions |= role.permissions;
+
+ return new Permissions(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, 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
+ * @param {string} [reason] Reason for editing this user
+ * @returns {Promise}
+ */
+ edit(data, reason) {
+ if (data.channel) {
+ data.channel_id = this.client.resolver.resolveChannel(data.channel).id;
+ data.channel = null;
+ }
+ if (data.roles) data.roles = data.roles.map(role => role instanceof Role ? role.id : role);
+ let endpoint = this.client.api.guilds(this.guild.id);
+ if (this.user.id === this.client.user.id) {
+ const keys = Object.keys(data);
+ if (keys.length === 1 && keys[0] === 'nick') endpoint = endpoint.members('@me').nick;
+ else endpoint = endpoint.members(this.id);
+ } else {
+ endpoint = endpoint.members(this.id);
+ }
+ return endpoint.patch({ data, reason }).then(newData => this.guild._updateMember(this, newData).mem);
+ }
+
+ /**
+ * 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.'));
+ if (this._roles.includes(role.id)) return Promise.resolve(this);
+ return this.client.api.guilds(this.guild.id).members(this.user.id).roles(role.id)
+ .put()
+ .then(() => this);
+ }
+
+ /**
+ * 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 ? role.id : role);
+ } else {
+ allRoles = this._roles.concat(roles.map(r => r.id ? r.id : r));
+ }
+ 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.api.guilds(this.guild.id).members(this.user.id).roles(role.id)
+ .delete()
+ .then(() => this);
+ }
+
+ /**
+ * 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.api.guilds(this.guild.id).members(this.user.id).delete({ reason })
+ .then(() =>
+ this.client.actions.GuildMemberRemove.handle({
+ guild_id: this.guild.id,
+ user: this.user,
+ }).member
+ );
+ }
+
+ /**
+ * 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() {}
+}
+
+TextBasedChannel.applyToClass(GuildMember);
+
+module.exports = GuildMember;
+
+
+/***/ }),
+/* 20 */
+/***/ (function(module, exports, __webpack_require__) {
+
+const Snowflake = __webpack_require__(6);
+const Permissions = __webpack_require__(10);
+
+/**
+ * Represents a role on Discord.
+ */
+class Role {
+ constructor(guild, data) {
+ /**
+ * The client that instantiated the role
+ * @name Role#client
+ * @type {Client}
+ * @readonly
+ */
+ Object.defineProperty(this, 'client', { value: guild.client });
+
+ /**
+ * The guild that the role belongs to
+ * @type {Guild}
+ */
+ this.guild = guild;
+
+ if (data) this.setup(data);
+ }
+
+ setup(data) {
+ /**
+ * The ID of the role (unique to the guild it is part of)
+ * @type {Snowflake}
+ */
+ this.id = data.id;
+
+ /**
+ * The name of the role
+ * @type {string}
+ */
+ this.name = data.name;
+
+ /**
+ * The base 10 color of the role
+ * @type {number}
+ */
+ this.color = data.color;
+
+ /**
+ * If true, users that are part of this role will appear in a separate category in the users list
+ * @type {boolean}
+ */
+ this.hoist = data.hoist;
+
+ /**
+ * The position of the role from the API
+ * @type {number}
+ */
+ this.position = data.position;
+
+ /**
+ * The permissions bitfield of the role
+ * @type {number}
+ */
+ this.permissions = data.permissions;
+
+ /**
+ * Whether or not the role is managed by an external service
+ * @type {boolean}
+ */
+ this.managed = data.managed;
+
+ /**
+ * Whether or not the role can be mentioned by anyone
+ * @type {boolean}
+ */
+ this.mentionable = data.mentionable;
+ }
+
+ /**
+ * The timestamp the role was created at
+ * @type {number}
+ * @readonly
+ */
+ get createdTimestamp() {
+ return Snowflake.deconstruct(this.id).timestamp;
+ }
+
+ /**
+ * The time the role was created
+ * @type {Date}
+ * @readonly
+ */
+ get createdAt() {
+ return new Date(this.createdTimestamp);
+ }
+
+ /**
+ * The hexadecimal version of the role color, with a leading hashtag
+ * @type {string}
+ * @readonly
+ */
+ get hexColor() {
+ let col = this.color.toString(16);
+ while (col.length < 6) col = `0${col}`;
+ return `#${col}`;
+ }
+
+ /**
+ * The cached guild members that have this role
+ * @type {Collection}
+ * @readonly
+ */
+ get members() {
+ return this.guild.members.filter(m => m.roles.has(this.id));
+ }
+
+ /**
+ * Whether the role is editable by the client user
+ * @type {boolean}
+ * @readonly
+ */
+ get editable() {
+ if (this.managed) return false;
+ const clientMember = this.guild.member(this.client.user);
+ if (!clientMember.permissions.has(Permissions.FLAGS.MANAGE_ROLES_OR_PERMISSIONS)) return false;
+ return clientMember.highestRole.comparePositionTo(this) > 0;
+ }
+
+ /**
+ * The position of the role in the role manager
+ * @type {number}
+ * @readonly
+ */
+ get calculatedPosition() {
+ const sorted = this.guild._sortedRoles;
+ return sorted.array().indexOf(sorted.get(this.id));
+ }
+
+ /**
+ * Get an object mapping permission names to whether or not the role enables that permission
+ * @returns {Object}
+ * @example
+ * // Print the serialized role permissions
+ * console.log(role.serialize());
+ */
+ serialize() {
+ return new Permissions(this.permissions).serialize();
+ }
+
+ /**
+ * Checks if the role has 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`)
+ * @returns {boolean}
+ * @example
+ * // See if a role can ban a member
+ * if (role.hasPermission('BAN_MEMBERS')) {
+ * console.log('This role can ban members');
+ * } else {
+ * console.log('This role can\'t ban members');
+ * }
+ */
+ hasPermission(permission, explicit = false, checkAdmin) {
+ return new Permissions(this.permissions).has(
+ permission, typeof checkAdmin !== 'undefined' ? checkAdmin : !explicit
+ );
+ }
+
+ /**
+ * Compares this role's position to another role's.
+ * @param {Role} role Role to compare to this one
+ * @returns {number} Negative number if the this role's position is lower (other role's is higher),
+ * positive number if the this one is higher (other's is lower), 0 if equal
+ */
+ comparePositionTo(role) {
+ return this.constructor.comparePositions(this, role);
+ }
+
+ /**
+ * The data for a role.
+ * @typedef {Object} RoleData
+ * @property {string} [name] The name of the role
+ * @property {ColorResolvable} [color] The color of the role, either a hex string or a base 10 number
+ * @property {boolean} [hoist] Whether or not the role should be hoisted
+ * @property {number} [position] The position of the role
+ * @property {string[]} [permissions] The permissions of the role
+ * @property {boolean} [mentionable] Whether or not the role should be mentionable
+ */
+
+ /**
+ * Edits the role.
+ * @param {RoleData} data The new data for the role
+ * @param {string} [reason] Reason for editing this role
+ * @returns {Promise}
+ * @example
+ * // Edit a role
+ * role.edit({name: 'new role'})
+ * .then(r => console.log(`Edited role ${r}`))
+ * .catch(console.error);
+ */
+ edit(data, reason) {
+ if (data.permissions) data.permissions = Permissions.resolve(data.permissions);
+ else data.permissions = this.permissions;
+ return this.client.api.guilds(this.guild.id).roles(this.id).patch({
+ data: {
+ name: data.name || this.name,
+ position: typeof data.position !== 'undefined' ? data.position : this.position,
+ color: this.client.resolver.resolveColor(data.color || this.color),
+ hoist: typeof data.hoist !== 'undefined' ? data.hoist : this.hoist,
+ mentionable: typeof data.mentionable !== 'undefined' ? data.mentionable : this.mentionable,
+ },
+ reason,
+ })
+ .then(role => this.client.actions.GuildRoleUpdate.handle({ role, guild_id: this.guild.id }).updated);
+ }
+
+ /**
+ * Set a new name for the role.
+ * @param {string} name The new name of the role
+ * @returns {Promise}
+ * @example
+ * // Set the name of the role
+ * role.setName('new role')
+ * .then(r => console.log(`Edited name of role ${r}`))
+ * .catch(console.error);
+ */
+ setName(name) {
+ return this.edit({ name });
+ }
+
+ /**
+ * Set a new color for the role.
+ * @param {ColorResolvable} color The color of the role
+ * @returns {Promise}
+ * @example
+ * // Set the color of a role
+ * role.setColor('#FF0000')
+ * .then(r => console.log(`Set color of role ${r}`))
+ * .catch(console.error);
+ */
+ setColor(color) {
+ return this.edit({ color });
+ }
+
+ /**
+ * Set whether or not the role should be hoisted.
+ * @param {boolean} hoist Whether or not to hoist the role
+ * @returns {Promise}
+ * @example
+ * // Set the hoist of the role
+ * role.setHoist(true)
+ * .then(r => console.log(`Role hoisted: ${r.hoist}`))
+ * .catch(console.error);
+ */
+ setHoist(hoist) {
+ return this.edit({ hoist });
+ }
+
+ /**
+ * Set the position of the role.
+ * @param {number} position The position of the role
+ * @param {boolean} [relative=false] Move the position relative to its current value
+ * @returns {Promise}
+ * @example
+ * // Set the position of the role
+ * role.setPosition(1)
+ * .then(r => console.log(`Role position: ${r.position}`))
+ * .catch(console.error);
+ */
+ setPosition(position, relative) {
+ return this.guild.setRolePosition(this, position, relative).then(() => this);
+ }
+
+ /**
+ * Set the permissions of the role.
+ * @param {string[]} permissions The permissions of the role
+ * @returns {Promise}
+ * @example
+ * // Set the permissions of the role
+ * role.setPermissions(['KICK_MEMBERS', 'BAN_MEMBERS'])
+ * .then(r => console.log(`Role updated ${r}`))
+ * .catch(console.error);
+ */
+ setPermissions(permissions) {
+ return this.edit({ permissions });
+ }
+
+ /**
+ * Set whether this role is mentionable.
+ * @param {boolean} mentionable Whether this role should be mentionable
+ * @returns {Promise}
+ * @example
+ * // Make the role mentionable
+ * role.setMentionable(true)
+ * .then(r => console.log(`Role updated ${r}`))
+ * .catch(console.error);
+ */
+ setMentionable(mentionable) {
+ return this.edit({ mentionable });
+ }
+
+ /**
+ * Deletes the role.
+ * @param {string} [reason] Reason for deleting this role
+ * @returns {Promise}
+ * @example
+ * // Delete a role
+ * role.delete()
+ * .then(r => console.log(`Deleted role ${r}`))
+ * .catch(console.error);
+ */
+ delete(reason) {
+ return this.client.api.guilds(this.guild.id).roles(this.id).delete({ reason })
+ .then(() =>
+ this.client.actions.GuildRoleDelete.handle({ guild_id: this.guild.id, role_id: this.id }).role
+ );
+ }
+
+ /**
+ * Whether this role equals another role. It compares all properties, so for most operations
+ * it is advisable to just compare `role.id === role2.id` as it is much faster and is often
+ * what most users need.
+ * @param {Role} role Role to compare with
+ * @returns {boolean}
+ */
+ equals(role) {
+ return role &&
+ this.id === role.id &&
+ this.name === role.name &&
+ this.color === role.color &&
+ this.hoist === role.hoist &&
+ this.position === role.position &&
+ this.permissions === role.permissions &&
+ this.managed === role.managed;
+ }
+
+ /**
+ * When concatenated with a string, this automatically concatenates the role mention rather than the Role object.
+ * @returns {string}
+ */
+ toString() {
+ if (this.id === this.guild.id) return '@everyone';
+ return `<@&${this.id}>`;
+ }
+
+ /**
+ * Compares the positions of two roles.
+ * @param {Role} role1 First role to compare
+ * @param {Role} role2 Second role to compare
+ * @returns {number} Negative number if the first role's position is lower (second role's is higher),
+ * positive number if the first's is higher (second's is lower), 0 if equal
+ */
+ static comparePositions(role1, role2) {
+ if (role1.position === role2.position) return role2.id - role1.id;
+ return role1.position - role2.position;
+ }
+}
+
+module.exports = Role;
+
+
+/***/ }),
+/* 21 */
+/***/ (function(module, exports, __webpack_require__) {
+
+const path = __webpack_require__(29);
+
+/**
+ * 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 });
+ }
+ }
+
+ 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.
+ * @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 {FileOptions[]|string[]} [files] Files 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.username) options.username = this.name;
+
+ if (options.avatarURL) {
+ options.avatar_url = options.avatarURL;
+ options.avatarURL = null;
+ }
+
+ if (typeof content !== 'undefined') content = this.client.resolver.resolveString(content);
+ if (content) {
+ if (options.disableEveryone ||
+ (typeof options.disableEveryone === 'undefined' && this.client.options.disableEveryone)
+ ) {
+ content = content.replace(/@(everyone|here)/g, '@\u200b$1');
+ }
+ }
+ options.content = content;
+
+ 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';
+ }
+ }
+ options.files[i] = file;
+ }
+
+ return Promise.all(options.files.map(file =>
+ this.client.resolver.resolveBuffer(file.attachment).then(buffer => {
+ file.file = buffer;
+ return file;
+ })
+ )).then(files => this.client.api.webhooks(this.id, this.token).post({
+ data: options,
+ query: { wait: true },
+ files,
+ auth: false,
+ }));
+ }
+
+ return this.client.api.webhooks(this.id, this.token).post({
+ data: options,
+ query: { wait: true },
+ auth: false,
+ }).then(data => {
+ if (!this.client.channels) return data;
+ const Message = __webpack_require__(8);
+ return new Message(this.client.channels.get(data.channel_id, data, this.client));
+ });
+ }
+
+ /**
+ * 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.api.webhooks(this.id, this.token).slack.post({
+ query: { wait: true },
+ auth: false,
+ data: body,
+ }).then(data => {
+ if (!this.client.channels) return data;
+ const Message = __webpack_require__(8);
+ return new Message(this.client.channels.get(data.channel_id, data, this.client));
+ });
+ }
+
+ /**
+ * Edit the webhook.
+ * @param {Object} options Options
+ * @param {string} [options.name] New name for this webhook
+ * @param {BufferResolvable} [options.avatar] New avatar for this webhook
+ * @param {string} [reason] Reason for editing this webhook
+ * @returns {Promise}
+ */
+ edit({ name = this.name, avatar }, reason) {
+ if (avatar && (typeof avatar === 'string' && !avatar.startsWith('data:'))) {
+ return this.client.resolver.resolveBuffer(avatar).then(file => {
+ const dataURI = this.client.resolver.resolveBase64(file);
+ return this.edit({ name, avatar: dataURI }, reason);
+ });
+ }
+ return this.client.api.webhooks(this.id, this.token).patch({
+ data: { name, avatar },
+ reason,
+ }).then(data => {
+ this.name = data.name;
+ this.avatar = data.avatar;
+ return this;
+ });
+ }
+
+ /**
+ * Delete the webhook.
+ * @param {string} [reason] Reason for deleting this webhook
+ * @returns {Promise}
+ */
+ delete(reason) {
+ return this.client.api.webhooks(this.id, this.token).delete({ reason });
+ }
+}
+
+module.exports = Webhook;
+
+
+/***/ }),
+/* 22 */
+/***/ (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
+// 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.
+
+// NOTE: These type checking functions intentionally don't use `instanceof`
+// because it is fragile and can be easily faked with `Object.create()`.
+
+function isArray(arg) {
+ if (Array.isArray) {
+ return Array.isArray(arg);
+ }
+ return objectToString(arg) === '[object Array]';
+}
+exports.isArray = isArray;
+
+function isBoolean(arg) {
+ return typeof arg === 'boolean';
+}
+exports.isBoolean = isBoolean;
+
+function isNull(arg) {
+ return arg === null;
+}
+exports.isNull = isNull;
+
+function isNullOrUndefined(arg) {
+ return arg == null;
+}
+exports.isNullOrUndefined = isNullOrUndefined;
+
+function isNumber(arg) {
+ return typeof arg === 'number';
+}
+exports.isNumber = isNumber;
+
+function isString(arg) {
+ return typeof arg === 'string';
+}
+exports.isString = isString;
+
+function isSymbol(arg) {
+ return typeof arg === 'symbol';
+}
+exports.isSymbol = isSymbol;
+
+function isUndefined(arg) {
+ return arg === void 0;
+}
+exports.isUndefined = isUndefined;
+
+function isRegExp(re) {
+ return objectToString(re) === '[object RegExp]';
+}
+exports.isRegExp = isRegExp;
+
+function isObject(arg) {
+ return typeof arg === 'object' && arg !== null;
+}
+exports.isObject = isObject;
+
+function isDate(d) {
+ return objectToString(d) === '[object Date]';
+}
+exports.isDate = isDate;
+
+function isError(e) {
+ return (objectToString(e) === '[object Error]' || e instanceof Error);
+}
+exports.isError = isError;
+
+function isFunction(arg) {
+ return typeof arg === 'function';
+}
+exports.isFunction = isFunction;
+
+function isPrimitive(arg) {
+ return arg === null ||
+ typeof arg === 'boolean' ||
+ typeof arg === 'number' ||
+ typeof arg === 'string' ||
+ typeof arg === 'symbol' || // ES6 symbol
+ typeof arg === 'undefined';
+}
+exports.isPrimitive = isPrimitive;
+
+exports.isBuffer = Buffer.isBuffer;
+
+function objectToString(o) {
+ return Object.prototype.toString.call(o);
+}
+
+/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(5).Buffer))
+
+/***/ }),
+/* 23 */
+/***/ (function(module, exports, __webpack_require__) {
+
+exports = module.exports = __webpack_require__(58);
+exports.Stream = exports;
+exports.Readable = exports;
+exports.Writable = __webpack_require__(37);
+exports.Duplex = __webpack_require__(15);
+exports.Transform = __webpack_require__(59);
+exports.PassThrough = __webpack_require__(86);
+
+
+/***/ }),
+/* 24 */
+/***/ (function(module, exports, __webpack_require__) {
+
+const path = __webpack_require__(29);
+const MessageCollector = __webpack_require__(47);
+const Shared = __webpack_require__(71);
+const Collection = __webpack_require__(3);
+const Snowflake = __webpack_require__(6);
+
+/**
+ * Interface for classes that have text-channel-like features.
+ * @interface
+ */
+class TextBasedChannel {
+ constructor() {
+ /**
+ * A collection containing the messages sent to this channel
+ * @type {Collection}
+ */
+ this.messages = new Collection();
+
+ /**
+ * The ID of the last message in the channel, if one was sent
+ * @type {?Snowflake}
+ */
+ this.lastMessageID = null;
+
+ /**
+ * The Message object of the last message in the channel, if one was sent
+ * @type {?Message}
+ */
+ this.lastMessage = null;
+ }
+
+ /**
+ * Options provided when sending or editing a message.
+ * @typedef {Object} MessageOptions
+ * @property {boolean} [tts=false] Whether or not the message should be spoken aloud
+ * @property {string} [nonce=''] The nonce for the message
+ * @property {RichEmbed|Object} [embed] An embed 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[]} [files] Files 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
+ * @property {UserResolvable} [reply] User to reply to (prefixes the message with a mention, except in DMs)
+ */
+
+ /**
+ * @typedef {Object} FileOptions
+ * @property {BufferResolvable} attachment File to attach
+ * @property {string} [name='file.jpg'] Filename of the attachment
+ */
+
+ /**
+ * Options for splitting a message.
+ * @typedef {Object} SplitOptions
+ * @property {number} [maxLength=1950] Maximum character length per message piece
+ * @property {string} [char='\n'] Character to split the message with
+ * @property {string} [prepend=''] Text to prepend to every piece except the first
+ * @property {string} [append=''] Text to append to every piece except the last
+ */
+
+ /**
+ * Send a message to this channel.
+ * @param {StringResolvable} [content] Text for the message
+ * @param {MessageOptions} [options={}] Options for the message
+ * @returns {Promise}
+ * @example
+ * // Send a message
+ * channel.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.content) options.content = content;
+
+ if (options.embed && options.embed.file) options.file = options.embed.file;
+
+ 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';
+ }
+ }
+ options.files[i] = file;
+ }
+
+ return Promise.all(options.files.map(file =>
+ this.client.resolver.resolveBuffer(file.attachment).then(buffer => {
+ file.file = buffer;
+ return file;
+ })
+ )).then(files => {
+ options.files = files;
+ return Shared.sendMessage(this, options);
+ });
+ }
+
+ return Shared.sendMessage(this, options);
+ }
+
+ /**
+ * Gets a single message from this channel, regardless of it being cached or not. Since the single message fetching
+ * endpoint is reserved for bot accounts, this abstracts the `fetchMessages` method to obtain the single message when
+ * using a user account.
+ * @param {Snowflake} messageID ID of the message to get
+ * @returns {Promise}
+ * @example
+ * // Get message
+ * channel.fetchMessage('99539446449315840')
+ * .then(message => console.log(message.content))
+ * .catch(console.error);
+ */
+ fetchMessage(messageID) {
+ const Message = __webpack_require__(8);
+ if (!this.client.user.bot) {
+ return this.fetchMessages({ limit: 1, around: messageID })
+ .then(messages => {
+ const msg = messages.get(messageID);
+ if (!msg) throw new Error('Message not found.');
+ return msg;
+ });
+ }
+ return this.client.api.channels(this.id).messages(messageID).get()
+ .then(data => {
+ const msg = data instanceof Message ? data : new Message(this, data, this.client);
+ this._cacheMessage(msg);
+ return msg;
+ });
+ }
+
+ /**
+ * The parameters to pass in when requesting previous messages from a channel. `around`, `before` and
+ * `after` are mutually exclusive. All the parameters are optional.
+ * @typedef {Object} ChannelLogsQueryOptions
+ * @property {number} [limit=50] Number of messages to acquire
+ * @property {Snowflake} [before] ID of a message to get the messages that were posted before it
+ * @property {Snowflake} [after] ID of a message to get the messages that were posted after it
+ * @property {Snowflake} [around] ID of a message to get the messages that were posted around it
+ */
+
+ /**
+ * Gets the past messages sent in this channel. Resolves with a collection mapping message ID's to Message objects.
+ * @param {ChannelLogsQueryOptions} [options={}] Query parameters to pass in
+ * @returns {Promise>}
+ * @example
+ * // Get messages
+ * channel.fetchMessages({limit: 10})
+ * .then(messages => console.log(`Received ${messages.size} messages`))
+ * .catch(console.error);
+ */
+ fetchMessages(options = {}) {
+ const Message = __webpack_require__(8);
+ return this.client.api.channels(this.id).messages.get({ query: options })
+ .then(data => {
+ const messages = new Collection();
+ for (const message of data) {
+ const msg = new Message(this, message, this.client);
+ messages.set(message.id, msg);
+ this._cacheMessage(msg);
+ }
+ return messages;
+ });
+ }
+
+ /**
+ * Fetches the pinned messages of this channel and returns a collection of them.
+ * @returns {Promise>}
+ */
+ fetchPinnedMessages() {
+ const Message = __webpack_require__(8);
+ return this.client.api.channels(this.id).pins.get().then(data => {
+ const messages = new Collection();
+ for (const message of data) {
+ const msg = new Message(this, message, this.client);
+ messages.set(message.id, msg);
+ this._cacheMessage(msg);
+ }
+ return messages;
+ });
+ }
+
+ /**
+ * @typedef {Object} MessageSearchOptions
+ * @property {string} [content] Message content
+ * @property {Snowflake} [maxID] Maximum ID for the filter
+ * @property {Snowflake} [minID] Minimum ID for the filter
+ * @property {string} [has] One of `link`, `embed`, `file`, `video`, `image`, or `sound`,
+ * or add `-` to negate (e.g. `-file`)
+ * @property {ChannelResolvable} [channel] Channel to limit search to (only for guild search endpoint)
+ * @property {UserResolvable} [author] Author to limit search
+ * @property {string} [authorType] One of `user`, `bot`, `webhook`, or add `-` to negate (e.g. `-webhook`)
+ * @property {string} [sortBy='recent'] `recent` or `relevant`
+ * @property {string} [sortOrder='desc'] `asc` or `desc`
+ * @property {number} [contextSize=2] How many messages to get around the matched message (0 to 2)
+ * @property {number} [limit=25] Maximum number of results to get (1 to 25)
+ * @property {number} [offset=0] Offset the "pages" of results (since you can only see 25 at a time)
+ * @property {UserResolvable} [mentions] Mentioned user filter
+ * @property {boolean} [mentionsEveryone] If everyone is mentioned
+ * @property {string} [linkHostname] Filter links by hostname
+ * @property {string} [embedProvider] The name of an embed provider
+ * @property {string} [embedType] one of `image`, `video`, `url`, `rich`
+ * @property {string} [attachmentFilename] The name of an attachment
+ * @property {string} [attachmentExtension] The extension of an attachment
+ * @property {Date} [before] Date to find messages before
+ * @property {Date} [after] Date to find messages before
+ * @property {Date} [during] Date to find messages during (range of date to date + 24 hours)
+ */
+
+ /**
+ * Performs a search within the channel.
+ * This is only available when using a user account.
+ * @param {MessageSearchOptions} [options={}] Options to pass to the search
+ * @returns {Promise>}
+ * An array containing arrays of messages. Each inner array is a search context cluster
+ * The message which has triggered the result will have the `hit` property set to `true`
+ * @example
+ * channel.search({
+ * content: 'discord.js',
+ * before: '2016-11-17'
+ * }).then(res => {
+ * const hit = res.messages[0].find(m => m.hit).content;
+ * console.log(`I found: **${hit}**, total results: ${res.totalResults}`);
+ * }).catch(console.error);
+ */
+ search(options = {}) {
+ return Shared.search(this, options);
+ }
+
+ /**
+ * Starts a typing indicator in the channel.
+ * @param {number} [count] The number of times startTyping should be considered to have been called
+ * @example
+ * // Start typing in a channel
+ * channel.startTyping();
+ */
+ startTyping(count) {
+ if (typeof count !== 'undefined' && count < 1) throw new RangeError('Count must be at least 1.');
+ if (!this.client.user._typing.has(this.id)) {
+ const endpoint = this.client.api.channels(this.id).typing;
+ this.client.user._typing.set(this.id, {
+ count: count || 1,
+ interval: this.client.setInterval(() => {
+ endpoint.post();
+ }, 9000),
+ });
+ endpoint.post();
+ } else {
+ const entry = this.client.user._typing.get(this.id);
+ entry.count = count || entry.count + 1;
+ }
+ }
+
+ /**
+ * Stops the typing indicator in the channel.
+ * The indicator will only stop if this is called as many times as startTyping().
+ * It can take a few seconds for the client user to stop typing.
+ * @param {boolean} [force=false] Whether or not to reset the call count and force the indicator to stop
+ * @example
+ * // Stop typing in a channel
+ * channel.stopTyping();
+ * @example
+ * // Force typing to fully stop in a channel
+ * channel.stopTyping(true);
+ */
+ stopTyping(force = false) {
+ if (this.client.user._typing.has(this.id)) {
+ const entry = this.client.user._typing.get(this.id);
+ entry.count--;
+ if (entry.count <= 0 || force) {
+ this.client.clearInterval(entry.interval);
+ this.client.user._typing.delete(this.id);
+ }
+ }
+ }
+
+ /**
+ * Whether or not the typing indicator is being shown in the channel
+ * @type {boolean}
+ * @readonly
+ */
+ get typing() {
+ return this.client.user._typing.has(this.id);
+ }
+
+ /**
+ * Number of times `startTyping` has been called
+ * @type {number}
+ * @readonly
+ */
+ get typingCount() {
+ if (this.client.user._typing.has(this.id)) return this.client.user._typing.get(this.id).count;
+ return 0;
+ }
+
+ /**
+ * Creates a Message Collector.
+ * @param {CollectorFilter} filter The filter to create the collector with
+ * @param {MessageCollectorOptions} [options={}] The options to pass to the collector
+ * @returns {MessageCollector}
+ * @example
+ * // Create a message collector
+ * const collector = channel.createCollector(
+ * m => m.content.includes('discord'),
+ * { time: 15000 }
+ * );
+ * collector.on('message', m => console.log(`Collected ${m.content}`));
+ * collector.on('end', collected => console.log(`Collected ${collected.size} items`));
+ */
+ createMessageCollector(filter, options = {}) {
+ return new MessageCollector(this, filter, options);
+ }
+
+ /**
+ * An object containing the same properties as CollectorOptions, but a few more:
+ * @typedef {MessageCollectorOptions} AwaitMessagesOptions
+ * @property {string[]} [errors] Stop/end reasons that cause the promise to reject
+ */
+
+ /**
+ * Similar to createCollector but in promise form. Resolves with a collection of messages that pass the specified
+ * filter.
+ * @param {CollectorFilter} filter The filter function to use
+ * @param {AwaitMessagesOptions} [options={}] Optional options to pass to the internal collector
+ * @returns {Promise>}
+ * @example
+ * // Await !vote messages
+ * const filter = m => m.content.startsWith('!vote');
+ * // Errors: ['time'] treats ending because of the time limit as an error
+ * channel.awaitMessages(filter, { max: 4, time: 60000, errors: ['time'] })
+ * .then(collected => console.log(collected.size))
+ * .catch(collected => console.log(`After a minute, only ${collected.size} out of 4 voted.`));
+ */
+ awaitMessages(filter, options = {}) {
+ return new Promise((resolve, reject) => {
+ const collector = this.createMessageCollector(filter, options);
+ collector.once('end', (collection, reason) => {
+ if (options.errors && options.errors.includes(reason)) {
+ reject(collection);
+ } else {
+ resolve(collection);
+ }
+ });
+ });
+ }
+
+ /**
+ * Bulk delete given messages that are newer than two weeks.
+ * This is only available when using a bot account.
+ * @param {Collection|Message[]|number} messages Messages or number of messages to delete
+ * @param {boolean} [filterOld=false] Filter messages to remove those which are older than two weeks automatically
+ * @returns {Promise>} Deleted messages
+ */
+ bulkDelete(messages, filterOld = false) {
+ if (!isNaN(messages)) return this.fetchMessages({ limit: messages }).then(msgs => this.bulkDelete(msgs, filterOld));
+ if (messages instanceof Array || messages instanceof Collection) {
+ let messageIDs = messages instanceof Collection ? messages.keyArray() : messages.map(m => m.id);
+ if (filterOld) {
+ messageIDs = messageIDs.filter(id =>
+ Date.now() - Snowflake.deconstruct(id).date.getTime() < 1209600000
+ );
+ }
+ return this.rest.api.channels(this.id).messages['bulk-delete']
+ .post({ data: { messages: messageIDs } })
+ .then(() =>
+ this.client.actions.MessageDeleteBulk.handle({
+ channel_id: this.id,
+ ids: messageIDs,
+ }).messages
+ );
+ }
+ throw new TypeError('The messages must be an Array, Collection, or number.');
+ }
+
+ /**
+ * Marks all messages in this channel as read.
+ * This is only available when using a user account.
+ * @returns {Promise}
+ */
+ acknowledge() {
+ if (!this.lastMessageID) return Promise.resolve(this);
+ return this.client.api.channels(this.id).messages(this.lastMessageID)
+ .post({ data: { token: this.client.rest._ackToken } })
+ .then(res => {
+ if (res.token) this.client.rest._ackToken = res.token;
+ return this;
+ });
+ }
+
+ _cacheMessage(message) {
+ const maxSize = this.client.options.messageCacheMaxSize;
+ if (maxSize === 0) return null;
+ if (this.messages.size >= maxSize && maxSize > 0) this.messages.delete(this.messages.firstKey());
+ this.messages.set(message.id, message);
+ return message;
+ }
+}
+
+exports.applyToClass = (structure, full = false, ignore = []) => {
+ const props = ['send'];
+ if (full) {
+ props.push(
+ '_cacheMessage',
+ 'acknowledge',
+ 'fetchMessages',
+ 'fetchMessage',
+ 'search',
+ 'bulkDelete',
+ 'startTyping',
+ 'stopTyping',
+ 'typing',
+ 'typingCount',
+ 'fetchPinnedMessages',
+ 'createMessageCollector',
+ 'awaitMessages'
+ );
+ }
+ for (const prop of props) {
+ if (ignore.includes(prop)) continue;
+ Object.defineProperty(structure.prototype, prop, Object.getOwnPropertyDescriptor(TextBasedChannel.prototype, prop));
+ }
+};
+
+
+/***/ }),
+/* 25 */
+/***/ (function(module, exports) {
+
+exports.endianness = function () { return 'LE' };
+
+exports.hostname = function () {
+ if (typeof location !== 'undefined') {
+ return location.hostname
+ }
+ else return '';
+};
+
+exports.loadavg = function () { return [] };
+
+exports.uptime = function () { return 0 };
+
+exports.freemem = function () {
+ return Number.MAX_VALUE;
+};
+
+exports.totalmem = function () {
+ return Number.MAX_VALUE;
+};
+
+exports.cpus = function () { return [] };
+
+exports.type = function () { return 'Browser' };
+
+exports.release = function () {
+ if (typeof navigator !== 'undefined') {
+ return navigator.appVersion;
+ }
+ return '';
+};
+
+exports.networkInterfaces
+= exports.getNetworkInterfaces
+= function () { return {} };
+
+exports.arch = function () { return 'javascript' };
+
+exports.platform = function () { return 'browser' };
+
+exports.tmpdir = exports.tmpDir = function () {
+ return '/tmp';
+};
+
+exports.EOL = '\n';
+
+
+/***/ }),
+/* 26 */
+/***/ (function(module, exports, __webpack_require__) {
+
+const Channel = __webpack_require__(16);
+const Role = __webpack_require__(20);
+const Invite = __webpack_require__(27);
const PermissionOverwrites = __webpack_require__(53);
-const Permissions = __webpack_require__(8);
+const Permissions = __webpack_require__(10);
const Collection = __webpack_require__(3);
/**
@@ -8007,7 +8356,8 @@ class GuildChannel extends Channel {
* Overwrites the permissions for a user or role in this channel.
* @param {RoleResolvable|UserResolvable} userOrRole The user or role to update
* @param {PermissionOverwriteOptions} options The configuration for the update
- * @returns {Promise}
+ * @param {string} [reason] Reason for creating/editing this overwrite
+ * @returns {Promise}
* @example
* // Overwrite permissions for a message author
* message.channel.overwritePermissions(message.author, {
@@ -8016,7 +8366,7 @@ class GuildChannel extends Channel {
* .then(() => console.log('Done!'))
* .catch(console.error);
*/
- overwritePermissions(userOrRole, options) {
+ overwritePermissions(userOrRole, options, reason) {
const payload = {
allow: 0,
deny: 0,
@@ -8055,7 +8405,9 @@ class GuildChannel extends Channel {
}
}
- return this.client.rest.methods.setChannelOverwrite(this, payload);
+ return this.client.api.channels(this.id).permissions(payload.id)
+ .put({ data: payload, reason })
+ .then(() => this);
}
/**
@@ -8071,6 +8423,7 @@ class GuildChannel extends Channel {
/**
* Edits the channel.
* @param {ChannelData} data The new data for the channel
+ * @param {string} [reason] Reason for editing this channel
* @returns {Promise}
* @example
* // Edit a channel
@@ -8078,8 +8431,17 @@ class GuildChannel extends Channel {
* .then(c => console.log(`Edited channel ${c}`))
* .catch(console.error);
*/
- edit(data) {
- return this.client.rest.methods.updateChannel(this, data);
+ edit(data, reason) {
+ return this.client.api.channels(this.id).patch({
+ data: {
+ name: (data.name || this.name).trim(),
+ topic: data.topic || this.topic,
+ position: data.position || this.position,
+ bitrate: data.bitrate || this.bitrate,
+ user_limit: data.userLimit || this.userLimit,
+ },
+ reason,
+ }).then(newData => this.client.actions.ChannelUpdate.handle(newData).updated);
}
/**
@@ -8122,7 +8484,7 @@ class GuildChannel extends Channel {
* .catch(console.error);
*/
setTopic(topic) {
- return this.client.rest.methods.updateChannel(this, { topic });
+ return this.edit({ topic });
}
/**
@@ -8138,10 +8500,14 @@ class GuildChannel extends Channel {
* kicked after 24 hours if they have not yet received a role
* @param {number} [options.maxAge=86400] How long the invite should last (in seconds, 0 for forever)
* @param {number} [options.maxUses=0] Maximum number of uses
+ * @param {string} [reason] Reason for creating this
* @returns {Promise}
*/
- createInvite(options = {}) {
- return this.client.rest.methods.createChannelInvite(this, options);
+ createInvite({ temporary = false, maxAge = 86400, maxUses = 0 }, reason) {
+ return this.client.api.channels(this.id).invites.post({ data: {
+ temporary, max_age: maxAge, max_uses: maxUses,
+ }, reason })
+ .then(invite => new Invite(this.client, invite));
}
/**
@@ -8191,6 +8557,20 @@ class GuildChannel extends Channel {
this.permissionsFor(this.client.user).has(Permissions.FLAGS.MANAGE_CHANNELS);
}
+ /**
+ * Deletes this channel.
+ * @param {string} [reason] Reason for deleting this channel
+ * @returns {Promise}
+ * @example
+ * // Delete the channel
+ * channel.delete('making room for new channels')
+ * .then() // Success
+ * .catch(console.error); // Log error
+ */
+ delete(reason) {
+ return this.client.api.channels(this.id).delete({ reason }).then(() => this);
+ }
+
/**
* When concatenated with a string, this automatically returns the channel's mention instead of the Channel object.
* @returns {string}
@@ -8210,7 +8590,176 @@ module.exports = GuildChannel;
/***/ }),
-/* 26 */
+/* 27 */
+/***/ (function(module, exports, __webpack_require__) {
+
+const PartialGuild = __webpack_require__(51);
+const PartialGuildChannel = __webpack_require__(52);
+const Constants = __webpack_require__(0);
+
+/**
+ * Represents an invitation to a guild channel.
+ * The only guaranteed properties are `code`, `guild` and `channel`. Other properties can be missing.
+ */
+class Invite {
+ constructor(client, data) {
+ /**
+ * The client that instantiated the invite
+ * @name Invite#client
+ * @type {Client}
+ * @readonly
+ */
+ Object.defineProperty(this, 'client', { value: client });
+
+ this.setup(data);
+ }
+
+ setup(data) {
+ /**
+ * The guild the invite is for. If this guild is already known, this will be a guild object. If the guild is
+ * unknown, this will be a PartialGuild object
+ * @type {Guild|PartialGuild}
+ */
+ this.guild = this.client.guilds.get(data.guild.id) || new PartialGuild(this.client, data.guild);
+
+ /**
+ * The code for this invite
+ * @type {string}
+ */
+ this.code = data.code;
+
+ /**
+ * The approximate number of online members of the guild this invite is for
+ * @type {number}
+ */
+ this.presenceCount = data.approximate_presence_count;
+
+ /**
+ * The approximate total number of members of the guild this invite is for
+ * @type {number}
+ */
+ this.memberCount = data.approximate_member_count;
+
+ /**
+ * The number of text channels the guild this invite goes to has
+ * @type {number}
+ */
+ this.textChannelCount = data.guild.text_channel_count;
+
+ /**
+ * The number of voice channels the guild this invite goes to has
+ * @type {number}
+ */
+ this.voiceChannelCount = data.guild.voice_channel_count;
+
+ /**
+ * Whether or not this invite is temporary
+ * @type {boolean}
+ */
+ this.temporary = data.temporary;
+
+ /**
+ * The maximum age of the invite, in seconds
+ * @type {?number}
+ */
+ this.maxAge = data.max_age;
+
+ /**
+ * How many times this invite has been used
+ * @type {number}
+ */
+ this.uses = data.uses;
+
+ /**
+ * The maximum uses of this invite
+ * @type {number}
+ */
+ this.maxUses = data.max_uses;
+
+ if (data.inviter) {
+ /**
+ * The user who created this invite
+ * @type {User}
+ */
+ this.inviter = this.client.dataManager.newUser(data.inviter);
+ }
+
+ /**
+ * The channel the invite is for. If this channel is already known, this will be a GuildChannel object.
+ * If the channel is unknown, this will be a PartialGuildChannel object.
+ * @type {GuildChannel|PartialGuildChannel}
+ */
+ this.channel = this.client.channels.get(data.channel.id) || new PartialGuildChannel(this.client, data.channel);
+
+ /**
+ * The timestamp the invite was created at
+ * @type {number}
+ */
+ this.createdTimestamp = new Date(data.created_at).getTime();
+ }
+
+ /**
+ * The time the invite was created
+ * @type {Date}
+ * @readonly
+ */
+ get createdAt() {
+ return new Date(this.createdTimestamp);
+ }
+
+ /**
+ * The timestamp the invite will expire at
+ * @type {number}
+ * @readonly
+ */
+ get expiresTimestamp() {
+ return this.createdTimestamp + (this.maxAge * 1000);
+ }
+
+ /**
+ * The time the invite will expire
+ * @type {Date}
+ * @readonly
+ */
+ get expiresAt() {
+ return new Date(this.expiresTimestamp);
+ }
+
+ /**
+ * The URL to the invite
+ * @type {string}
+ * @readonly
+ */
+ get url() {
+ return Constants.Endpoints.invite(this.code);
+ }
+
+ /**
+ * Deletes this invite.
+ * @param {string} [reason] Reason for deleting this invite
+ * @returns {Promise}
+ */
+ delete(reason) {
+ return this.client.api.invites(this.code).delete({ reason }).then(() => this);
+ }
+
+ /**
+ * When concatenated with a string, this automatically concatenates the invite's URL instead of the object.
+ * @returns {string}
+ * @example
+ * // Logs: Invite: https://discord.gg/A1b2C3
+ * console.log(`Invite: ${invite}`);
+ */
+ toString() {
+ return this.url;
+ }
+}
+
+module.exports = Invite;
+
+
+/***/ }),
+/* 28 */
/***/ (function(module, exports, __webpack_require__) {
const Snowflake = __webpack_require__(6);
@@ -8352,7 +8901,8 @@ class OAuth2Application {
* @returns {OAuth2Application}
*/
reset() {
- return this.client.rest.methods.resetApplication(this.id);
+ return this.rest.api.oauth2.applications(this.id).reset.post()
+ .then(app => new OAuth2Application(this.client, app));
}
/**
@@ -8368,7 +8918,7 @@ module.exports = OAuth2Application;
/***/ }),
-/* 27 */
+/* 29 */
/***/ (function(module, exports, __webpack_require__) {
/* WEBPACK VAR INJECTION */(function(process) {// Copyright Joyent, Inc. and other Node contributors.
@@ -8599,11 +9149,11 @@ var substr = 'ab'.substr(-1) === 'b'
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7)))
/***/ }),
-/* 28 */
+/* 30 */
/***/ (function(module, exports, __webpack_require__) {
-const Channel = __webpack_require__(14);
-const TextBasedChannel = __webpack_require__(22);
+const Channel = __webpack_require__(16);
+const TextBasedChannel = __webpack_require__(24);
const Collection = __webpack_require__(3);
/*
@@ -8730,16 +9280,17 @@ class GroupDMChannel extends Channel {
/**
* Add a user to the DM
- * @param {UserResolvable|string} accessTokenOrID Access token or user resolvable
+ * @param {UserResolvable|string} accessTokenOrUser Access token or user resolvable
* @param {string} [nick] Permanent nickname to give the user (only available if a bot is creating the DM)
+ * @returns {Promise}
*/
-
- addUser(accessTokenOrID, nick) {
- return this.client.rest.methods.addUserToGroupDM(this, {
- nick,
- id: this.client.resolver.resolveUserID(accessTokenOrID),
- accessToken: accessTokenOrID,
- });
+ addUser(accessTokenOrUser, nick) {
+ const id = this.client.resolver.resolveUserID(accessTokenOrUser);
+ const data = this.client.user.bot ?
+ { nick, access_token: accessTokenOrUser } :
+ { recipient: id };
+ return this.client.api.channels(this.id).recipients(id).put({ data })
+ .then(() => this);
}
/**
@@ -8780,7 +9331,7 @@ module.exports = GroupDMChannel;
/***/ }),
-/* 29 */
+/* 31 */
/***/ (function(module, exports) {
/**
@@ -8835,207 +9386,11 @@ module.exports = ReactionEmoji;
/***/ }),
-/* 30 */
-/***/ (function(module, exports, __webpack_require__) {
-
-const path = __webpack_require__(27);
-
-/**
- * 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 });
- }
- }
-
- 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.
- * @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 {FileOptions[]|string[]} [files] Files 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';
- }
- }
- options.files[i] = file;
- }
-
- return Promise.all(options.files.map(file =>
- this.client.resolver.resolveBuffer(file.attachment).then(buffer => {
- file.file = buffer;
- return file;
- })
- )).then(files => this.client.rest.methods.sendWebhookMessage(this, content, options, files));
- }
-
- return this.client.rest.methods.sendWebhookMessage(this, content, options);
- }
-
- /**
- * 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;
-
-
-/***/ }),
-/* 31 */
+/* 32 */
/***/ (function(module, exports, __webpack_require__) {
const Collection = __webpack_require__(3);
-const EventEmitter = __webpack_require__(12).EventEmitter;
+const EventEmitter = __webpack_require__(14).EventEmitter;
/**
* Filter to be applied to the collector.
@@ -9215,7 +9570,7 @@ module.exports = Collector;
/***/ }),
-/* 32 */
+/* 33 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -9331,7 +9686,7 @@ exports.allocUnsafeSlow = function allocUnsafeSlow(size) {
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(9)))
/***/ }),
-/* 33 */
+/* 34 */
/***/ (function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*
@@ -10549,7 +10904,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
/***/ }),
-/* 34 */
+/* 35 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -10600,18 +10955,18 @@ function nextTick(fn, arg1, arg2, arg3) {
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7)))
/***/ }),
-/* 35 */
+/* 36 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-exports.decode = exports.parse = __webpack_require__(81);
-exports.encode = exports.stringify = __webpack_require__(82);
+exports.decode = exports.parse = __webpack_require__(83);
+exports.encode = exports.stringify = __webpack_require__(84);
/***/ }),
-/* 36 */
+/* 37 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
@@ -10624,7 +10979,7 @@ exports.encode = exports.stringify = __webpack_require__(82);
module.exports = Writable;
/**/
-var processNextTick = __webpack_require__(34);
+var processNextTick = __webpack_require__(35);
/**/
/**/
@@ -10638,13 +10993,13 @@ var Duplex;
Writable.WritableState = WritableState;
/**/
-var util = __webpack_require__(20);
-util.inherits = __webpack_require__(10);
+var util = __webpack_require__(22);
+util.inherits = __webpack_require__(11);
/**/
/**/
var internalUtil = {
- deprecate: __webpack_require__(101)
+ deprecate: __webpack_require__(103)
};
/**/
@@ -10654,7 +11009,7 @@ var Stream = __webpack_require__(60);
var Buffer = __webpack_require__(5).Buffer;
/**/
-var bufferShim = __webpack_require__(32);
+var bufferShim = __webpack_require__(33);
/**/
util.inherits(Writable, Stream);
@@ -10669,7 +11024,7 @@ function WriteReq(chunk, encoding, cb) {
}
function WritableState(options, stream) {
- Duplex = Duplex || __webpack_require__(13);
+ Duplex = Duplex || __webpack_require__(15);
options = options || {};
@@ -10803,7 +11158,7 @@ if (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.protot
}
function Writable(options) {
- Duplex = Duplex || __webpack_require__(13);
+ Duplex = Duplex || __webpack_require__(15);
// Writable ctor is applied to Duplexes, too.
// `realHasInstance` is necessary because using plain `instanceof`
@@ -11159,13 +11514,13 @@ function CorkedRequest(state) {
}
};
}
-/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7), __webpack_require__(98).setImmediate))
+/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7), __webpack_require__(100).setImmediate))
/***/ }),
-/* 37 */
+/* 38 */
/***/ (function(module, exports, __webpack_require__) {
-const Snekfetch = __webpack_require__(92);
+const Snekfetch = __webpack_require__(94);
// const ENV_VAR = '__SNEKFETCH_SYNC_REQUEST';
// let first = true;
@@ -11228,28 +11583,28 @@ module.exports = Snekfetch;
/***/ }),
-/* 38 */
+/* 39 */
/***/ (function(module, exports) {
/***/ }),
-/* 39 */
+/* 40 */
/***/ (function(module, exports, __webpack_require__) {
-/* WEBPACK VAR INJECTION */(function(Buffer) {const path = __webpack_require__(27);
-const fs = __webpack_require__(38);
-const snekfetch = __webpack_require__(37);
+/* WEBPACK VAR INJECTION */(function(Buffer) {const path = __webpack_require__(29);
+const fs = __webpack_require__(39);
+const snekfetch = __webpack_require__(38);
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__(24);
-const Channel = __webpack_require__(14);
-const GuildMember = __webpack_require__(18);
+const User = __webpack_require__(12);
+const Message = __webpack_require__(8);
+const Guild = __webpack_require__(18);
+const Channel = __webpack_require__(16);
+const GuildMember = __webpack_require__(19);
const Emoji = __webpack_require__(17);
-const ReactionEmoji = __webpack_require__(29);
+const ReactionEmoji = __webpack_require__(31);
/**
* The DataResolver identifies different objects and tries to resolve a specific piece of information from them, e.g.
@@ -11569,7 +11924,7 @@ module.exports = ClientDataResolver;
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(5).Buffer))
/***/ }),
-/* 40 */
+/* 41 */
/***/ (function(module, exports) {
module.exports = {
@@ -11668,13 +12023,17 @@ module.exports = {
};
/***/ }),
-/* 41 */
+/* 42 */
/***/ (function(module, exports, __webpack_require__) {
-const User = __webpack_require__(16);
+const User = __webpack_require__(12);
const Collection = __webpack_require__(3);
-const ClientUserSettings = __webpack_require__(42);
+const ClientUserSettings = __webpack_require__(43);
const Constants = __webpack_require__(0);
+const Util = __webpack_require__(4);
+const Guild = __webpack_require__(18);
+const Message = __webpack_require__(8);
+const GroupDMChannel = __webpack_require__(30);
/**
* Represents the logged in client's Discord user.
@@ -11748,8 +12107,18 @@ class ClientUser extends User {
if (data.user_settings) this.settings = new ClientUserSettings(this, data.user_settings);
}
- edit(data) {
- return this.client.rest.methods.updateCurrentUser(data);
+ edit(data, password) {
+ const _data = {};
+ _data.username = data.username || this.username;
+ _data.avatar = this.client.resolver.resolveBase64(data.avatar) || this.avatar;
+ if (!this.bot) {
+ _data.email = data.email || this.email;
+ _data.password = password;
+ if (data.new_password) _data.new_password = data.newPassword;
+ }
+
+ return this.client.api.users('@me').patch({ data })
+ .then(newData => this.client.actions.UserUpdate.handle(newData).updated);
}
/**
@@ -11766,7 +12135,7 @@ class ClientUser extends User {
* .catch(console.error);
*/
setUsername(username, password) {
- return this.client.rest.methods.updateCurrentUser({ username }, password);
+ return this.edit({ username }, password);
}
/**
@@ -11782,7 +12151,7 @@ class ClientUser extends User {
* .catch(console.error);
*/
setEmail(email, password) {
- return this.client.rest.methods.updateCurrentUser({ email }, password);
+ return this.edit({ email }, password);
}
/**
@@ -11798,7 +12167,7 @@ class ClientUser extends User {
* .catch(console.error);
*/
setPassword(newPassword, oldPassword) {
- return this.client.rest.methods.updateCurrentUser({ password: newPassword }, oldPassword);
+ return this.edit({ password: newPassword }, oldPassword);
}
/**
@@ -11813,11 +12182,10 @@ class ClientUser extends User {
*/
setAvatar(avatar) {
if (typeof avatar === 'string' && avatar.startsWith('data:')) {
- return this.client.rest.methods.updateCurrentUser({ avatar });
+ return this.edit({ avatar });
} else {
- return this.client.resolver.resolveBuffer(avatar).then(data =>
- this.client.rest.methods.updateCurrentUser({ avatar: data })
- );
+ return this.client.resolver.resolveBuffer(avatar)
+ .then(data => this.edit({ avatar: this.client.resolver.resolveBase64(data) || null }));
}
}
@@ -11939,58 +12307,42 @@ class ClientUser extends User {
* @returns {Promise}
*/
fetchMentions(options = {}) {
- return this.client.rest.methods.fetchMentions(options);
- }
+ if (options.guild instanceof Guild) options.guild = options.guild.id;
+ Util.mergeDefault({ limit: 25, roles: true, everyone: true, guild: null }, 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);
+ return this.client.api.users('@me').mentions.get({ query: options })
+ .then(data => data.map(m => new Message(this.client.channels.get(m.channel_id), m, this.client)));
}
/**
* 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
+ * @param {Object} [options] Options for the creating
+ * @param {string} [options.region] The region for the server, defaults to the closest one available
+ * @param {BufferResolvable|Base64Resolvable} [options.icon=null] The icon for the guild
* @returns {Promise} The guild that was created
*/
- createGuild(name, region, icon = null) {
- if (!icon) return this.client.rest.methods.createGuild({ name, icon, region });
- if (typeof icon === 'string' && icon.startsWith('data:')) {
- return this.client.rest.methods.createGuild({ name, icon, region });
+ createGuild(name, { region, icon = null } = {}) {
+ if (!icon || (typeof icon === 'string' && icon.startsWith('data:'))) {
+ return this.client.api.guilds.post({ data: { name, region, icon } })
+ .then(data => this.client.dataManager.newGuild(data));
} else {
- return this.client.resolver.resolveBuffer(icon).then(data =>
- this.client.rest.methods.createGuild({ name, icon: data, region })
- );
+ return this.client.resolver.resolveBuffer(icon)
+ .then(data => this.createGuild(name, region, 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
+ * @property {UserResolvable} [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)
+ * @property {string} [id] If no user resolveable is provided and you want to assign nicknames
+ * you must provide user ids instead
*/
/**
@@ -11999,21 +12351,15 @@ class ClientUser extends User {
* @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);
+ const data = this.bot ? {
+ access_tokens: recipients.map(u => u.accessToken),
+ nicks: recipients.reduce((o, r) => {
+ if (r.nick) o[r.user ? r.user.id : r.id] = r.nick;
+ return o;
+ }, {}),
+ } : { recipients: recipients.map(u => this.client.resolver.resolveUserID(u)) };
+ return this.client.api.users('@me').channels.post({ data })
+ .then(res => new GroupDMChannel(this.client, res));
}
}
@@ -12021,7 +12367,7 @@ module.exports = ClientUser;
/***/ }),
-/* 42 */
+/* 43 */
/***/ (function(module, exports, __webpack_require__) {
const Constants = __webpack_require__(0);
@@ -12059,7 +12405,7 @@ class ClientUserSettings {
* @returns {Promise