From 51800b53a077e2dcd330f73a0d54b9d40532b5d4 Mon Sep 17 00:00:00 2001 From: shadowplay1 Date: Wed, 17 Aug 2022 18:19:57 +0300 Subject: [PATCH] discord-leveling-super v1.0.5 **v1.0.5** - Fixed bugs. - Discord.js v14 support. - Now "options.xp" is accepting a number or an array of numbers [min, max] XP values. Every time user sends a message, a random number of XP between `min` and `max` values will be added to a user. - Added a new `gainedXP` property `addXP` and `addTotalXP` events that indicates how much XP the user gained. --- LICENSE | 2 +- dist/LICENSE | 21 + dist/README.md | 45 ++ dist/index.js | 72 +++ dist/install.js | 16 + dist/package.json | 47 ++ dist/src/classes/DotParser.js | 129 ++++++ dist/src/classes/Emitter.js | 41 ++ dist/src/classes/LevelingError.js | 24 + dist/src/index.js | 560 +++++++++++++++++++++++ dist/src/managers/DatabaseManager.js | 173 +++++++ dist/src/managers/FetchManager.js | 144 ++++++ dist/src/managers/LevelManager.js | 143 ++++++ dist/src/managers/RanksManager.js | 112 +++++ dist/src/managers/SettingsManager.js | 232 ++++++++++ dist/src/managers/TotalXPManager.js | 143 ++++++ dist/src/managers/UtilsManager.js | 329 ++++++++++++++ dist/src/managers/XPManager.js | 145 ++++++ dist/src/structures/DefaultObject.js | 16 + dist/src/structures/DefaultOptions.js | 32 ++ dist/src/structures/Errors.js | 85 ++++ package-lock.json | 625 ++++++++++++++++++++++++++ package.json | 94 ++-- src/classes/Emitter.ts | 2 + src/index.ts | 81 ++-- src/managers/DatabaseManager.ts | 18 +- src/managers/FetchManager.ts | 12 +- src/managers/LevelManager.ts | 10 +- src/managers/RanksManager.ts | 2 +- src/managers/SettingsManager.ts | 14 +- src/managers/TotalXPManager.ts | 9 +- src/managers/UtilsManager.ts | 28 +- src/managers/XPManager.ts | 9 +- src/structures/Errors.ts | 2 +- 34 files changed, 3281 insertions(+), 136 deletions(-) create mode 100644 dist/LICENSE create mode 100644 dist/README.md create mode 100644 dist/index.js create mode 100644 dist/install.js create mode 100644 dist/package.json create mode 100644 dist/src/classes/DotParser.js create mode 100644 dist/src/classes/Emitter.js create mode 100644 dist/src/classes/LevelingError.js create mode 100644 dist/src/index.js create mode 100644 dist/src/managers/DatabaseManager.js create mode 100644 dist/src/managers/FetchManager.js create mode 100644 dist/src/managers/LevelManager.js create mode 100644 dist/src/managers/RanksManager.js create mode 100644 dist/src/managers/SettingsManager.js create mode 100644 dist/src/managers/TotalXPManager.js create mode 100644 dist/src/managers/UtilsManager.js create mode 100644 dist/src/managers/XPManager.js create mode 100644 dist/src/structures/DefaultObject.js create mode 100644 dist/src/structures/DefaultOptions.js create mode 100644 dist/src/structures/Errors.js create mode 100644 package-lock.json diff --git a/LICENSE b/LICENSE index 66b5b6c..a5e92bf 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021 ShadowPlay. +Copyright (c) 2022 ShadowPlay. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/dist/LICENSE b/dist/LICENSE new file mode 100644 index 0000000..66b5b6c --- /dev/null +++ b/dist/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 ShadowPlay. + +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. \ No newline at end of file diff --git a/dist/README.md b/dist/README.md new file mode 100644 index 0000000..3d67558 --- /dev/null +++ b/dist/README.md @@ -0,0 +1,45 @@ +# Discord Leveling Super + +[![Downloads](https://img.shields.io/npm/dt/discord-leveling-super?style=for-the-badge)](https://www.npmjs.com/package/discord-leveling-super) +[![Stable Version](https://img.shields.io/npm/v/discord-leveling-super?style=for-the-badge)](https://www.npmjs.com/package/discord-leveling-super) + +Discord Leveling Super - Easy and customizable leveling framework for your [Discord Bot](https://discord.js.org/#/). + +## ❓ | Why? + + +## 📂 | Installation +Note:
+Node.js >=16.9.0 and Discord.js >=14.0.1 is required.
+```console +npm i discord-leveling-super +yarn add discord-leveling-super +pnpm add discord-leveling-super +``` + +## [[Module Documentation]](https://dls-docs.js.org) + +## 🤔 | Help +If you don't understand something in the documentation or you are experiencing problems, feel free to join our Support Server. + +## ❗ | Useful Links + +If you found a bug, have any questions or need help, join the Support Server. +
+Module Created by ShadowPlay. + +# ❤️ Thanks for using Discord Leveling Super ❤️ \ No newline at end of file diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..5d81b56 --- /dev/null +++ b/dist/index.js @@ -0,0 +1,72 @@ +const { existsSync } = require('fs') + +const LevelingError = require('./src/classes/LevelingError') + +const errors = require('./src/structures/Errors') +const modulePackage = require('./package.json') + +const colors = { + red: '\x1b[31m', + green: '\x1b[32m', + yellow: '\x1b[33m', + blue: '\x1b[34m', + magenta: '\x1b[35m', + cyan: '\x1b[36m', + white: '\x1b[37m', + reset: '\x1b[0m' +} + +function moduleVersion(moduleName) { + const modulePath = __dirname.includes('\\') + ? __dirname.split('\\').slice(0, -1).join('\\') + `\\${moduleName}` + : __dirname.split('/').slice(0, -1).join('/') + `/${moduleName}` + + if (!modulePackage.dependencies) return { + status: false, + version: null, + error: errors.noDependencies + } + + if (!existsSync(modulePath)) return { + status: false, + version: null, + error: errors.noDiscordJS + } + + const nodeModulePackage = require(modulePath) + return { + status: true, + version: nodeModulePackage.version, + error: null + } +} + + +function sendError(err) { + const error = new LevelingError(err) + + console.log(`${colors.red}Failed to start the module:${colors.cyan}`) + console.log(error, colors.reset) + + process.exit(1) +} + +const djsVersion = moduleVersion('discord.js') +const nodeVersionNumbers = process.version.slice(1).split('.').map(x => Number(x)) + +function start() { + if (nodeVersionNumbers[0] < 16 && nodeVersionNumbers[1] < 6) return sendError(errors.oldNodeVersion + process.version) + if (djsVersion.error) return sendError(djsVersion.error) + + const djsVersionNumbers = djsVersion.version.split('.').map(x => Number(x)) + if (djsVersionNumbers[0] < 13 && djsVersionNumbers[1] < 1) return sendError(errors.oldDJSVersion + djsVersion.version) + + const Leveling = require('./src/index') + + module.exports = Object.assign(Leveling, { + version: modulePackage.version, + docs: 'https://dls-docs.js.org' + }) +} + +start() \ No newline at end of file diff --git a/dist/install.js b/dist/install.js new file mode 100644 index 0000000..291d2cf --- /dev/null +++ b/dist/install.js @@ -0,0 +1,16 @@ +const colors = { + green: '\x1b[32m', + cyan: '\x1b[36m', + blue: '\x1b[34m' +} + +console.log() +console.log(`${colors.green}╔═══════════════════════════════════════════════════════════════════╗`) +console.log(`${colors.green}║ @ discord-leveling-super - [] X ║`) +console.log(`${colors.green}║═══════════════════════════════════════════════════════════════════║`) +console.log(`${colors.green}║ ${colors.cyan}Thank you for installing Discord Leveling Super! ${colors.green}║`) +console.log(`${colors.green}║═══════════════════════════════════════════════════════════════════║`) +console.log(`${colors.green}║ If you have any questions or need help, join the Support Server: ${colors.green}║`) +console.log(`${colors.green}║ ${colors.blue}https://discord.gg/4pWKq8vUnb ${colors.green}║`) +console.log(`${colors.green}╚═══════════════════════════════════════════════════════════════════╝\x1b[37m`) +console.log() \ No newline at end of file diff --git a/dist/package.json b/dist/package.json new file mode 100644 index 0000000..1a2240e --- /dev/null +++ b/dist/package.json @@ -0,0 +1,47 @@ +{ + "name": "discord-leveling-super", + "version": "1.0.5", + "description": "Easy and customizable leveling framework for your Discord bot.", + "types": "./typings/Leveling.d.ts", + "main": "index.js", + "scripts": { + "test": "echo \"ok\" && exit 0", + "postinstall": "node install.js", + "buildfiles": "tsc", + "begin": "npm i typescript" + }, + "engines": { + "node": ">=16.6.0", + "npm": ">=7.0.0" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/shadowplay1/discord-leveling-super.git" + }, + "keywords": [ + "discord", + "bot", + "discord.js", + "leveling", + "discord-leveling", + "discord-leveling-super", + "ranks", + "ranking", + "discord-ranks", + "discord-js", + "super", + "rank", + "shadowplay" + ], + "author": "shadowplay", + "license": "MIT", + "bugs": { + "url": "https://github.com/shadowplay1/discord-leveling-super/issues" + }, + "homepage": "https://github.com/shadowplay1/discord-leveling-super#readme", + "dependencies": { + "discord.js": "^14.2.0", + "node-fetch": "^2.6.7", + "typescript": "^4.7.4" + } +} \ No newline at end of file diff --git a/dist/src/classes/DotParser.js b/dist/src/classes/DotParser.js new file mode 100644 index 0000000..4a5d6bc --- /dev/null +++ b/dist/src/classes/DotParser.js @@ -0,0 +1,129 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const fs_1 = require("fs"); +const FetchManager_1 = __importDefault(require("../managers/FetchManager")); +const DefaultOptions_1 = __importDefault(require("../structures/DefaultOptions")); +/** + * Dot parser class. + * @private + */ +class DotParser { + options; + storagePath; + fetcher; + /** + * Leveling constructor options object. There's only needed options object properties for this manager to work properly. + * @param {Object} options Constructor options object. + * @param {String} options.storagePath Full path to a JSON file. Default: './leveling.json'. + */ + constructor(options = {}) { + /** + * Leveling constructor options object. + * @private + * @type {LevelingOptions} + */ + this.options = options; + /** + * Fetch manager methods object. + * @type {FetchManager} + * @private + */ + this.fetcher = new FetchManager_1.default(options); + if (!options.storagePath) + this.storagePath = DefaultOptions_1.default.storagePath; + } + /** + * Parses the key and fetches the value from database. + * @param {String} key The key in database. + * @returns {any | false} The data from database or 'false' if failed to parse or 'null' if nothing found. + */ + parse(key) { + let parsed = this.fetcher.fetchAll(); + if (!key) + return false; + if (typeof key !== 'string') + return false; + const keys = key.split('.'); + let tmp = parsed; + for (let i = 0; i < keys.length; i++) { + if ((keys.length - 1) == i) { + parsed = tmp?.[keys[i]] || null; + } + tmp = tmp?.[keys[i]]; + } + return parsed || null; + } + /** + * Parses the key and sets the data in database. + * @param {String} key The key in database. + * @param {any} value Any data to set. + * @returns {Boolean} If set successfully: true; else: false + */ + set(key, value) { + const { isObject } = this; + let storageData = this.fetcher.fetchAll(); + if (!key) + return false; + if (typeof key !== 'string') + return false; + if (value == undefined) + return false; + if (typeof value == 'function') + return false; + const keys = key.split('.'); + let tmp = storageData; + for (let i = 0; i < keys.length; i++) { + if ((keys.length - 1) == i) { + tmp[keys[i]] = value; + } + else if (!isObject(tmp[keys[i]])) { + tmp[keys[i]] = {}; + } + tmp = tmp?.[keys[i]]; + } + (0, fs_1.writeFileSync)(this.options.storagePath || './leveling.json', JSON.stringify(storageData, null, '\t')); + return true; + } + /** + * Parses the key and removes the data from database. + * @param {String} key The key in database. + * @returns {Boolean} If removed successfully: true; else: false + */ + remove(key) { + const { isObject } = this; + let storageData = this.fetcher.fetchAll(); + if (!key) + return false; + if (typeof key !== 'string') + return false; + const data = this.parse(key); + if (data == null) + return false; + const keys = key.split('.'); + let tmp = storageData; + for (let i = 0; i < keys.length; i++) { + if ((keys.length - 1) == i) { + delete tmp?.[keys[i]]; + } + else if (!isObject(tmp?.[keys[i]])) { + tmp[keys[i]] = {}; + } + tmp = tmp[keys[i]]; + } + (0, fs_1.writeFileSync)(this.options.storagePath || './leveling.json', JSON.stringify(storageData, null, '\t')); + return true; + } + /** + * Checks for is the item object and returns it. + * @param {any} item The item to check. + * @returns {Boolean} Is the item object or not. + */ + isObject(item) { + return !Array.isArray(item) + && typeof item == 'object' + && item !== null; + } +} +module.exports = DotParser; diff --git a/dist/src/classes/Emitter.js b/dist/src/classes/Emitter.js new file mode 100644 index 0000000..1e8b5cb --- /dev/null +++ b/dist/src/classes/Emitter.js @@ -0,0 +1,41 @@ +"use strict"; +const events_1 = require("events"); +const emitter = new events_1.EventEmitter(); +/** + * Simple Leveling event emitter with only important emitter methods. + * @private + */ +class Emitter { + /** + * Simple Leveling event emitter with only important emitter methods. + * @private + */ + constructor() { } + /** + * Listens to the event. + * @param {LevelingEvents} event Event name. + * @param {Function} listener Listener function. + */ + on(event, listener) { + emitter.on(event, listener); + return this; + } + /** + * Listens to the event only for once. + * @param {LevelingEvents} event Event name. + * @param {Function} listener Listener function. + */ + once(event, listener) { + emitter.once(event, listener); + return this; + } + /** + * Emits the event. + * @param {LevelingEvents} event Event name. + * @param {Function} args Listener arguments. + */ + emit(event, ...args) { + return emitter.emit(event, ...args); + } +} +module.exports = Emitter; diff --git a/dist/src/classes/LevelingError.js b/dist/src/classes/LevelingError.js new file mode 100644 index 0000000..1deeaa2 --- /dev/null +++ b/dist/src/classes/LevelingError.js @@ -0,0 +1,24 @@ +"use strict"; +/** + * LevelingError class. + */ +class LevelingError extends Error { + /** + * Creates an 'LevelingError' instance. + * @param {String | Error} message Error message. + */ + constructor(message) { + if (message instanceof Error) { + super(message.message); + Error.captureStackTrace(this, this.constructor); + } + else + super(message); + /** + * Error name. + * @type {String} + */ + this.name = 'LevelingError'; + } +} +module.exports = LevelingError; diff --git a/dist/src/index.js b/dist/src/index.js new file mode 100644 index 0000000..fce2c85 --- /dev/null +++ b/dist/src/index.js @@ -0,0 +1,560 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const util_1 = require("util"); +const fs_1 = require("fs"); +const Emitter_1 = __importDefault(require("./classes/Emitter")); +const LevelingError_1 = __importDefault(require("./classes/LevelingError")); +const Errors_1 = __importDefault(require("./structures/Errors")); +const DefaultObject_1 = __importDefault(require("./structures/DefaultObject")); +const UtilsManager_1 = __importDefault(require("./managers/UtilsManager")); +const DatabaseManager_1 = __importDefault(require("./managers/DatabaseManager")); +const FetchManager_1 = __importDefault(require("./managers/FetchManager")); +const RanksManager_1 = __importDefault(require("./managers/RanksManager")); +const XPManager_1 = __importDefault(require("./managers/XPManager")); +const LevelManager_1 = __importDefault(require("./managers/LevelManager")); +const TotalXPManager_1 = __importDefault(require("./managers/TotalXPManager")); +const SettingsManager_1 = __importDefault(require("./managers/SettingsManager")); +const package_json_1 = __importDefault(require("../package.json")); +const colors = { + red: '\x1b[31m', + green: '\x1b[32m', + yellow: '\x1b[33m', + blue: '\x1b[34m', + magenta: '\x1b[35m', + cyan: '\x1b[36m', + white: '\x1b[37m', + reset: '\x1b[0m' +}; +/** + * The Leveling class. + * @extends {Emitter} + */ +class Leveling extends Emitter_1.default { + /** + * Leveling options object. + * @type {LevelingOptions} + */ + options; + /** + * Discord Bot Client + * @type {Client} + */ + client; + /** + * Module ready status. + * @type {Boolean} + */ + ready; + /** + * Module errored status. + * @type {Boolean} + */ + errored; + /** + * Database checking interval. + * @type {NodeJS.Timeout} + */ + interval; + /** + * Leveling error class. + * @type {LevelingError} + */ + LevelingError; + /** + * Utils manager methods object. + * @type {UtilsManager} + */ + utils; + /** + * Module version. + * @type {String} + */ + version; + /** + * Link to the module's documentation website. + * @type {String} + */ + docs; + /** + * Database manager methods object. + * @type {DatabaseManager} + */ + database; + /** + * XP manager methods object. + * @type {FetchManager} + */ + fetcher; + /** + * Settings manager methods class. + * @type {SettingsManager} + */ + settings; + /** + * XP manager methods object. + * @type {XPManager} + */ + xp; + /** + * Level manager methods object. + * @type {LevelManager} + */ + levels; + /** + * Total XP manager methods object. + * @type {LevelManager} + */ + totalXP; + /** + * Ranks manager methods object. + * @type {RanksManager} + */ + ranks; + /** + * The Leveling class. + * @param {Client} client Discord Bot Client. + * @param {LevelingOptions} options Leveling options object. + */ + constructor(client, options = {}) { + super(); + this.LevelingError = LevelingError_1.default; + this.utils = new UtilsManager_1.default(options, client); + this.options = this.utils.checkOptions(options.optionsChecker, options || {}); + this.client = client; + this.ready = false; + this.errored = false; + this.interval = null; + this.version = package_json_1.default.version; + this.docs = 'https://dls-docs.js.org'; + this.database = null; + this.fetcher = null; + this.settings = null; + this.xp = null; + this.levels = null; + this.totalXP = null; + this.ranks = null; + this.init(); + } + /** + * Kills the Leveling instance. + * @fires Leveling#destroy + * @returns {Leveling | boolean} Leveling instance. + */ + kill() { + if (!this.ready) + return false; + clearInterval(this.interval); + this.ready = false; + this.LevelingError = null; + this.interval = null; + this.utils = null; + this.database = null; + this.fetcher = null; + this.settings = null; + this.xp = null; + this.levels = null; + this.totalXP = null; + this.ranks = null; + this.emit('destroy'); + return this; + } + /** + * Starts the module. + * @fires Leveling#ready + * @returns {Promise} If started successfully: true; else: Error instance. + */ + init() { + let attempt = 0; + let attempts = this.options?.errorHandler?.attempts == 0 ? Infinity : this.options?.errorHandler?.attempts; + const time = this.options?.errorHandler?.time; + const retryingTime = (time / 1000).toFixed(1); + const sleep = (0, util_1.promisify)(setTimeout); + const check = () => new Promise(resolve => { + this._init().then(x => { + if (x) { + this.errored = false; + this.ready = true; + return console.log(`${colors.green}Started successfully! :)`); + } + resolve(x); + }).catch(err => resolve(err)); + }); + return this.options?.errorHandler?.handleErrors ? this._init().catch(async (err) => { + if (!(err instanceof LevelingError_1.default)) + this.errored = true; + console.log(`${colors.red}Failed to start the module:${colors.cyan}`); + console.log(err); + if (err.message.includes('This module is supporting only Node.js v14 or newer.')) + process.exit(1); + else + console.log(`${colors.magenta}Retrying in ${retryingTime} seconds...${colors.reset}`); + while (attempt < attempts && attempt !== -1) { + await sleep(time); + if (attempt < attempts) + check().then(async (res) => { + if (res.message) { + attempt++; + console.log(`${colors.red}Failed to start the module:${colors.cyan}`); + console.log(err); + console.log(`\x1b[34mAttempt ${attempt}${attempts == Infinity ? '.' : `/${attempts}`}`); + if (attempt == attempts) { + console.log(`${colors.green}Failed to start the module within ${attempts} attempts...${colors.reset}`); + process.exit(1); + } + console.log(`${colors.magenta}Retrying in ${retryingTime} seconds...`); + await sleep(time); + } + else + attempt = -1; + }); + } + }) : this._init(); + } + /** + * Initializates the module. + * @returns {Promise} If started successfully: true; else: Error instance. + * @private + */ + _init() { + const storagePath = this.options.storagePath || './leveling.json'; + const updateCountdown = this.options.updateCountdown; + const isFileExist = (0, fs_1.existsSync)(storagePath); + return new Promise(async (resolve, reject) => { + try { + if (!this.client) + return reject(new LevelingError_1.default(Errors_1.default.noClient)); + if (this.errored) + return; + if (this.ready) + return; + if (this.options?.checkStorage) { + if (!isFileExist) + (0, fs_1.writeFileSync)(storagePath, '{}'); + try { + if (storagePath.endsWith('package.json')) + return reject(new LevelingError_1.default(Errors_1.default.reservedName('package.json'))); + if (storagePath.endsWith('package-lock.json')) + return reject(new LevelingError_1.default(Errors_1.default.reservedName('package-lock.json'))); + const data = (0, fs_1.readFileSync)(storagePath); + JSON.parse(data.toString()); + } + catch (err) { + if (err.message.includes('Unexpected') && err.message.includes('JSON')) + return reject(new LevelingError_1.default(Errors_1.default.wrongStorageData)); + else + reject(err); + } + } + if (this.options.updater?.checkUpdates) { + const version = await this.utils.checkUpdates(); + if (!version.updated) { + console.log('\n\n'); + console.log(colors.green + '╔═══════════════════════════════════════════════════════════════╗'); + console.log(colors.green + '║ @ discord-leveling-super - [] X ║'); + console.log(colors.green + '║═══════════════════════════════════════════════════════════════║'); + console.log(colors.yellow + `║ The module is ${colors.red}out of date!${colors.yellow} ║`); + console.log(colors.magenta + '║ New version is available! ║'); + console.log(colors.blue + `║ ${version.installedVersion} --> ${version.packageVersion} ║`); + console.log(colors.cyan + '║ Run "npm i discord-leveling-super@latest" ║'); + console.log(colors.cyan + '║ to update! ║'); + console.log(colors.white + '║ View the full changelog here: ║'); + console.log(colors.red + '║ https://dls-docs.js.org/#/docs/main/stable/general/changelog ║'); + console.log(colors.green + '╚═══════════════════════════════════════════════════════════════╝\x1b[37m'); + console.log('\n\n'); + } + else { + if (this.options?.updater?.upToDateMessage) { + console.log('\n\n'); + console.log(colors.green + '╔═══════════════════════════════════════════════════════════════╗'); + console.log(colors.green + '║ @ discord-leveling-super - [] X ║'); + console.log(colors.green + '║═══════════════════════════════════════════════════════════════║'); + console.log(colors.yellow + `║ The module is ${colors.cyan}up of date!${colors.yellow} ║`); + console.log(colors.magenta + '║ No updates are available. ║'); + console.log(colors.blue + `║ Current version is ${version.packageVersion}. ║`); + console.log(colors.cyan + '║ Enjoy! ║'); + console.log(colors.white + '║ View the full changelog here: ║'); + console.log(colors.red + '║ https://dls-docs.js.org/#/docs/main/stable/general/changelog ║'); + console.log(colors.green + '╚═══════════════════════════════════════════════════════════════╝\x1b[37m'); + console.log('\n\n'); + } + } + } + if (this.options?.checkStorage == undefined ? true : this.options?.checkStorage) { + const storageExists = (0, fs_1.existsSync)(storagePath); + const interval = setInterval(() => { + if (!storageExists) { + try { + if (storagePath?.endsWith('package.json')) + throw new LevelingError_1.default(Errors_1.default.reservedName('package.json')); + if (storagePath?.endsWith('package-lock.json')) + throw new LevelingError_1.default(Errors_1.default.reservedName('package-lock.json')); + (0, fs_1.writeFileSync)(storagePath, '{}', 'utf-8'); + } + catch (err) { + throw new LevelingError_1.default(Errors_1.default.notReady); + } + console.log(`${colors.red}failed to find a database file; created another one...${colors.reset}`); + } + try { + if (!storageExists) + (0, fs_1.writeFileSync)(storagePath, '{}', 'utf-8'); + const data = (0, fs_1.readFileSync)(storagePath); + JSON.parse(data.toString()); + } + catch (err) { + if (err.message.includes('Unexpected token') || + err.message.includes('Unexpected end')) + reject(new LevelingError_1.default(Errors_1.default.wrongStorageData)); + else { + reject(err); + throw err; + } + } + }, updateCountdown); + this.interval = interval; + } + this.start(); + this.ready = true; + this.emit('ready', undefined); + return resolve(true); + } + catch (err) { + this.errored = true; + reject(err); + } + }); + } + /** + * Starts all the managers. + * @returns {Boolean} If successfully started: true. + * @private + */ + start() { + this.utils = new UtilsManager_1.default(this.options, this.client); + this.database = new DatabaseManager_1.default(this.options); + this.fetcher = new FetchManager_1.default(this.options); + this.settings = new SettingsManager_1.default(this.options, this.client); + this.xp = new XPManager_1.default(this.options); + this.levels = new LevelManager_1.default(this.options); + this.totalXP = new TotalXPManager_1.default(this.options); + this.ranks = new RanksManager_1.default(this.options, this.client); + if (!this.client.on) { + console.log(new LevelingError_1.default(Errors_1.default.invalidClient)); + process.exit(1); + } + this.client.on('messageCreate', async (message) => { + if (this.ready) { + const data = this.fetcher.fetchAll(); + const guildID = message.guild.id; + const memberID = message.author.id; + const settings = { + xp: this.settings.get('xp', guildID), + maxXP: this.settings.get('maxXP', guildID), + multiplier: this.settings.get('multiplier', guildID), + status: this.settings.get('status', guildID), + ignoreBots: this.settings.get('ignoreBots', guildID), + lockedChannels: this.settings.get('lockedChannels', guildID), + ignoredUsers: this.settings.get('ignoredUsers', guildID), + filter: this.settings.get('filter', guildID) + }; + const filterFunction = (settings.filter || this.options.filter).toString(); + const filter = filterFunction.includes('{') ? + filterFunction.split('{').slice(1).join('').slice(0, -1) : + 'return ' + filterFunction.split('=>').slice(1).join(''); + const options = { + xp: settings.xp || this.options.xp, + maxXP: settings.maxXP || this.options.maxXP, + multiplier: settings.multiplier || this.options.multiplier, + status: settings.status == null ? this.options.status : settings.status, + ignoreBots: settings.ignoreBots == null ? this.options.ignoreBots : settings.ignoreBots, + lockedChannels: settings.lockedChannels || this.options.lockedChannels, + ignoredUsers: settings.ignoredUsers || this.options.ignoredUsers, + filter: new Function('msg', filter) + }; + const lockedChannelsArray = []; + const ignoredUsersArray = []; + const ignoredGuildsArray = []; + const lockedChannels = options.lockedChannels; + const ignoredUsers = options.ignoredUsers; + const ignoredGuilds = this.options.ignoredGuilds; + for (let i of lockedChannels) { + const type = this.utils.typeOf(i); + switch (type) { + case 'String': + lockedChannelsArray.push(i); + break; + default: + lockedChannelsArray.push(i); + } + } + const invalidChannelTypes = lockedChannelsArray.filter(x => typeof x !== 'string'); + if (invalidChannelTypes.length) { + throw new LevelingError_1.default(Errors_1.default.lockedChannels.invalidTypes + + '\n[\n' + + lockedChannels + .map((x) => { + const type = this.utils.typeOf(x); + const isOk = type == 'String' ? '(ok)' : ''; + return ` ${x} - ${type} ${isOk}`; + }) + .join('\n') + + '\n]'); + } + const invalidChannels = lockedChannelsArray.filter(x => x.length !== 18 && x.length !== 19); + if (invalidChannels.length) + return console.log(new LevelingError_1.default(Errors_1.default.lockedChannels.invalidChannels(invalidChannels))); + for (let i of ignoredUsers) { + const type = this.utils.typeOf(i); + switch (type) { + case 'String': + ignoredUsersArray.push(i); + break; + default: + ignoredUsersArray.push(i); + } + } + const invalidUserTypes = ignoredUsersArray.filter(x => typeof x !== 'string'); + if (invalidUserTypes.length) { + throw new LevelingError_1.default(Errors_1.default.ignoredUsers.invalidTypes + + '\n[\n' + + ignoredUsers + .map((x) => { + const type = this.utils.typeOf(x); + const isOk = type == 'String' ? '(ok)' : ''; + return ` ${x} - ${type} ${isOk}`; + }) + .join('\n') + + '\n]'); + } + const invalidUsers = ignoredUsersArray.filter(x => x.length !== 18 && x.length !== 19); + if (invalidUsers.length && ignoredUsers.length) + return console.log(new LevelingError_1.default(Errors_1.default.ignoredUsers.invalidUsers(ignoredUsers))); + for (let i of ignoredGuilds) { + const type = this.utils.typeOf(i); + switch (type) { + case 'String': + ignoredGuildsArray.push(i); + break; + default: + ignoredGuildsArray.push(i); + } + } + const invalidGuildTypes = ignoredGuildsArray.filter(x => typeof x !== 'string'); + if (invalidGuildTypes.length) { + throw new LevelingError_1.default(Errors_1.default.ignoredGuilds.invalidTypes + + '\n[\n' + + ignoredGuilds + .map((x) => { + const type = this.utils.typeOf(x); + const isOk = type == 'String' ? '(ok)' : ''; + return ` ${x} - ${type} ${isOk}`; + }) + .join('\n') + + '\n]'); + } + const invalidGuilds = ignoredGuildsArray.filter(x => x.length !== 18 && x.length !== 19); + if (invalidGuilds.length && ignoredGuilds.length) + throw new LevelingError_1.default(Errors_1.default.ignoredGuilds.invalidGuilds(invalidGuilds)); + const levelingStatus = options.status; + const isFiltered = options.filter(message); + const isUserIgnored = ignoredUsersArray.includes(message.author.id); + const isLockedChannel = lockedChannelsArray.includes(message.channel.id); + const isGuildIgnored = ignoredGuildsArray.includes(message.guild.id); + const isBot = options.ignoreBots && message.author.bot; + const guildData = data[guildID]; + let memberData = guildData?.[memberID]; + if (levelingStatus && isFiltered && + !isLockedChannel && !isUserIgnored && + !isBot && !isGuildIgnored) { + if (!memberData) { + this.utils.reset(memberID, guildID); + memberData = DefaultObject_1.default; + return; + } + const level = this.database.fetch(`${guildID}.${memberID}.level`); + const memberMultiplier = this.database.fetch(`${guildID}.${memberID}.multiplier`); + const userXP = this.database.fetch(`${guildID}.${memberID}.xp`); + const userMaxXP = this.database.fetch(`${guildID}.${memberID}.maxXP`); + const settingsEXP = this.settings.get('xp', guildID); + const settingsXP = Array.isArray(settingsEXP) ? Math.floor(Math.random() * (settingsEXP[1] - settingsEXP[0] + 1)) + settingsEXP[0] : settingsEXP; + const xp = Array.isArray(options.xp) ? Math.floor(Math.random() * (options.xp[1] - options.xp[0] + 1)) + options.xp[0] : options.xp; + const multiplier = memberMultiplier == 1 ? options.multiplier : memberMultiplier; + const memberXP = xp * multiplier; + const newLevel = level + 1; + this.xp.add(memberXP, memberID, guildID, true); + this.totalXP.add(memberXP, memberID, guildID, true); + this.database.set(`${guildID}.${memberID}.difference`, (userMaxXP - userXP) - settingsXP); + if (memberData.xp >= memberData.maxXP || memberXP > memberData.maxXP) { + const newMaxXP = options.maxXP * newLevel; + this.xp.set(0, memberID, guildID, true); + this.levels.add(1, memberID, guildID, true); + this.database.set(`${guildID}.${memberID}.maxXP`, newMaxXP); + this.database.set(`${guildID}.${memberID}.difference`, newMaxXP); + this.emit('levelUp', { + guildID, + user: message.author, + level: newLevel, + maxXP: newMaxXP, + multiplier, + sendMessage: (msg, channel) => { + const type = this.utils.typeOf(msg); + let messageOptions; + let textChannel; + switch (type) { + case 'String': + messageOptions = { + content: msg + }; + break; + case 'Object': + messageOptions = msg; + break; + case 'EmbedBuilder': + messageOptions = { + embeds: [ + msg + ] + }; + break; + case 'AttachmentBuilder': + messageOptions = { + files: [ + messageOptions + ] + }; + break; + default: + throw new LevelingError_1.default(Errors_1.default.sendMessage.invalidTypes.msg + type); + } + if (channel) { + const channelType = this.utils.typeOf(channel); + switch (channelType) { + case 'String': + textChannel = this.client.channels.cache.get(channel); + break; + case 'Channel': + textChannel = channel; + break; + case 'TextChannel': + textChannel = channel; + break; + default: + throw new LevelingError_1.default(Errors_1.default.sendMessage.invalidTypes.channel + channelType); + } + if (!textChannel) + throw new LevelingError_1.default(Errors_1.default.sendMessage.channelNotFound); + return textChannel.send(messageOptions); + } + return message.channel.send(messageOptions); + } + }); + } + } + } + }); + return true; + } +} +module.exports = Leveling; diff --git a/dist/src/managers/DatabaseManager.js b/dist/src/managers/DatabaseManager.js new file mode 100644 index 0000000..89b6ecb --- /dev/null +++ b/dist/src/managers/DatabaseManager.js @@ -0,0 +1,173 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const FetchManager_1 = __importDefault(require("./FetchManager")); +const Errors_1 = __importDefault(require("../structures/Errors")); +const DotParser_1 = __importDefault(require("../classes/DotParser")); +const LevelingError_1 = __importDefault(require("../classes/LevelingError")); +/** + * Database manager methods class. + */ +class DatabaseManager { + /** + * Dor Parser. + * @type {DotParser} + * @private + */ + parser; + /** + * Fetch Manager. + * @type {FetchManager} + * @private + */ + fetcher; + /** + * Database manager methods class. + * @param {LevelingOptions} options Leveling options object. + */ + constructor(options = {}) { + this.fetcher = new FetchManager_1.default(options); + this.parser = new DotParser_1.default({ storagePath: options.storagePath || './leveling.json' }); + } + /** + * Gets a list of keys in database. + * @param {String} key The key in database. + * @returns {string[]} An array with all keys in database or 'null' if nothing found. + */ + keyList(key) { + const storageData = this.fetcher.fetchAll(); + const data = this.fetch(key); + if (!key || typeof key !== 'string') + return Object.keys(storageData).filter(x => storageData[x]); + if (data == null) + return null; + const keys = Object.keys(data); + return keys.filter(x => data[x] !== undefined && data[x] !== null); + } + /** + * Sets data in a property in database. + * @param {String} key The key in database. + * @param {any} value Any data to set in property. + * @returns {Boolean} If set successfully: true; else: false + */ + set(key, value) { + if (!key) + return false; + if (typeof key !== 'string') + throw new LevelingError_1.default(Errors_1.default.databaseManager.invalidTypes.key + typeof key); + if (value == undefined) + return false; + return this.parser.set(key, value); + } + /** + * Adds a number to a property data in database. + * @param {String} key The key in database. + * @param {Number} value Any number to add. + * @returns {Boolean} If added successfully: true; else: false + */ + add(key, value) { + const data = this.parser.parse(key); + if (!key) + return false; + if (typeof key !== 'string') + throw new LevelingError_1.default(Errors_1.default.databaseManager.invalidTypes.key + typeof key); + if (isNaN(value)) + throw new LevelingError_1.default(Errors_1.default.databaseManager.invalidTypes.value.number + typeof value); + if (isNaN(data)) + throw new LevelingError_1.default(Errors_1.default.databaseManager.invalidTypes.target.number + typeof data); + const numData = Number(data); + const numValue = Number(value); + return this.set(key, numData + numValue); + } + /** + * Subtracts a number from a property data in database. + * @param {String} key The key in database. + * @param {Number} value Any number to subtract. + * @returns {Boolean} If set successfully: true; else: false + */ + subtract(key, value) { + const data = this.parser.parse(key); + if (!key) + return false; + if (typeof key !== 'string') + throw new LevelingError_1.default(Errors_1.default.databaseManager.invalidTypes.key + typeof key); + if (isNaN(value)) + throw new LevelingError_1.default(Errors_1.default.databaseManager.invalidTypes.value.number + typeof value); + if (isNaN(data)) + throw new LevelingError_1.default(Errors_1.default.databaseManager.invalidTypes.target.number + typeof data); + const numData = Number(data); + const numValue = Number(value); + return this.set(key, numData - numValue); + } + /** + * Fetches the data from the storage file. + * @param {String} key The key in database. + * @returns {any | false} Value from the specified key or 'false' if failed to read or 'null' if nothing found. + */ + fetch(key) { + if (!key) + return false; + if (typeof key !== 'string') + throw new LevelingError_1.default(Errors_1.default.databaseManager.invalidTypes.key + typeof key); + return this.parser.parse(key); + } + /** + * Removes the property from the existing object in database. + * @param {String} key The key in database. + * @returns {Boolean} If cleared: true; else: false. + */ + remove(key) { + if (!key) + return false; + if (typeof key !== 'string') + throw new LevelingError_1.default(Errors_1.default.databaseManager.invalidTypes.key + typeof key); + return this.parser.remove(key); + } + /** + * Pushes a value to a specified array from the database. + * @param {String} key The key in database. + * @param {any} value The key in database. + * @returns {Boolean} If cleared: true; else: false. + */ + push(key, value) { + if (!key) + return false; + if (value == undefined) + return false; + if (typeof key !== 'string') + throw new LevelingError_1.default(Errors_1.default.databaseManager.invalidTypes.key + typeof key); + let data = this.fetch(key) || []; + if (!Array.isArray(data) && !data.length) + throw new LevelingError_1.default(Errors_1.default.databaseManager.invalidTypes.target.array + typeof data); + data.push(value); + return this.set(key, data); + } + /** + * Removes an element from a specified array in the database. + * @param {String} key The key in database. + * @param {Number} index The index in the array. + * @returns {Boolean} If cleared: true; else: false. + */ + removeElement(key, index) { + if (!key) + return false; + if (index == undefined) + return false; + if (typeof key !== 'string') + throw new LevelingError_1.default(Errors_1.default.databaseManager.invalidTypes.key + typeof key); + let data = this.fetch(key); + if (!Array.isArray(data)) + throw new LevelingError_1.default(Errors_1.default.databaseManager.invalidTypes.target.array + typeof data); + data.splice(index, 1); + return this.set(key, data); + } + /** + * Fetches the entire database. + * @returns {Object} Database contents + */ + all() { + return this.fetcher.fetchAll(); + } +} +module.exports = DatabaseManager; diff --git a/dist/src/managers/FetchManager.js b/dist/src/managers/FetchManager.js new file mode 100644 index 0000000..8f49634 --- /dev/null +++ b/dist/src/managers/FetchManager.js @@ -0,0 +1,144 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const fs_1 = require("fs"); +const discord_js_1 = require("discord.js"); +const Errors_1 = __importDefault(require("../structures/Errors")); +const LevelingError_1 = __importDefault(require("../classes/LevelingError")); +/** + * Fetch manager methods class. + */ +class FetchManager { + /** + * Storage Path. + * @type {String} + * @private + */ + storagePath; + /** + * Fetch manager methods class. + * @param {LevelingOptions} options Leveling options object. + */ + constructor(options = {}) { + this.storagePath = options.storagePath || './leveling.json'; + } + /** + * Gets the amount of XP for specified user. + * @param {String | GuildMember | User} member Member or it's ID. + * @param {String | Guild} guild Guild or it's ID. + * @returns {Number} Amount of XP. + */ + fetchXP(member, guild) { + const data = this.fetchAll(); + const isUser = member instanceof discord_js_1.GuildMember || member instanceof discord_js_1.User; + const isGuild = guild instanceof discord_js_1.Guild; + if (typeof member !== 'string' && !isUser) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.member + typeof member); + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + const user = isUser ? member.id : member.toString(); + const botGuild = isGuild ? guild.id : guild.toString(); + const guildData = data[botGuild]; + const memberData = guildData?.[user]; + const xp = memberData?.xp; + return (xp || 0); + } + /** + * Gets the amount of total XP for specified user. + * @param {String | GuildMember | User} member Member or it's ID. + * @param {String | Guild} guild Guild or it's ID. + * @returns {Number} Amount of XP. + */ + fetchTotalXP(member, guild) { + const data = this.fetchAll(); + const isUser = member instanceof discord_js_1.GuildMember || member instanceof discord_js_1.User; + const isGuild = guild instanceof discord_js_1.Guild; + if (typeof member !== 'string' && !isUser) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.member + typeof member); + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + const user = isUser ? member.id : member.toString(); + const botGuild = isGuild ? guild.id : guild.toString(); + const guildData = data[botGuild]; + const memberData = guildData?.[user]; + const totalXP = memberData?.totalXP; + return (totalXP || 0); + } + /** + * Gets the amount of levels for specified user. + * @param {String | GuildMember | User} member Member or it's ID. + * @param {String | Guild} guild Guild or it's ID. + * @returns {Number} Amount of XP. + */ + fetchLevels(member, guild) { + const data = this.fetchAll(); + const isUser = member instanceof discord_js_1.GuildMember || member instanceof discord_js_1.User; + const isGuild = guild instanceof discord_js_1.Guild; + if (typeof member !== 'string' && !isUser) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.member + typeof member); + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + const user = isUser ? member.id : member.toString(); + const botGuild = isGuild ? guild.id : guild.toString(); + const guildData = data[botGuild]; + const memberData = guildData?.[user]; + const levels = memberData?.level; + return (levels || 0); + } + /** + * Gets the amount of max XP for specified user. + * @param {String | GuildMember | User} member Member or it's ID. + * @param {String | Guild} guild Guild or it's ID. + * @returns {Number} Amount of XP. + */ + fetchMaxXP(member, guild) { + const data = this.fetchAll(); + const isUser = member instanceof discord_js_1.GuildMember || member instanceof discord_js_1.User; + const isGuild = guild instanceof discord_js_1.Guild; + if (typeof member !== 'string' && !isUser) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.member + typeof member); + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + const user = isUser ? member.id : member.toString(); + const botGuild = isGuild ? guild.id : guild.toString(); + const guildData = data[botGuild]; + const memberData = guildData?.[user]; + const maxXP = memberData?.maxXP; + return (maxXP || 0); + } + /** + * Gets the difference between max XP and user's XP. + * @param {String | GuildMember | User} member Member or it's ID. + * @param {String | Guild} guild Guild or it's ID. + * @returns {Number} Amount of XP. + */ + fetchDifference(member, guild) { + const data = this.fetchAll(); + const isUser = member instanceof discord_js_1.GuildMember || member instanceof discord_js_1.User; + const isGuild = guild instanceof discord_js_1.Guild; + if (typeof member !== 'string' && !isUser) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.member + typeof member); + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + const user = isUser ? member.id : member.toString(); + const botGuild = isGuild ? guild.id : guild.toString(); + const guildData = data[botGuild]; + const memberData = guildData?.[user]; + const difference = memberData?.difference; + return (difference || 0); + } + /** + * Fetches the entire database. + * @returns {Object} Database contents + */ + fetchAll() { + const isFileExisting = (0, fs_1.existsSync)(this.storagePath); + if (!isFileExisting) + (0, fs_1.writeFileSync)(this.storagePath, '{}'); + const fileData = (0, fs_1.readFileSync)(this.storagePath); + const stringData = fileData.toString(); + return JSON.parse(stringData); + } +} +module.exports = FetchManager; diff --git a/dist/src/managers/LevelManager.js b/dist/src/managers/LevelManager.js new file mode 100644 index 0000000..3d3cada --- /dev/null +++ b/dist/src/managers/LevelManager.js @@ -0,0 +1,143 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const discord_js_1 = require("discord.js"); +const Emitter_1 = __importDefault(require("../classes/Emitter")); +const LevelingError_1 = __importDefault(require("../classes/LevelingError")); +const DatabaseManager_1 = __importDefault(require("./DatabaseManager")); +const Errors_1 = __importDefault(require("../structures/Errors")); +/** + * Level manager methods class. + * @extends {Emitter} + */ +class LevelManager extends Emitter_1.default { + /** + * Database Manager. + * @type {DatabaseManager} + * @private + */ + database; + /** + * Leveling manager methods class. + * @param {LevelingOptions} options Leveling options object. + */ + constructor(options) { + super(); + this.database = new DatabaseManager_1.default(options); + } + /** + * Gets the XP for specified user. + * @param {String | GuildMember | User} member Member or it's ID. + * @param {String | Guild} guild Guild or it's ID. + * @returns {Number} Amount of levels. + */ + get(member, guild) { + const isUser = member instanceof discord_js_1.GuildMember || member instanceof discord_js_1.User; + const isGuild = guild instanceof discord_js_1.Guild; + if (typeof member !== 'string' && !isUser) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.member + typeof member); + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + const user = isUser ? member.id : member.toString(); + const botGuild = isGuild ? guild.id : guild.toString(); + const level = this.database.fetch(`${botGuild}.${user}.level`); + return level; + } + /** + * Sets the XP for specified user. + * @fires Leveling#setLevel + * @param {Number} level Amount of levels. + * @param {String | GuildMember | User} member Member or it's ID. + * @param {String | Guild} guild Guild or it's ID. + * @returns {Boolean} If set successfully: true, else: false. + */ + set(level, member, guild) { + const isUser = member instanceof discord_js_1.GuildMember || member instanceof discord_js_1.User; + const isGuild = guild instanceof discord_js_1.Guild; + if (typeof member !== 'string' && !isUser) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.member + typeof member); + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + const user = isUser ? member.id : member.toString(); + const botGuild = isGuild ? guild.id : guild.toString(); + const userLevelData = this.database.fetch(`${botGuild}.${user}`); + this.emit('setLevel', { + userData: userLevelData.userData, + guildID: botGuild, + userID: user, + xp: userLevelData.xp, + totalXP: userLevelData.totalXP, + level, + maxXP: userLevelData.maxXP, + difference: userLevelData.difference, + multiplier: userLevelData.multiplier + }); + return this.database.set(`${botGuild}.${user}.level`, level); + } + /** + * Adds the XP for specified user. + * @fires Leveling#addLevel + * @param {Number} level Amount of levels. + * @param {String | GuildMember | User} member Member or it's ID. + * @param {String | Guild} guild Guild or it's ID. + * @param {Boolean} onMessage The value will be true if the method was called on 'messageCreate' bot event. + * @returns {Boolean} If added successfully: true, else: false. + */ + add(level, member, guild, onMessage = false) { + const isUser = member instanceof discord_js_1.GuildMember || member instanceof discord_js_1.User; + const isGuild = guild instanceof discord_js_1.Guild; + if (typeof member !== 'string' && !isUser) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.member + typeof member); + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + const user = isUser ? member.id : member.toString(); + const botGuild = isGuild ? guild.id : guild.toString(); + const userData = this.database.fetch(`${botGuild}.${user}`); + if (!onMessage) + this.emit('addLevel', { + guildID: botGuild, + userID: user, + xp: userData.xp, + totalXP: userData.totalXP, + level: userData.level + level, + maxXP: userData.maxXP, + difference: userData.difference, + multiplier: userData.multiplier, + onMessage + }); + return this.database.add(`${botGuild}.${user}.level`, level); + } + /** + * Subtracts the XP for specified user. + * @fires Leveling#subtractLevel + * @param {Number} level Amount of levels. + * @param {String | GuildMember | User} member Member or it's ID. + * @param {String | Guild} guild Guild or it's ID. + * @returns {Boolean} If subtracted successfully: true, else: false. + */ + subtract(level, member, guild) { + const isUser = member instanceof discord_js_1.GuildMember || member instanceof discord_js_1.User; + const isGuild = guild instanceof discord_js_1.Guild; + if (typeof member !== 'string' && !isUser) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.member + typeof member); + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + const user = isUser ? member.id : member.toString(); + const botGuild = isGuild ? guild.id : guild.toString(); + const userLevelData = this.database.fetch(`${botGuild}.${user}`); + this.emit('subtractLevel', { + userData: userLevelData.userData, + guildID: botGuild, + userID: user, + xp: userLevelData.xp, + totalXP: userLevelData.totalXP, + level: userLevelData.level - level, + maxXP: userLevelData.maxXP, + difference: userLevelData.difference, + multiplier: userLevelData.multiplier + }); + return this.database.subtract(`${botGuild}.${user}.level`, level); + } +} +module.exports = LevelManager; diff --git a/dist/src/managers/RanksManager.js b/dist/src/managers/RanksManager.js new file mode 100644 index 0000000..9448e96 --- /dev/null +++ b/dist/src/managers/RanksManager.js @@ -0,0 +1,112 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const discord_js_1 = require("discord.js"); +const LevelingError_1 = __importDefault(require("../classes/LevelingError")); +const Errors_1 = __importDefault(require("../structures/Errors")); +const DatabaseManager_1 = __importDefault(require("./DatabaseManager")); +/** + * Ranks manager methods class. + */ +class RanksManager { + /** + * Database Manager. + * @type {DatabaseManager} + * @private + */ + database; + /** + * Discord Bot Client. + * @type {Client} + * @private + */ + client; + /** + * Ranks manager methods class. + * @param {LevelingOptions} options Leveling options object. + */ + constructor(options, client) { + this.client = client; + this.database = new DatabaseManager_1.default(options); + } + /** + * Fetches the user's rank. + * @param {String | GuildMember | User} member Member or it's ID + * @param {String | Guild} guild Guild or it's ID + * @returns {RankData} User's rank object. + */ + get(member, guild) { + const isUser = member instanceof discord_js_1.GuildMember || member instanceof discord_js_1.User; + const isGuild = guild instanceof discord_js_1.Guild; + if (typeof member !== 'string' && !isUser) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.member + typeof member); + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + const user = isUser ? member.id : member.toString(); + const botGuild = isGuild ? guild.id : guild.toString(); + const rank = this.database.fetch(`${botGuild}.${user}`); + if (!rank) + return { + userData: null, + xp: null, + totalXP: null, + multiplier: null, + level: null, + maxXP: null, + difference: null, + }; + return rank; + } + /** + * Shows a level leaderboard for specified server. + * @param {String | Guild} guild Guild or it's ID + * @returns {LeaderboardData[]} Sorted leaderboard array. + */ + leaderboard(guild) { + const isGuild = guild instanceof discord_js_1.Guild; + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + const botGuild = isGuild ? guild.id : guild.toString(); + const serverData = this.database.fetch(`${botGuild}`); + let leaderboard = []; + if (!serverData) + return []; + let users = Object.keys(serverData); + let ranks = Object.values(serverData); + for (let i in users) + leaderboard.push({ + userID: users[i], + xp: ranks[i].xp, + totalXP: ranks[i].totalXP, + level: ranks[i].level, + maxXP: ranks[i].maxXP, + difference: ranks[i].difference, + multiplier: ranks[i].multiplier, + user: this.client.users.cache.get(users[i]), + userData: ranks[i].userData + }); + return leaderboard.sort((a, b) => b.totalXP - a.totalXP).filter(x => !isNaN(x.totalXP)); + } + /** + * Sets the multiplier for specified user. + * @param {Number} multiplier The multimplier number to set. + * @param {String | GuildMember | User} member Member or it's ID. + * @param {String | Guild} guild Guild or it's ID. + * @returns {Boolean} If set successfully: true; else: false + */ + setMultiplier(multiplier, member, guild) { + const isUser = member instanceof discord_js_1.GuildMember || member instanceof discord_js_1.User; + const isGuild = guild instanceof discord_js_1.Guild; + if (typeof member !== 'string' && !isUser) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.member + typeof member); + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + if (isNaN(multiplier)) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.multiplier + typeof multiplier); + const user = isUser ? member.id : member.toString(); + const botGuild = isGuild ? guild.id : guild.toString(); + return this.database.set(`${botGuild}.${user}.multiplier`, multiplier); + } +} +module.exports = RanksManager; diff --git a/dist/src/managers/SettingsManager.js b/dist/src/managers/SettingsManager.js new file mode 100644 index 0000000..06ae8a0 --- /dev/null +++ b/dist/src/managers/SettingsManager.js @@ -0,0 +1,232 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const discord_js_1 = require("discord.js"); +const LevelingError_1 = __importDefault(require("../classes/LevelingError")); +const Errors_1 = __importDefault(require("../structures/Errors")); +const DatabaseManager_1 = __importDefault(require("./DatabaseManager")); +const UtilsManager_1 = __importDefault(require("./UtilsManager")); +const SettingsArray = [ + 'xp', + 'maxXP', + 'multiplier', + 'status', + 'ignoredUsers', + 'lockedChannels', + 'ignoreBots', + 'filter' +]; +/** + * Settings manager methods class. + */ +class SettingsManager { + /** + * Leveling Options. + * @type {LevelingOptions} + * @private + */ + options; + /** + * Database Manager. + * @type {DatabaseManager} + * @private + */ + database; + /** + * Utils Manager. + * @type {UtilsManager} + * @private + */ + utils; + /** + * Ranks manager methods class. + * @param {LevelingOptions} options Leveling options object. + */ + constructor(options, client) { + this.options = options; + this.database = new DatabaseManager_1.default(options); + this.utils = new UtilsManager_1.default(options, client); + } + /** + * Gets the specified setting from the database. + * + * Note: If the server don't have any setting specified, + * the module will take the values from the + * options object or default options object. + * + * @param {SettingsTypes} key The setting to fetch. + * @param {String} guild Guild or it's ID. + * @returns {SettingsTypes} The setting from the database. + */ + get(key, guild) { + const isGuild = guild instanceof discord_js_1.Guild; + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + if (!SettingsArray.includes(key)) + throw new LevelingError_1.default(Errors_1.default.settingsManager.invalidKey + key); + const botGuild = isGuild ? guild.id : guild.toString(); + const data = this.all(botGuild); + const dbValue = data[key]; + return dbValue; + } + /** + * Changes the specified setting. + * + * Note: If the server don't have any setting specified, + * the module will take the values from the + * options object or default options object. + * + * @param {SettingsTypes} key The setting to change. + * @param {SettingsTypes} value The value to set. + * @param {String} guild Guild or it's ID. + * @returns {SettingsTypes} The server settings object. + */ + set(key, value, guild) { + const isGuild = guild instanceof discord_js_1.Guild; + if (value == undefined) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.value + typeof value); + if (typeof key !== 'string') + throw new LevelingError_1.default(Errors_1.default.databaseManager.invalidTypes.key + typeof key); + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + if (!SettingsArray.includes(key)) + throw new LevelingError_1.default(Errors_1.default.settingsManager.invalidKey + key); + const botGuild = isGuild ? guild.id : guild.toString(); + if (key == 'filter') + this.database.set(`${botGuild}.settings.${key}`, value.toString()); + else + this.database.set(`${botGuild}.settings.${key}`, value); + return this.all(botGuild); + } + /** + * Pushes the element in a setting's array. + * + * Note: If the server don't have any setting specified, + * the module will take the values from the + * options object or default options object. + * + * @param {SettingsArrays} key The setting to change. + * @param {SettingsArrays} value The value to set. + * @param {String} guild Guild or it's ID. + * @returns {SettingsTypes} The server settings object. + */ + push(key, value, guild) { + const isGuild = guild instanceof discord_js_1.Guild; + if (value == undefined) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.value + typeof value); + if (typeof key !== 'string') + throw new LevelingError_1.default(Errors_1.default.databaseManager.invalidTypes.key + typeof key); + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + if (!SettingsArray.includes(key)) + throw new LevelingError_1.default(Errors_1.default.settingsManager.invalidKey + key); + const botGuild = isGuild ? guild.id : guild.toString(); + const data = this.get(key, guild); + const type = this.utils.typeOf(data); + if (type !== 'Array') + throw new LevelingError_1.default(Errors_1.default.databaseManager.invalidTypes.target.array + type); + this.database.push(`${botGuild}.settings.${key}`, value); + return this.all(botGuild); + } + /** + * Removes the element from a setting's array. + * + * Note: If the server don't have any setting specified, + * the module will take the values from the + * options object or default options object. + * + * @param {SettingsArrays} key The setting to change. + * @param {SettingsArrays} value The value to remove. + * @param {String} guild Guild or it's ID. + * @returns {SettingsTypes} The server settings object. + */ + unpush(key, value, guild) { + const isGuild = guild instanceof discord_js_1.Guild; + if (typeof key !== 'string') + throw new LevelingError_1.default(Errors_1.default.databaseManager.invalidTypes.key + typeof key); + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + if (!SettingsArray.includes(key)) + throw new LevelingError_1.default(Errors_1.default.settingsManager.invalidKey + key); + const botGuild = isGuild ? guild.id : guild.toString(); + const data = this.get(key, guild); + const index = data.indexOf(value); + const type = this.utils.typeOf(data); + if (type !== 'Array') + throw new LevelingError_1.default(Errors_1.default.databaseManager.invalidTypes.target.array + type); + if (index == -1) + throw new LevelingError_1.default(Errors_1.default.settingsManager.valueNotFound(key, value)); + this.database.removeElement(`${botGuild}.settings.${key}`, index); + return this.all(botGuild); + } + /** + * Removes the specified setting. + * + * Note: If the server don't have any setting specified, + * the module will take the values from the + * options object or default options object. + * + * @param {SettingsTypes} key The setting to remove. + * @param {String} guild Guild or it's ID. + * @returns {SettingsTypes} The server settings object. + */ + remove(key, guild) { + const isGuild = guild instanceof discord_js_1.Guild; + if (typeof key !== 'string') + throw new LevelingError_1.default(Errors_1.default.databaseManager.invalidTypes.key + typeof key); + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + if (!SettingsArray.includes(key)) + throw new LevelingError_1.default(Errors_1.default.settingsManager.invalidKey + key); + const botGuild = isGuild ? guild.id : guild.toString(); + this.database.remove(`${botGuild}.settings.${key}`); + return this.all(guild); + } + /** + * Fetches the server's settings object. + * @param {String} guild Guild or it's ID. + * @returns {SettingsTypes} The server settings object. + */ + all(guild) { + const isGuild = guild instanceof discord_js_1.Guild; + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + const botGuild = isGuild ? guild.id : guild.toString(); + const settings = this.database.fetch(`${botGuild}.settings`); + return { + xp: settings?.xp == null ? null : settings?.xp, + maxXP: settings?.maxXP == null ? null : settings?.maxXP, + multiplier: settings?.multiplier == null ? null : settings?.multiplier, + status: settings?.status == null ? null : settings?.status, + ignoreBots: settings?.ignoreBots == null ? null : settings?.ignoreBots, + ignoredUsers: settings?.ignoredUsers == null ? null : settings?.ignoredUsers, + lockedChannels: settings?.lockedChannels == null ? null : settings?.lockedChannels, + filter: settings?.filter || null + }; + } + /** + * Resets all the settings to setting that are in options object. + * @param {String} guild Guild or it's ID. + * @returns {SettingsTypes} The server settings object. + */ + reset(guild) { + const isGuild = guild instanceof discord_js_1.Guild; + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + const botGuild = isGuild ? guild.id : guild.toString(); + const defaultSettings = { + xp: this.options.xp, + maxXP: this.options.maxXP, + multiplier: this.options.multiplier, + status: this.options.status, + ignoreBots: this.options.ignoreBots, + ignoredUsers: this.options.ignoredUsers, + lockedChannels: this.options.lockedChannels, + filter: this.options.filter + }; + this.database.set(`${botGuild}.settings`, defaultSettings); + return defaultSettings; + } +} +module.exports = SettingsManager; diff --git a/dist/src/managers/TotalXPManager.js b/dist/src/managers/TotalXPManager.js new file mode 100644 index 0000000..ceedfa9 --- /dev/null +++ b/dist/src/managers/TotalXPManager.js @@ -0,0 +1,143 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const discord_js_1 = require("discord.js"); +const Emitter_1 = __importDefault(require("../classes/Emitter")); +const LevelingError_1 = __importDefault(require("../classes/LevelingError")); +const DatabaseManager_1 = __importDefault(require("./DatabaseManager")); +const Errors_1 = __importDefault(require("../structures/Errors")); +/** + * Total XP manager methods class. + * @extends {Emitter} + */ +class TotalXPManager extends Emitter_1.default { + /** + * Database Manager. + * @type {DatabaseManager} + * @private + */ + database; + /** + * Total XP manager methods class. + * @param {LevelingOptions} options Leveling options object. + */ + constructor(options) { + super(); + this.database = new DatabaseManager_1.default(options); + } + /** + * Gets the XP for specified user. + * @param {String | GuildMember | User} member Member or it's ID. + * @param {String | Guild} guild Guild or it's ID. + * @returns {Number} Amount of total XP. + */ + get(member, guild) { + const isUser = member instanceof discord_js_1.GuildMember || member instanceof discord_js_1.User; + const isGuild = guild instanceof discord_js_1.Guild; + if (typeof member !== 'string' && !isUser) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.member + typeof member); + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + const user = isUser ? member.id : member.toString(); + const botGuild = isGuild ? guild.id : guild.toString(); + const totalXP = this.database.fetch(`${botGuild}.${user}.totalXP`); + return totalXP; + } + /** + * Sets the XP for specified user. + * @fires Leveling#setTotalXP + * @param {Number} totalXP Amount of total XP. + * @param {String | GuildMember | User} member Member or it's ID. + * @param {String | Guild} guild Guild or it's ID. + * @returns {Boolean} If set successfully: true, else: false. + */ + set(totalXP, member, guild) { + const isUser = member instanceof discord_js_1.GuildMember || member instanceof discord_js_1.User; + const isGuild = guild instanceof discord_js_1.Guild; + if (typeof member !== 'string' && !isUser) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.member + typeof member); + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + const user = isUser ? member.id : member.toString(); + const botGuild = isGuild ? guild.id : guild.toString(); + const userLevelData = this.database.fetch(`${botGuild}.${user}`); + this.emit('setTotalXP', { + userData: userLevelData.userData, + guildID: botGuild, + userID: user, + xp: userLevelData.xp, + level: userLevelData.level, + totalXP, + maxXP: userLevelData.maxXP, + difference: userLevelData.difference, + multiplier: userLevelData.multiplier + }); + return this.database.set(`${botGuild}.${user}.totalXP`, totalXP); + } + /** + * Adds the XP for specified user. + * @fires Leveling#addTotalXP + * @param {Number} totalXP Amount of total XP. + * @param {String | GuildMember | User} member Member or it's ID. + * @param {String | Guild} guild Guild or it's ID. + * @param {Boolean} onMessage The value will be true if the method was called on 'messageCreate' bot event. + * @returns {Boolean} If added successfully: true, else: false. + */ + add(totalXP, member, guild, onMessage = false) { + const isUser = member instanceof discord_js_1.GuildMember || member instanceof discord_js_1.User; + const isGuild = guild instanceof discord_js_1.Guild; + if (typeof member !== 'string' && !isUser) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.member + typeof member); + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + const user = isUser ? member.id : member.toString(); + const botGuild = isGuild ? guild.id : guild.toString(); + const userData = this.database.fetch(`${botGuild}.${user}`); + this.emit('addTotalXP', { + guildID: botGuild, + userID: user, + xp: userData.xp, + level: userData.level, + gainedXP: totalXP, + totalXP: userData.totalXP + totalXP, + maxXP: userData.maxXP, + difference: userData.difference, + multiplier: userData.multiplier, + onMessage + }); + return this.database.add(`${botGuild}.${user}.totalXP`, totalXP); + } + /** + * Subtracts the XP for specified user. + * @fires Leveling#subtractTotalXP + * @param {Number} totalXP Amount of total XP. + * @param {String | GuildMember | User} member Member or it's ID. + * @param {String | Guild} guild Guild or it's ID. + * @returns {Boolean} If subtracted successfully: true, else: false. + */ + subtract(totalXP, member, guild) { + const isUser = member instanceof discord_js_1.GuildMember || member instanceof discord_js_1.User; + const isGuild = guild instanceof discord_js_1.Guild; + if (typeof member !== 'string' && !isUser) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.member + typeof member); + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + const user = isUser ? member.id : member.toString(); + const botGuild = isGuild ? guild.id : guild.toString(); + const userLevelData = this.database.fetch(`${botGuild}.${user}`); + this.emit('subtractTotalXP', { + userData: userLevelData.userData, + guildID: botGuild, + userID: user, + xp: userLevelData.xp, + level: userLevelData.level, + totalXP: userLevelData.totalXP - totalXP, + maxXP: userLevelData.maxXP, + difference: userLevelData.difference, + multiplier: userLevelData.multiplier + }); + return this.database.subtract(`${botGuild}.${user}.totalXP`, totalXP); + } +} +module.exports = TotalXPManager; diff --git a/dist/src/managers/UtilsManager.js b/dist/src/managers/UtilsManager.js new file mode 100644 index 0000000..d47c649 --- /dev/null +++ b/dist/src/managers/UtilsManager.js @@ -0,0 +1,329 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const node_fetch_1 = __importDefault(require("node-fetch")); +const fs_1 = require("fs"); +const DefaultOptions_1 = __importDefault(require("../structures/DefaultOptions")); +const FetchManager_1 = __importDefault(require("./FetchManager")); +const DatabaseManager_1 = __importDefault(require("./DatabaseManager")); +const DefaultObject_1 = __importDefault(require("../structures/DefaultObject")); +/** + * Utils manager methods class. + */ +class UtilsManager { + /** + * Fetch Manager. + * @type {FetchManager} + * @private + */ + fetcher; + /** + * Database Manager. + * @type {DatabaseManager} + * @private + */ + database; + /** + * Discord Bot Client. + * @type {Client} + * @private + */ + client; + /** + * Leveling Options. + * @type {LevelingOptions} + * @private + */ + options; + /** + * Utils manager methods class. + * @param {LevelingOptions} options Leveling options object. + */ + constructor(options, client) { + this.options = options; + this.client = client; + this.database = new DatabaseManager_1.default(options); + this.fetcher = new FetchManager_1.default(options); + } + /** + * Checks for if the module is up to date. + * @returns {Promise} This method will show is the module updated, latest version and installed version. + */ + async checkUpdates() { + const version = require('../../package.json').version; + const packageData = await (0, node_fetch_1.default)('https://registry.npmjs.com/discord-leveling-super') + .then((text) => text.json()); + if (version == packageData['dist-tags'].latest) + return { + updated: true, + installedVersion: version, + packageVersion: packageData['dist-tags'].latest + }; + return { + updated: false, + installedVersion: version, + packageVersion: packageData['dist-tags'].latest + }; + } + /** + * Fetches the entire database. + * @returns {Object} Database contents + */ + all() { + return this.fetcher.fetchAll(); + } + /** + * Writes the data to file. + * @param {String} path File path to write. + * @param {any} data Any data to write + * @returns {Boolean} If successfully written: true; else: false. + */ + write(path, data) { + if (!path) + return false; + if (!data) + return false; + const fileData = (0, fs_1.readFileSync)(path).toString(); + if (fileData == data) + return false; + (0, fs_1.writeFileSync)(this.options.storagePath || './leveling.json', JSON.stringify(data, null, '\t')); + return true; + } + /** + * Clears the storage file. + * @returns {Boolean} If cleared successfully: true; else: false + */ + clearStorage() { + const data = this.all(); + const stringData = String(data); + if (stringData == '{}') + return false; + this.write(this.options.storagePath || './leveling.json', '{}'); + return true; + } + /** + * Fully removes the guild from database. + * @param {String} guildID Guild ID + * @returns {Boolean} If cleared successfully: true; else: false + */ + removeGuild(guildID) { + const data = this.fetcher.fetchAll(); + const guild = data[guildID]; + if (!guildID) + return false; + if (!guild) + return false; + this.database.remove(guildID); + return true; + } + /** + * Removes the user from database. + * @param {String} memberID Member ID + * @param {String} guildID Guild ID + * @returns {Boolean} If cleared successfully: true; else: false + */ + removeUser(memberID, guildID) { + const data = this.fetcher.fetchAll(); + const guild = data[guildID]; + const user = guild?.[memberID]; + if (!guildID) + return false; + if (!guild) + return false; + if (!user) + return false; + this.database.remove(`${guildID}.${memberID}`); + return true; + } + /** + * Sets the default user object for the specified member. + * @param {String} memberID Member ID. + * @param {String} guildID Guild ID. + * @param {RankData} object Custom rank object to set. + * @returns {Boolean} If reset is successful: true; else: false. + */ + reset(memberID, guildID, object) { + const dataObject = DefaultObject_1.default; + if (!guildID) + return false; + if (!memberID) + return false; + if (object) + return this.database.set(`${guildID}.${memberID}`, object); + const user = this.client.users.cache.get(memberID); + if (!user) + return false; + dataObject.userData = { + id: memberID, + username: user.username, + tag: user.tag, + discriminator: user.discriminator + }; + dataObject.xp = 0; + dataObject.totalXP = 0; + return this.database.set(`${guildID}.${memberID}`, dataObject); + } + /** + * Returns a rank object with specified values. + * @param {LevelData} options Rank object to use. + * @returns {LevelData} Rank object with specified values. + */ + getRankObject(options) { + const isDefined = (val) => val !== undefined ? val : false; + if (!options) + return { + userData: null, + guildID: null, + userID: null, + xp: null, + totalXP: null, + level: null, + maxXP: null, + difference: null, + multiplier: null + }; + return { + userData: isDefined(options.userData) || null, + guildID: isDefined(options.guildID) || null, + userID: isDefined(options.userID) || null, + xp: isDefined(options.xp) || null, + totalXP: isDefined(options.totalXP) || null, + level: isDefined(options.level) || null, + maxXP: isDefined(options.maxXP) || null, + difference: isDefined(options.difference) || null, + multiplier: isDefined(options.multiplier) || null + }; + } + /** + * Returns the type or instance of specified item. + * @param {any} item The item to get the type of. + * @returns {String} Type or instance of the item. + */ + typeOf(item) { + return item === null ? + 'null' : + item === undefined ? + 'undefined' : + item.constructor.name && item.name + ? item.name : + item.constructor.name; + } + /** + * Checks for is the item object and returns it. + * @param {any} item The item to check. + * @returns {Boolean} Is the item object or not. + */ + isObject(item) { + return !Array.isArray(item) + && typeof item == 'object' + && item !== null; + } + /** + * Checks the Leveling options object, fixes the problems in it and returns the fixed options object. + * @param {CheckerOptions} options Option checker options. + * @param {LevelingOptions} levelingOptions Leveling options object to check. + * @returns {LevelingOptions} Fixed Leveling options object. + */ + checkOptions(options = {}, levelingOptions) { + const unset = (obj, key) => { + const keys = key.split('.'); + let tmp = obj; + for (let i = 0; i < keys.length; i++) { + if ((keys.length - 1) == i) { + delete tmp[keys[i]]; + } + else if (!this.isObject(tmp[keys[i]])) { + tmp[keys[i]] = {}; + } + tmp = tmp[keys[i]]; + } + }; + let problems = []; + let output = {}; + const keys = Object.keys(DefaultOptions_1.default); + const optionKeys = Object.keys(levelingOptions || {}); + if (typeof levelingOptions !== 'object' && !Array.isArray(levelingOptions)) { + problems.push('options is not an object. Received type: ' + typeof levelingOptions); + output = DefaultOptions_1.default; + } + else { + if (!optionKeys.length) { + problems.push('options object is empty.'); + return DefaultOptions_1.default; + } + for (let i of keys) { + if (levelingOptions[i] == undefined) { + output[i] = DefaultOptions_1.default[i]; + if (!options.ignoreUnspecifiedOptions) + problems.push(`options.${i} is not specified.`); + } + else { + output[i] = levelingOptions[i]; + } + for (let y of Object.keys(DefaultOptions_1.default[i])) { + if (levelingOptions[i]?.[y] == undefined || output[i]?.[y] == undefined) { + try { + output[i][y] = DefaultOptions_1.default[i][y]; + } + catch (_) { } + if (!options.ignoreUnspecifiedOptions && isNaN(Number(y))) + problems.push(`options.${i}.${y} is not specified.`); + } + else { } + } + if (typeof output[i] !== typeof DefaultOptions_1.default[i]) { + if (!options.ignoreInvalidTypes) { + if (i == 'xp') { + if (typeof output[i] !== 'number' && !Array.isArray(output[i])) { + problems.push(`options.${i} is not a ${i == 'xp' ? 'number or array' : typeof DefaultOptions_1.default[i]}. Received type: ${typeof output[i]}.`); + output[i] = DefaultOptions_1.default[i]; + } + } + else { + problems.push(`options.${i} is not a ${typeof DefaultOptions_1.default[i]}. Received type: ${typeof output[i]}.`); + output[i] = DefaultOptions_1.default[i]; + } + } + } + else { } + for (let y of Object.keys(DefaultOptions_1.default[i])) { + if (typeof output[i]?.[y] !== typeof DefaultOptions_1.default[i][y]) { + if (!options.ignoreInvalidTypes) + problems.push(`options.${i}.${y} is not a ${typeof DefaultOptions_1.default[i][y]}. Received type: ${typeof output[i][y]}.`); + output[i][y] = DefaultOptions_1.default[i][y]; + } + else { } + } + } + for (let i of optionKeys) { + const defaultIndex = keys.indexOf(i); + const objectKeys = Object.keys(levelingOptions?.[i]); + for (let y of objectKeys) { + const allKeys = Object.keys(DefaultOptions_1.default[i] || '0'); + const index = allKeys.indexOf(y); + if (!allKeys[index] && isNaN(Number(y))) { + problems.push(`options.${i}.${y} is an invalid option.`); + unset(output, `${i}.${y}`); + } + } + if (!keys[defaultIndex]) { + unset(output, i); + problems.push(`options.${i} is an invalid option.`); + } + } + } + if (options.sendLog) { + if (options.showProblems) + console.log(`Checked the options: ${problems.length ? + `${problems.length} problems found:\n\n${problems.join('\n')}` : '0 problems found.'}`); + if (options.sendSuccessLog && !options.showProblems) + console.log(`Checked the options: ${problems.length} ${problems.length == 1 ? 'problem' : 'problems'} found.`); + } + if (output == DefaultOptions_1.default) + return levelingOptions; + else + return output; + } +} +module.exports = UtilsManager; diff --git a/dist/src/managers/XPManager.js b/dist/src/managers/XPManager.js new file mode 100644 index 0000000..e019ac2 --- /dev/null +++ b/dist/src/managers/XPManager.js @@ -0,0 +1,145 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const discord_js_1 = require("discord.js"); +const Emitter_1 = __importDefault(require("../classes/Emitter")); +const LevelingError_1 = __importDefault(require("../classes/LevelingError")); +const DatabaseManager_1 = __importDefault(require("./DatabaseManager")); +const Errors_1 = __importDefault(require("../structures/Errors")); +/** + * XP manager methods class. + * @extends {Emitter} + */ +class XPManager extends Emitter_1.default { + /** + * Database Manager. + * @type {DatabaseManager} + * @private + */ + database; + /** + * XP manager methods class. + * @param {LevelingOptions} options Leveling options object. + */ + constructor(options) { + super(); + this.database = new DatabaseManager_1.default(options); + } + /** + * Gets the XP for specified user. + * @param {String | GuildMember | User} member Member or it's ID. + * @param {String | Guild} guild Guild or it's ID. + * @returns {Number} Amount of XP. + */ + get(member, guild) { + const isUser = member instanceof discord_js_1.GuildMember || member instanceof discord_js_1.User; + const isGuild = guild instanceof discord_js_1.Guild; + if (typeof member !== 'string' && !isUser) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.member + typeof member); + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + const user = isUser ? member.id : member.toString(); + const botGuild = isGuild ? guild.id : guild.toString(); + const xp = this.database.fetch(`${botGuild}.${user}.xp`); + return xp; + } + /** + * Sets the XP for specified user. + * @fires Leveling#setXP + * @param {Number} xp Amount of XP. + * @param {String | GuildMember | User} member Member or it's ID. + * @param {String | Guild} guild Guild or it's ID. + * @param {Boolean} onMessage The value will be true if the method was called on 'messageCreate' bot event. + * @returns {Boolean} If set successfully: true, else: false. + */ + set(xp, member, guild, onMessage) { + const isUser = member instanceof discord_js_1.GuildMember || member instanceof discord_js_1.User; + const isGuild = guild instanceof discord_js_1.Guild; + if (typeof member !== 'string' && !isUser) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.member + typeof member); + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + const user = isUser ? member.id : member.toString(); + const botGuild = isGuild ? guild.id : guild.toString(); + const userLevelData = this.database.fetch(`${botGuild}.${user}`); + if (!onMessage) + this.emit('setXP', { + userData: userLevelData.userData, + guildID: botGuild, + userID: user, + xp, + totalXP: userLevelData.totalXP, + level: userLevelData.level, + maxXP: userLevelData.maxXP, + difference: userLevelData.difference, + multiplier: userLevelData.multiplier + }); + return this.database.set(`${botGuild}.${user}.xp`, xp); + } + /** + * Adds the XP for specified user. + * @fires Leveling#addXP + * @param {Number} xp Amount of XP. + * @param {String | GuildMember | User} member Member or it's ID. + * @param {String | Guild} guild Guild or it's ID. + * @param {Boolean} onMessage The value will be true if the method was called on 'messageCreate' bot event. + * @returns {Boolean} If added successfully: true, else: false. + */ + add(xp, member, guild, onMessage = false) { + const isUser = member instanceof discord_js_1.GuildMember || member instanceof discord_js_1.User; + const isGuild = guild instanceof discord_js_1.Guild; + if (typeof member !== 'string' && !isUser) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.member + typeof member); + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + const user = isUser ? member.id : member.toString(); + const botGuild = isGuild ? guild.id : guild.toString(); + const userData = this.database.fetch(`${botGuild}.${user}`); + this.emit('addXP', { + guildID: botGuild, + userID: user, + xp: userData.xp + xp, + totalXP: userData.totalXP, + level: userData.level, + gainedXP: xp, + maxXP: userData.maxXP, + difference: userData.difference, + multiplier: userData.multiplier, + onMessage + }); + return this.database.add(`${botGuild}.${user}.xp`, xp); + } + /** + * Subtracts the XP for specified user. + * @fires Leveling#subtractXP + * @param {Number} xp Amount of XP. + * @param {String | GuildMember | User} member Member or it's ID. + * @param {String | Guild} guild Guild or it's ID. + * @returns {Boolean} If subtracted successfully: true, else: false. + */ + subtract(xp, member, guild) { + const isUser = member instanceof discord_js_1.GuildMember || member instanceof discord_js_1.User; + const isGuild = guild instanceof discord_js_1.Guild; + if (typeof member !== 'string' && !isUser) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.member + typeof member); + if (typeof guild !== 'string' && !isGuild) + throw new LevelingError_1.default(Errors_1.default.invalidTypes.guild + typeof guild); + const user = isUser ? member.id : member.toString(); + const botGuild = isGuild ? guild.id : guild.toString(); + const userLevelData = this.database.fetch(`${botGuild}.${user}`); + this.emit('subtractXP', { + userData: userLevelData.userData, + guildID: botGuild, + userID: user, + xp: userLevelData.xp - xp, + totalXP: userLevelData.totalXP, + level: userLevelData.level, + maxXP: userLevelData.maxXP, + difference: userLevelData.difference, + multiplier: userLevelData.multiplier + }); + return this.database.subtract(`${botGuild}.${user}.xp`, xp); + } +} +module.exports = XPManager; diff --git a/dist/src/structures/DefaultObject.js b/dist/src/structures/DefaultObject.js new file mode 100644 index 0000000..e86db59 --- /dev/null +++ b/dist/src/structures/DefaultObject.js @@ -0,0 +1,16 @@ +"use strict"; +const DefaultObject = { + userData: { + id: '', + username: '', + tag: '', + discriminator: '' + }, + xp: 0, + totalXP: 0, + multiplier: 1, + level: 1, + maxXP: 300, + difference: 300, +}; +module.exports = DefaultObject; diff --git a/dist/src/structures/DefaultOptions.js b/dist/src/structures/DefaultOptions.js new file mode 100644 index 0000000..bb4102e --- /dev/null +++ b/dist/src/structures/DefaultOptions.js @@ -0,0 +1,32 @@ +"use strict"; +const DefaultOptions = { + storagePath: './leveling.json', + checkStorage: true, + xp: 5, + maxXP: 300, + multiplier: 1, + status: true, + ignoreBots: false, + lockedChannels: [], + ignoredUsers: [], + ignoredGuilds: [], + filter: () => true, + updater: { + checkUpdates: true, + upToDateMessage: true + }, + errorHandler: { + handleErrors: true, + attempts: 5, + time: 3000 + }, + optionsChecker: { + ignoreInvalidTypes: false, + ignoreUnspecifiedOptions: false, + ignoreInvalidOptions: false, + showProblems: false, + sendLog: false, + sendSuccessLog: false + } +}; +module.exports = DefaultOptions; diff --git a/dist/src/structures/Errors.js b/dist/src/structures/Errors.js new file mode 100644 index 0000000..041f37b --- /dev/null +++ b/dist/src/structures/Errors.js @@ -0,0 +1,85 @@ +"use strict"; +const SettingsArray = [ + 'xp', + 'maxXP', + 'multiplier', + 'status', + 'ignoredUsers', + 'lockedChannels', + 'ignoreBots', + 'filter' +]; +const LevelingErrors = { + noClient: 'Specify the bot client.', + invalidClient: 'Specified client is invalid.', + notReady: 'The module is not ready to work.', + noDependencies: 'Cannot find dependencies in your \'package.json\' file.', + noDiscordJS: 'Discord.js not found!', + oldNodeVersion: 'This module is supporting only Node.js v16.6.0 or newer. Installed version is ', + oldDJSVersion: 'This module is supporting only Discord.js v13.1.0 or newer. Installed version is ', + invalidStorage: 'Storage file is not valid.', + wrongStorageData: 'Storage file contains wrong data.', + invalidTypes: { + level: 'level must be a number or string. Received type: ', + xp: 'xp must be a number or string. Received type: ', + member: 'member must be a string or an instance of GuildMember or User. Received type: ', + guild: 'guild must be a string or an instance of Guild. Received type: ', + multiplier: 'multiplier must be a string. Received type: ', + value: 'value must be specified. Received: ' + }, + settingsManager: { + invalidKey: `You have specified the incorrect settings key. It must be one of the following values:\n${SettingsArray.map(x => `'${x}'`).join(', ')}.\nReceived: `, + valueNotFound(setting, value) { + return `Cannot find the value "${value}", in a setting "${setting}".`; + } + }, + databaseManager: { + invalidTypes: { + key: 'Key must be a string. Received type: ', + target: { + number: 'Target is not a number. Received type: ', + array: 'Target is not an array. Received type: ' + }, + value: { + number: 'Value is not a number. Received type: ', + array: 'Value is not an array. Received type: ' + } + } + }, + sendMessage: { + invalidTypes: { + msg: 'The message must be a string or an object with message options or instance of EmbedBuilder or AttachmentBuilder. Received type: ', + channel: 'The channel must be a string. Received type: ', + }, + channelNotFound: 'Cannot find the specified channel.', + invalidChannelType: 'Cannot send a message in a voice channel or category.' + }, + lockedChannels: { + invalidTypes: 'The elements of array of locked channels must be a string. Received: ', + invalidChannels(channelsArray) { + if (channelsArray.length == 1) + return `Cannot find the specified channel: ${channelsArray[0]}`; + return `Cannot find the ${channelsArray.length} specified channels: ${channelsArray.join(', ')}`; + } + }, + ignoredUsers: { + invalidTypes: 'The elements of array of ignored users must be a string. Received: ', + invalidUsers(usersArray) { + if (usersArray.length == 1) + return `Cannot find the specified user: ${usersArray[0]}`; + return `Cannot find the ${usersArray.length} specified users: ${usersArray.join(', ')}`; + } + }, + ignoredGuilds: { + invalidTypes: 'The elements of array of ignored guilds must be a string. Received: ', + invalidGuilds(guildsArray) { + if (guildsArray.length == 1) + return `Cannot find the specified guild: ${guildsArray[0]}`; + return `Cannot find the ${guildsArray.length} specified guilds: ${guildsArray.join(', ')}`; + } + }, + reservedName(name) { + return `'${name}' is a reserved storage file name. You cannot use it.`; + } +}; +module.exports = LevelingErrors; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..2ec0da3 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,625 @@ +{ + "name": "discord-leveling-super", + "version": "1.0.5", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "discord-leveling-super", + "version": "1.0.5", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "discord.js": "^14.2.0", + "node-fetch": "^2.6.7", + "typescript": "^4.7.4" + }, + "engines": { + "node": ">=16.6.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@discordjs/builders": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.1.0.tgz", + "integrity": "sha512-EO8TSltiIc9Z1wE854wAFvv5AccqEtvjFmao9PPoxQhRaJ0hEb7FwWRTCA1jGg4ZWI3hcp4m+RET5ufZQz3rOg==", + "dependencies": { + "@sapphire/shapeshift": "^3.5.1", + "discord-api-types": "^0.36.3", + "fast-deep-equal": "^3.1.3", + "ts-mixer": "^6.0.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/@discordjs/collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.0.1.tgz", + "integrity": "sha512-5V/wswzR3r2RVYXLxxg4TvrAnBhVCNgHTXhC+OUtLoriJ072rPMHo+Iw1SS1vrCckp8Es40XM411+WkNRPaXFw==", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/@discordjs/rest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-1.0.1.tgz", + "integrity": "sha512-w08CTKVzzYYvKxEjXKOs9AdS7KQ1J502TrPfF8eCZ2lF6AfKuMP/32YgDakiwIyYTDjEQS/v0nKLSFcncHRMtg==", + "dependencies": { + "@discordjs/collection": "^1.0.1", + "@sapphire/async-queue": "^1.3.2", + "@sapphire/snowflake": "^3.2.2", + "discord-api-types": "^0.36.3", + "file-type": "^17.1.4", + "tslib": "^2.4.0", + "undici": "^5.8.0" + }, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/@sapphire/async-queue": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz", + "integrity": "sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@sapphire/shapeshift": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.5.1.tgz", + "integrity": "sha512-7JFsW5IglyOIUQI1eE0g6h06D/Far6HqpcowRScgCiLSqTf3hhkPWCWotVTtVycnDCMYIwPeaw6IEPBomKC8pA==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "lodash.uniqwith": "^4.5.0" + }, + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@sapphire/snowflake": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.2.2.tgz", + "integrity": "sha512-ula2O0kpSZtX9rKXNeQMrHwNd7E4jPDJYUXmEGTFdMRfyfMw+FPyh04oKMjAiDuOi64bYgVkOV3MjK+loImFhQ==", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" + }, + "node_modules/@types/node": { + "version": "18.7.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.6.tgz", + "integrity": "sha512-EdxgKRXgYsNITy5mjjXjVE/CS8YENSdhiagGrLqjG0pvA2owgJ6i4l7wy/PFZGC0B1/H20lWKN7ONVDNYDZm7A==" + }, + "node_modules/@types/ws": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/discord-api-types": { + "version": "0.36.3", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.36.3.tgz", + "integrity": "sha512-bz/NDyG0KBo/tY14vSkrwQ/n3HKPf87a0WFW/1M9+tXYK+vp5Z5EksawfCWo2zkAc6o7CClc0eff1Pjrqznlwg==" + }, + "node_modules/discord.js": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.2.0.tgz", + "integrity": "sha512-kIGhEeOB1d9k7whL9HCCuRuzK2GL7i/hTesYINOZ2szWm4TOsBVwRU+i9O/zDb2M+Gvff4SJ4EpAtCVV0okgVw==", + "dependencies": { + "@discordjs/builders": "^1.1.0", + "@discordjs/collection": "^1.0.1", + "@discordjs/rest": "^1.0.1", + "@sapphire/snowflake": "^3.2.2", + "@types/ws": "^8.5.3", + "discord-api-types": "^0.36.3", + "fast-deep-equal": "^3.1.3", + "lodash.snakecase": "^4.1.1", + "tslib": "^2.4.0", + "undici": "^5.8.2", + "ws": "^8.8.1" + }, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/file-type": { + "version": "17.1.6", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-17.1.6.tgz", + "integrity": "sha512-hlDw5Ev+9e883s0pwUsuuYNu4tD7GgpUnOvykjv1Gya0ZIjuKumthDRua90VUn6/nlRKAjcxLUnHNTIUWwWIiw==", + "dependencies": { + "readable-web-to-node-stream": "^3.0.2", + "strtok3": "^7.0.0-alpha.9", + "token-types": "^5.0.0-alpha.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" + }, + "node_modules/lodash.uniqwith": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniqwith/-/lodash.uniqwith-4.5.0.tgz", + "integrity": "sha512-7lYL8bLopMoy4CTICbxygAUq6CdRJ36vFc80DucPueUee+d5NBRxz3FdT9Pes/HEx5mPoT9jwnsEJWz1N7uq7Q==" + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/peek-readable": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz", + "integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readable-web-to-node-stream": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", + "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", + "dependencies": { + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/strtok3": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz", + "integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "peek-readable": "^5.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/token-types": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz", + "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/ts-mixer": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.1.tgz", + "integrity": "sha512-hvE+ZYXuINrx6Ei6D6hz+PTim0Uf++dYbK9FFifLNwQj+RwKquhQpn868yZsCtJYiclZF1u8l6WZxxKi+vv7Rg==" + }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "node_modules/typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/undici": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.8.2.tgz", + "integrity": "sha512-3KLq3pXMS0Y4IELV045fTxqz04Nk9Ms7yfBBHum3yxsTR4XNn+ZCaUbf/mWitgYDAhsplQ0B1G4S5D345lMO3A==", + "engines": { + "node": ">=12.18" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/ws": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz", + "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + }, + "dependencies": { + "@discordjs/builders": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.1.0.tgz", + "integrity": "sha512-EO8TSltiIc9Z1wE854wAFvv5AccqEtvjFmao9PPoxQhRaJ0hEb7FwWRTCA1jGg4ZWI3hcp4m+RET5ufZQz3rOg==", + "requires": { + "@sapphire/shapeshift": "^3.5.1", + "discord-api-types": "^0.36.3", + "fast-deep-equal": "^3.1.3", + "ts-mixer": "^6.0.1", + "tslib": "^2.4.0" + } + }, + "@discordjs/collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.0.1.tgz", + "integrity": "sha512-5V/wswzR3r2RVYXLxxg4TvrAnBhVCNgHTXhC+OUtLoriJ072rPMHo+Iw1SS1vrCckp8Es40XM411+WkNRPaXFw==" + }, + "@discordjs/rest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-1.0.1.tgz", + "integrity": "sha512-w08CTKVzzYYvKxEjXKOs9AdS7KQ1J502TrPfF8eCZ2lF6AfKuMP/32YgDakiwIyYTDjEQS/v0nKLSFcncHRMtg==", + "requires": { + "@discordjs/collection": "^1.0.1", + "@sapphire/async-queue": "^1.3.2", + "@sapphire/snowflake": "^3.2.2", + "discord-api-types": "^0.36.3", + "file-type": "^17.1.4", + "tslib": "^2.4.0", + "undici": "^5.8.0" + } + }, + "@sapphire/async-queue": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz", + "integrity": "sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==" + }, + "@sapphire/shapeshift": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.5.1.tgz", + "integrity": "sha512-7JFsW5IglyOIUQI1eE0g6h06D/Far6HqpcowRScgCiLSqTf3hhkPWCWotVTtVycnDCMYIwPeaw6IEPBomKC8pA==", + "requires": { + "fast-deep-equal": "^3.1.3", + "lodash.uniqwith": "^4.5.0" + } + }, + "@sapphire/snowflake": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.2.2.tgz", + "integrity": "sha512-ula2O0kpSZtX9rKXNeQMrHwNd7E4jPDJYUXmEGTFdMRfyfMw+FPyh04oKMjAiDuOi64bYgVkOV3MjK+loImFhQ==" + }, + "@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" + }, + "@types/node": { + "version": "18.7.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.6.tgz", + "integrity": "sha512-EdxgKRXgYsNITy5mjjXjVE/CS8YENSdhiagGrLqjG0pvA2owgJ6i4l7wy/PFZGC0B1/H20lWKN7ONVDNYDZm7A==" + }, + "@types/ws": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", + "requires": { + "@types/node": "*" + } + }, + "discord-api-types": { + "version": "0.36.3", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.36.3.tgz", + "integrity": "sha512-bz/NDyG0KBo/tY14vSkrwQ/n3HKPf87a0WFW/1M9+tXYK+vp5Z5EksawfCWo2zkAc6o7CClc0eff1Pjrqznlwg==" + }, + "discord.js": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.2.0.tgz", + "integrity": "sha512-kIGhEeOB1d9k7whL9HCCuRuzK2GL7i/hTesYINOZ2szWm4TOsBVwRU+i9O/zDb2M+Gvff4SJ4EpAtCVV0okgVw==", + "requires": { + "@discordjs/builders": "^1.1.0", + "@discordjs/collection": "^1.0.1", + "@discordjs/rest": "^1.0.1", + "@sapphire/snowflake": "^3.2.2", + "@types/ws": "^8.5.3", + "discord-api-types": "^0.36.3", + "fast-deep-equal": "^3.1.3", + "lodash.snakecase": "^4.1.1", + "tslib": "^2.4.0", + "undici": "^5.8.2", + "ws": "^8.8.1" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "file-type": { + "version": "17.1.6", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-17.1.6.tgz", + "integrity": "sha512-hlDw5Ev+9e883s0pwUsuuYNu4tD7GgpUnOvykjv1Gya0ZIjuKumthDRua90VUn6/nlRKAjcxLUnHNTIUWwWIiw==", + "requires": { + "readable-web-to-node-stream": "^3.0.2", + "strtok3": "^7.0.0-alpha.9", + "token-types": "^5.0.0-alpha.2" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" + }, + "lodash.uniqwith": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniqwith/-/lodash.uniqwith-4.5.0.tgz", + "integrity": "sha512-7lYL8bLopMoy4CTICbxygAUq6CdRJ36vFc80DucPueUee+d5NBRxz3FdT9Pes/HEx5mPoT9jwnsEJWz1N7uq7Q==" + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "peek-readable": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz", + "integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==" + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readable-web-to-node-stream": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", + "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", + "requires": { + "readable-stream": "^3.6.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "strtok3": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz", + "integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==", + "requires": { + "@tokenizer/token": "^0.3.0", + "peek-readable": "^5.0.0" + } + }, + "token-types": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz", + "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==", + "requires": { + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "ts-mixer": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.1.tgz", + "integrity": "sha512-hvE+ZYXuINrx6Ei6D6hz+PTim0Uf++dYbK9FFifLNwQj+RwKquhQpn868yZsCtJYiclZF1u8l6WZxxKi+vv7Rg==" + }, + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==" + }, + "undici": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.8.2.tgz", + "integrity": "sha512-3KLq3pXMS0Y4IELV045fTxqz04Nk9Ms7yfBBHum3yxsTR4XNn+ZCaUbf/mWitgYDAhsplQ0B1G4S5D345lMO3A==" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "ws": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz", + "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==", + "requires": {} + } + } +} diff --git a/package.json b/package.json index d4cbfbb..d4660cc 100644 --- a/package.json +++ b/package.json @@ -1,46 +1,50 @@ { - "name": "discord-leveling-super", - "version": "1.0.4", - "description": "Easy and customizable leveling framework for your Discord bot.", - "types": "./typings/Leveling.d.ts", - "main": "index.js", - "scripts": { - "test": "echo \"ok\" && exit 0", - "postinstall": "node install.js", - "buildfiles": "tsc", - "begin": "npm i typescript" - }, - "engines": { - "node": ">=16.6.0", - "npm": ">=7.0.0" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/shadowplay1/discord-leveling-super.git" - }, - "keywords": [ - "discord", - "bot", - "discord.js", - "leveling", - "discord-leveling", - "discord-leveling-super", - "ranks", - "ranking", - "discord-ranks", - "discord-js", - "super", - "rank", - "shadowplay" - ], - "author": "shadowplay", - "license": "MIT", - "bugs": { - "url": "https://github.com/shadowplay1/discord-leveling-super/issues" - }, - "homepage": "https://github.com/shadowplay1/discord-leveling-super#readme", - "dependencies": { - "discord.js": "^13.2.0", - "node-fetch": "^2.6.1" - } -} \ No newline at end of file + "name": "discord-leveling-super", + "version": "1.0.5", + "description": "Easy and customizable leveling framework for your Discord bot.", + "types": "./typings/Leveling.d.ts", + "main": "index.js", + "scripts": { + "test": "echo \"ok\" && exit 0", + "start": "ts-node bot.ts", + "buildfiles": "tsc", + "build": "node build.js", + "docgen": "node docgen.js", + "postinstall": "node install.js", + "begin": "npm i typescript" + }, + "engines": { + "node": ">=16.6.0", + "npm": ">=7.0.0" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/shadowplay1/discord-leveling-super.git" + }, + "keywords": [ + "discord", + "bot", + "discord.js", + "leveling", + "discord-leveling", + "discord-leveling-super", + "ranks", + "ranking", + "discord-ranks", + "discord-js", + "super", + "rank", + "shadowplay" + ], + "author": "shadowplay", + "license": "MIT", + "bugs": { + "url": "https://github.com/shadowplay1/discord-leveling-super/issues" + }, + "homepage": "https://github.com/shadowplay1/discord-leveling-super#readme", + "dependencies": { + "discord.js": "^14.2.0", + "node-fetch": "^2.6.7", + "typescript": "^4.7.4" + } +} diff --git a/src/classes/Emitter.ts b/src/classes/Emitter.ts index a541cf1..7037001 100644 --- a/src/classes/Emitter.ts +++ b/src/classes/Emitter.ts @@ -8,6 +8,7 @@ const emitter = new EventEmitter() * @private */ class Emitter { + /** * Simple Leveling event emitter with only important emitter methods. * @private @@ -43,4 +44,5 @@ class Emitter { return emitter.emit(event, ...args) } } + export = Emitter \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index e5be4f6..f67f2bc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,7 +2,7 @@ import { promisify } from 'util' import { readFileSync, writeFileSync, existsSync } from 'fs' import { - Client, MessageAttachment, MessageEmbed, + Client, AttachmentBuilder, EmbedBuilder, Channel, MessagePayload, MessageOptions, TextChannel } from 'discord.js' @@ -166,7 +166,7 @@ class Leveling extends Emitter { this.interval = null this.version = modulePackage.version - this.docs = 'https://dls-docs.tk' + this.docs = 'https://dls-docs.js.org' this.database = null this.fetcher = null @@ -187,7 +187,7 @@ class Leveling extends Emitter { * @fires Leveling#destroy * @returns {Leveling | boolean} Leveling instance. */ - kill(): Leveling | boolean { + public kill(): Leveling | boolean { if (!this.ready) return false clearInterval(this.interval) @@ -217,7 +217,7 @@ class Leveling extends Emitter { * @fires Leveling#ready * @returns {Promise} If started successfully: true; else: Error instance. */ - init(): Promise { + public init(): Promise { let attempt = 0 let attempts = this.options?.errorHandler?.attempts == 0 ? Infinity : this.options?.errorHandler?.attempts @@ -279,7 +279,7 @@ class Leveling extends Emitter { * @returns {Promise} If started successfully: true; else: Error instance. * @private */ - _init(): Promise { + private _init(): Promise { const storagePath = this.options.storagePath || './leveling.json' const updateCountdown = this.options.updateCountdown const isFileExist = existsSync(storagePath) @@ -312,33 +312,33 @@ class Leveling extends Emitter { if (!version.updated) { console.log('\n\n') - console.log(colors.green + '╔═══════════════════════════════════════════════════════════╗') - console.log(colors.green + '║ @ discord-leveling-super - [] X ║') - console.log(colors.green + '║═══════════════════════════════════════════════════════════║') - console.log(colors.yellow + `║ The module is ${colors.red}out of date!${colors.yellow} ║`) - console.log(colors.magenta + '║ New version is available! ║') - console.log(colors.blue + `║ ${version.installedVersion} --> ${version.packageVersion} ║`) - console.log(colors.cyan + '║ Run "npm i discord-leveling-super@latest" ║') - console.log(colors.cyan + '║ to update! ║') - console.log(colors.white + '║ View the full changelog here: ║') - console.log(colors.red + '║ https://dls-docs.tk/#/docs/main/stable/general/changelog ║') - console.log(colors.green + '╚═══════════════════════════════════════════════════════════╝\x1b[37m') + console.log(colors.green + '╔═══════════════════════════════════════════════════════════════╗') + console.log(colors.green + '║ @ discord-leveling-super - [] X ║') + console.log(colors.green + '║═══════════════════════════════════════════════════════════════║') + console.log(colors.yellow + `║ The module is ${colors.red}out of date!${colors.yellow} ║`) + console.log(colors.magenta + '║ New version is available! ║') + console.log(colors.blue + `║ ${version.installedVersion} --> ${version.packageVersion} ║`) + console.log(colors.cyan + '║ Run "npm i discord-leveling-super@latest" ║') + console.log(colors.cyan + '║ to update! ║') + console.log(colors.white + '║ View the full changelog here: ║') + console.log(colors.red + '║ https://dls-docs.js.org/#/docs/main/stable/general/changelog ║') + console.log(colors.green + '╚═══════════════════════════════════════════════════════════════╝\x1b[37m') console.log('\n\n') } else { if (this.options?.updater?.upToDateMessage) { console.log('\n\n') - console.log(colors.green + '╔═══════════════════════════════════════════════════════════╗') - console.log(colors.green + '║ @ discord-leveling-super - [] X ║') - console.log(colors.green + '║═══════════════════════════════════════════════════════════║') - console.log(colors.yellow + `║ The module is ${colors.cyan}up of date!${colors.yellow} ║`) - console.log(colors.magenta + '║ No updates are available. ║') - console.log(colors.blue + `║ Current version is ${version.packageVersion}. ║`) - console.log(colors.cyan + '║ Enjoy! ║') - console.log(colors.white + '║ View the full changelog here: ║') - console.log(colors.red + '║ https://dls-docs.tk/#/docs/main/stable/general/changelog ║') - console.log(colors.green + '╚═══════════════════════════════════════════════════════════╝\x1b[37m') + console.log(colors.green + '╔═══════════════════════════════════════════════════════════════╗') + console.log(colors.green + '║ @ discord-leveling-super - [] X ║') + console.log(colors.green + '║═══════════════════════════════════════════════════════════════║') + console.log(colors.yellow + `║ The module is ${colors.cyan}up of date!${colors.yellow} ║`) + console.log(colors.magenta + '║ No updates are available. ║') + console.log(colors.blue + `║ Current version is ${version.packageVersion}. ║`) + console.log(colors.cyan + '║ Enjoy! ║') + console.log(colors.white + '║ View the full changelog here: ║') + console.log(colors.red + '║ https://dls-docs.js.org/#/docs/main/stable/general/changelog ║') + console.log(colors.green + '╚═══════════════════════════════════════════════════════════════╝\x1b[37m') console.log('\n\n') } @@ -399,7 +399,7 @@ class Leveling extends Emitter { * @returns {Boolean} If successfully started: true. * @private */ - start(): boolean { + public start(): boolean { this.utils = new UtilsManager(this.options, this.client) this.database = new DatabaseManager(this.options) this.fetcher = new FetchManager(this.options) @@ -412,7 +412,7 @@ class Leveling extends Emitter { this.ranks = new RanksManager(this.options, this.client) - if(!this.client.on) { + if (!this.client.on) { console.log(new LevelingError(errors.invalidClient)) process.exit(1) } @@ -495,7 +495,7 @@ class Leveling extends Emitter { + '\n]' ) } - const invalidChannels = lockedChannelsArray.filter(x => x.length !== 18) + const invalidChannels = lockedChannelsArray.filter(x => x.length !== 18 && x.length !== 19) if (invalidChannels.length) return console.log(new LevelingError(errors.lockedChannels.invalidChannels(invalidChannels))) @@ -528,7 +528,7 @@ class Leveling extends Emitter { + '\n]' ) } - const invalidUsers = ignoredUsersArray.filter(x => x.length !== 18) + const invalidUsers = ignoredUsersArray.filter(x => x.length !== 18 && x.length !== 19) if (invalidUsers.length && ignoredUsers.length) return console.log(new LevelingError(errors.ignoredUsers.invalidUsers(ignoredUsers))) for (let i of ignoredGuilds) { @@ -560,7 +560,8 @@ class Leveling extends Emitter { + '\n]' ) } - const invalidGuilds = ignoredGuildsArray.filter(x => x.length !== 18) + + const invalidGuilds = ignoredGuildsArray.filter(x => x.length !== 18 && x.length !== 19) if (invalidGuilds.length && ignoredGuilds.length) throw new LevelingError(errors.ignoredGuilds.invalidGuilds(invalidGuilds)) const levelingStatus = options.status @@ -594,9 +595,10 @@ class Leveling extends Emitter { const userXP = this.database.fetch(`${guildID}.${memberID}.xp`) const userMaxXP = this.database.fetch(`${guildID}.${memberID}.maxXP`) - const settingsXP = this.settings.get('xp', guildID) + const settingsEXP = this.settings.get('xp', guildID) + const settingsXP = Array.isArray(settingsEXP) ? Math.floor(Math.random() * (settingsEXP[1] - settingsEXP[0] + 1)) + settingsEXP[0] : settingsEXP - const xp = options.xp + const xp = Array.isArray(options.xp) ? Math.floor(Math.random() * (options.xp[1] - options.xp[0] + 1)) + options.xp[0] : options.xp const multiplier = memberMultiplier == 1 ? options.multiplier : memberMultiplier const memberXP = xp * multiplier @@ -624,7 +626,7 @@ class Leveling extends Emitter { maxXP: newMaxXP, multiplier, - sendMessage: (msg: string | MessageEmbed | MessageAttachment | MessageOptions, channel?: string | Channel | TextChannel) => { + sendMessage: (msg: string | EmbedBuilder | AttachmentBuilder | MessageOptions, channel?: string | Channel | TextChannel) => { const type = this.utils.typeOf(msg) let messageOptions: string | MessagePayload | MessageOptions @@ -641,18 +643,18 @@ class Leveling extends Emitter { messageOptions = msg as MessageOptions break - case 'MessageEmbed': + case 'EmbedBuilder': messageOptions = { embeds: [ - msg as MessageEmbed + msg as EmbedBuilder ] } break - case 'MessageAttachment': + case 'AttachmentBuilder': messageOptions = { files: [ - messageOptions as MessageAttachment + messageOptions as AttachmentBuilder ] } break @@ -683,7 +685,7 @@ class Leveling extends Emitter { if (!textChannel) throw new LevelingError(errors.sendMessage.channelNotFound) - textChannel.send(messageOptions) + return textChannel.send(messageOptions) } return message.channel.send(messageOptions) @@ -693,6 +695,7 @@ class Leveling extends Emitter { } } }) + return true } } diff --git a/src/managers/DatabaseManager.ts b/src/managers/DatabaseManager.ts index a259871..e7b060f 100644 --- a/src/managers/DatabaseManager.ts +++ b/src/managers/DatabaseManager.ts @@ -40,7 +40,7 @@ class DatabaseManager { * @param {String} key The key in database. * @returns {string[]} An array with all keys in database or 'null' if nothing found. */ - keyList(key: string): string[] { + public keyList(key: string): string[] { const storageData = this.fetcher.fetchAll() const data = this.fetch(key) @@ -57,7 +57,7 @@ class DatabaseManager { * @param {any} value Any data to set in property. * @returns {Boolean} If set successfully: true; else: false */ - set(key: string, value: any): boolean { + public set(key: string, value: any): boolean { if (!key) return false if (typeof key !== 'string') throw new LevelingError(errors.databaseManager.invalidTypes.key + typeof key) if (value == undefined) return false @@ -71,7 +71,7 @@ class DatabaseManager { * @param {Number} value Any number to add. * @returns {Boolean} If added successfully: true; else: false */ - add(key: string, value: number): boolean { + public add(key: string, value: number): boolean { const data = this.parser.parse(key) if (!key) return false @@ -92,7 +92,7 @@ class DatabaseManager { * @param {Number} value Any number to subtract. * @returns {Boolean} If set successfully: true; else: false */ - subtract(key: string, value: number): boolean { + public subtract(key: string, value: number): boolean { const data = this.parser.parse(key) if (!key) return false @@ -112,7 +112,7 @@ class DatabaseManager { * @param {String} key The key in database. * @returns {any | false} Value from the specified key or 'false' if failed to read or 'null' if nothing found. */ - fetch(key: string): any | false { + public fetch(key: string): any | false { if (!key) return false if (typeof key !== 'string') throw new LevelingError(errors.databaseManager.invalidTypes.key + typeof key) @@ -124,7 +124,7 @@ class DatabaseManager { * @param {String} key The key in database. * @returns {Boolean} If cleared: true; else: false. */ - remove(key: string): boolean { + public remove(key: string): boolean { if (!key) return false if (typeof key !== 'string') throw new LevelingError(errors.databaseManager.invalidTypes.key + typeof key) @@ -137,7 +137,7 @@ class DatabaseManager { * @param {any} value The key in database. * @returns {Boolean} If cleared: true; else: false. */ - push(key: string, value: any): boolean { + public push(key: string, value: any): boolean { if (!key) return false if (value == undefined) return false if (typeof key !== 'string') throw new LevelingError(errors.databaseManager.invalidTypes.key + typeof key) @@ -155,7 +155,7 @@ class DatabaseManager { * @param {Number} index The index in the array. * @returns {Boolean} If cleared: true; else: false. */ - removeElement(key: string, index: number): boolean { + public removeElement(key: string, index: number): boolean { if (!key) return false if (index == undefined) return false if (typeof key !== 'string') throw new LevelingError(errors.databaseManager.invalidTypes.key + typeof key) @@ -171,7 +171,7 @@ class DatabaseManager { * Fetches the entire database. * @returns {Object} Database contents */ - all(): object { + public all(): object { return this.fetcher.fetchAll() } } diff --git a/src/managers/FetchManager.ts b/src/managers/FetchManager.ts index bde5232..d13690c 100644 --- a/src/managers/FetchManager.ts +++ b/src/managers/FetchManager.ts @@ -34,7 +34,7 @@ class FetchManager { * @param {String | Guild} guild Guild or it's ID. * @returns {Number} Amount of XP. */ - fetchXP(member: string | GuildMember | User, guild: string | Guild): number { + public fetchXP(member: string | GuildMember | User, guild: string | Guild): number { const data = this.fetchAll() const isUser = member instanceof GuildMember || member instanceof User @@ -60,7 +60,7 @@ class FetchManager { * @param {String | Guild} guild Guild or it's ID. * @returns {Number} Amount of XP. */ - fetchTotalXP(member: string | GuildMember | User, guild: string | Guild): number { + public fetchTotalXP(member: string | GuildMember | User, guild: string | Guild): number { const data = this.fetchAll() const isUser = member instanceof GuildMember || member instanceof User @@ -86,7 +86,7 @@ class FetchManager { * @param {String | Guild} guild Guild or it's ID. * @returns {Number} Amount of XP. */ - fetchLevels(member: string | GuildMember | User, guild: string | Guild): number { + public fetchLevels(member: string | GuildMember | User, guild: string | Guild): number { const data = this.fetchAll() const isUser = member instanceof GuildMember || member instanceof User @@ -112,7 +112,7 @@ class FetchManager { * @param {String | Guild} guild Guild or it's ID. * @returns {Number} Amount of XP. */ - fetchMaxXP(member: string | GuildMember | User, guild: string | Guild): number { + public fetchMaxXP(member: string | GuildMember | User, guild: string | Guild): number { const data = this.fetchAll() const isUser = member instanceof GuildMember || member instanceof User @@ -138,7 +138,7 @@ class FetchManager { * @param {String | Guild} guild Guild or it's ID. * @returns {Number} Amount of XP. */ - fetchDifference(member: string | GuildMember | User, guild: string | Guild): number { + public fetchDifference(member: string | GuildMember | User, guild: string | Guild): number { const data = this.fetchAll() const isUser = member instanceof GuildMember || member instanceof User @@ -162,7 +162,7 @@ class FetchManager { * Fetches the entire database. * @returns {Object} Database contents */ - fetchAll(): object { + public fetchAll(): object { const isFileExisting = existsSync(this.storagePath) if (!isFileExisting) writeFileSync(this.storagePath, '{}') diff --git a/src/managers/LevelManager.ts b/src/managers/LevelManager.ts index 0473c2a..54e662e 100644 --- a/src/managers/LevelManager.ts +++ b/src/managers/LevelManager.ts @@ -37,7 +37,7 @@ class LevelManager extends Emitter { * @param {String | Guild} guild Guild or it's ID. * @returns {Number} Amount of levels. */ - get(member: string | GuildMember | User, guild: string | Guild): number { + public get(member: string | GuildMember | User, guild: string | Guild): number { const isUser = member instanceof GuildMember || member instanceof User const isGuild = guild instanceof Guild @@ -59,7 +59,7 @@ class LevelManager extends Emitter { * @param {String | Guild} guild Guild or it's ID. * @returns {Boolean} If set successfully: true, else: false. */ - set(level: number, member: string | GuildMember | User, guild: string | Guild): boolean { + public set(level: number, member: string | GuildMember | User, guild: string | Guild): boolean { const isUser = member instanceof GuildMember || member instanceof User const isGuild = guild instanceof Guild @@ -95,7 +95,7 @@ class LevelManager extends Emitter { * @param {Boolean} onMessage The value will be true if the method was called on 'messageCreate' bot event. * @returns {Boolean} If added successfully: true, else: false. */ - add(level: number, member: string | GuildMember | User, guild: string | Guild, onMessage: boolean = false): boolean { + public add(level: number, member: string | GuildMember | User, guild: string | Guild, onMessage: boolean = false): boolean { const isUser = member instanceof GuildMember || member instanceof User const isGuild = guild instanceof Guild @@ -107,7 +107,7 @@ class LevelManager extends Emitter { const userData: LevelData = this.database.fetch(`${botGuild}.${user}`) - if(!onMessage) this.emit('addLevel', { + if (!onMessage) this.emit('addLevel', { guildID: botGuild, userID: user, xp: userData.xp, @@ -130,7 +130,7 @@ class LevelManager extends Emitter { * @param {String | Guild} guild Guild or it's ID. * @returns {Boolean} If subtracted successfully: true, else: false. */ - subtract(level: number, member: string | GuildMember | User, guild: string | Guild): boolean { + public subtract(level: number, member: string | GuildMember | User, guild: string | Guild): boolean { const isUser = member instanceof GuildMember || member instanceof User const isGuild = guild instanceof Guild diff --git a/src/managers/RanksManager.ts b/src/managers/RanksManager.ts index b127b28..f05cce8 100644 --- a/src/managers/RanksManager.ts +++ b/src/managers/RanksManager.ts @@ -75,7 +75,7 @@ class RanksManager { * @param {String | Guild} guild Guild or it's ID * @returns {LeaderboardData[]} Sorted leaderboard array. */ - leaderboard(guild: string | Guild): LeaderboardData[] { + public leaderboard(guild: string | Guild): LeaderboardData[] { const isGuild = guild instanceof Guild if (typeof guild !== 'string' && !isGuild) throw new LevelingError(errors.invalidTypes.guild + typeof guild) diff --git a/src/managers/SettingsManager.ts b/src/managers/SettingsManager.ts index 5b2e140..305185c 100644 --- a/src/managers/SettingsManager.ts +++ b/src/managers/SettingsManager.ts @@ -70,7 +70,7 @@ class SettingsManager { * @param {String} guild Guild or it's ID. * @returns {SettingsTypes[K]} The setting from the database. */ - get(key: K, guild: string | Guild): SettingsTypes[K] { + public get(key: K, guild: string | Guild): SettingsTypes[K] { const isGuild = guild instanceof Guild if (typeof guild !== 'string' && !isGuild) throw new LevelingError(errors.invalidTypes.guild + typeof guild) @@ -95,7 +95,7 @@ class SettingsManager { * @param {String} guild Guild or it's ID. * @returns {SettingsTypes} The server settings object. */ - set(key: K, value: SettingsTypes[K], guild: string | Guild): SettingsTypes { + public set(key: K, value: SettingsTypes[K], guild: string | Guild): SettingsTypes { const isGuild = guild instanceof Guild if (value == undefined) throw new LevelingError(errors.invalidTypes.value + typeof value) @@ -124,7 +124,7 @@ class SettingsManager { * @param {String} guild Guild or it's ID. * @returns {SettingsTypes} The server settings object. */ - push(key: K, value: SettingsArrays[K], guild: string | Guild): SettingsTypes { + public push(key: K, value: SettingsArrays[K], guild: string | Guild): SettingsTypes { const isGuild = guild instanceof Guild if (value == undefined) throw new LevelingError(errors.invalidTypes.value + typeof value) @@ -156,7 +156,7 @@ class SettingsManager { * @param {String} guild Guild or it's ID. * @returns {SettingsTypes} The server settings object. */ - unpush(key: K, value: any, guild: string | Guild): SettingsTypes { + public unpush(key: K, value: any, guild: string | Guild): SettingsTypes { const isGuild = guild instanceof Guild if (typeof key !== 'string') throw new LevelingError(errors.databaseManager.invalidTypes.key + typeof key) @@ -189,7 +189,7 @@ class SettingsManager { * @param {String} guild Guild or it's ID. * @returns {SettingsTypes} The server settings object. */ - remove(key: K, guild: string | Guild): SettingsTypes { + public remove(key: K, guild: string | Guild): SettingsTypes { const isGuild = guild instanceof Guild if (typeof key !== 'string') throw new LevelingError(errors.databaseManager.invalidTypes.key + typeof key) @@ -208,7 +208,7 @@ class SettingsManager { * @param {String} guild Guild or it's ID. * @returns {SettingsTypes} The server settings object. */ - all(guild: string | Guild): SettingsTypes { + public all(guild: string | Guild): SettingsTypes { const isGuild = guild instanceof Guild if (typeof guild !== 'string' && !isGuild) throw new LevelingError(errors.invalidTypes.guild + typeof guild) @@ -238,7 +238,7 @@ class SettingsManager { * @param {String} guild Guild or it's ID. * @returns {SettingsTypes} The server settings object. */ - reset(guild: string | Guild): SettingsTypes { + public reset(guild: string | Guild): SettingsTypes { const isGuild = guild instanceof Guild if (typeof guild !== 'string' && !isGuild) throw new LevelingError(errors.invalidTypes.guild + typeof guild) diff --git a/src/managers/TotalXPManager.ts b/src/managers/TotalXPManager.ts index a77f175..8007dd9 100644 --- a/src/managers/TotalXPManager.ts +++ b/src/managers/TotalXPManager.ts @@ -37,7 +37,7 @@ class TotalXPManager extends Emitter { * @param {String | Guild} guild Guild or it's ID. * @returns {Number} Amount of total XP. */ - get(member: string | GuildMember | User, guild: string | Guild): number { + public get(member: string | GuildMember | User, guild: string | Guild): number { const isUser = member instanceof GuildMember || member instanceof User const isGuild = guild instanceof Guild @@ -59,7 +59,7 @@ class TotalXPManager extends Emitter { * @param {String | Guild} guild Guild or it's ID. * @returns {Boolean} If set successfully: true, else: false. */ - set(totalXP: number, member: string | GuildMember | User, guild: string | Guild): boolean { + public set(totalXP: number, member: string | GuildMember | User, guild: string | Guild): boolean { const isUser = member instanceof GuildMember || member instanceof User const isGuild = guild instanceof Guild @@ -95,7 +95,7 @@ class TotalXPManager extends Emitter { * @param {Boolean} onMessage The value will be true if the method was called on 'messageCreate' bot event. * @returns {Boolean} If added successfully: true, else: false. */ - add(totalXP: number, member: string | GuildMember | User, guild: string | Guild, onMessage: boolean = false): boolean { + public add(totalXP: number, member: string | GuildMember | User, guild: string | Guild, onMessage: boolean = false): boolean { const isUser = member instanceof GuildMember || member instanceof User const isGuild = guild instanceof Guild @@ -112,6 +112,7 @@ class TotalXPManager extends Emitter { userID: user, xp: userData.xp, level: userData.level, + gainedXP: totalXP, totalXP: userData.totalXP + totalXP, maxXP: userData.maxXP, difference: userData.difference, @@ -130,7 +131,7 @@ class TotalXPManager extends Emitter { * @param {String | Guild} guild Guild or it's ID. * @returns {Boolean} If subtracted successfully: true, else: false. */ - subtract(totalXP: number, member: string | GuildMember | User, guild: string | Guild): boolean { + public subtract(totalXP: number, member: string | GuildMember | User, guild: string | Guild): boolean { const isUser = member instanceof GuildMember || member instanceof User const isGuild = guild instanceof Guild diff --git a/src/managers/UtilsManager.ts b/src/managers/UtilsManager.ts index 3ea2565..ea6d5ad 100644 --- a/src/managers/UtilsManager.ts +++ b/src/managers/UtilsManager.ts @@ -66,7 +66,7 @@ class UtilsManager { * Checks for if the module is up to date. * @returns {Promise} This method will show is the module updated, latest version and installed version. */ - async checkUpdates(): Promise { + public async checkUpdates(): Promise { const version = require('../../package.json').version const packageData = await fetch('https://registry.npmjs.com/discord-leveling-super') @@ -89,7 +89,7 @@ class UtilsManager { * Fetches the entire database. * @returns {Object} Database contents */ - all(): object { + public all(): object { return this.fetcher.fetchAll() } @@ -99,7 +99,7 @@ class UtilsManager { * @param {any} data Any data to write * @returns {Boolean} If successfully written: true; else: false. */ - write(path: string, data: any): boolean { + public write(path: string, data: any): boolean { if (!path) return false if (!data) return false @@ -114,7 +114,7 @@ class UtilsManager { * Clears the storage file. * @returns {Boolean} If cleared successfully: true; else: false */ - clearStorage(): boolean { + public clearStorage(): boolean { const data = this.all() const stringData = String(data) @@ -129,7 +129,7 @@ class UtilsManager { * @param {String} guildID Guild ID * @returns {Boolean} If cleared successfully: true; else: false */ - removeGuild(guildID: string): boolean { + public removeGuild(guildID: string): boolean { const data = this.fetcher.fetchAll() const guild = data[guildID] @@ -146,7 +146,7 @@ class UtilsManager { * @param {String} guildID Guild ID * @returns {Boolean} If cleared successfully: true; else: false */ - removeUser(memberID: string, guildID: string): boolean { + public removeUser(memberID: string, guildID: string): boolean { const data = this.fetcher.fetchAll() const guild = data[guildID] @@ -167,7 +167,7 @@ class UtilsManager { * @param {RankData} object Custom rank object to set. * @returns {Boolean} If reset is successful: true; else: false. */ - reset(memberID: string, guildID: string, object?: RankData): boolean { + public reset(memberID: string, guildID: string, object?: RankData): boolean { const dataObject = DefaultObject if (!guildID) return false @@ -196,7 +196,7 @@ class UtilsManager { * @param {LevelData} options Rank object to use. * @returns {LevelData} Rank object with specified values. */ - getRankObject(options?: LevelData): LevelData { + public getRankObject(options?: LevelData): LevelData { const isDefined = (val: any) => val !== undefined ? val : false if (!options) return { @@ -229,7 +229,7 @@ class UtilsManager { * @param {any} item The item to get the type of. * @returns {String} Type or instance of the item. */ - typeOf(item: any): string { + public typeOf(item: any): string { return item === null ? 'null' : item === undefined ? @@ -244,7 +244,7 @@ class UtilsManager { * @param {any} item The item to check. * @returns {Boolean} Is the item object or not. */ - isObject(item: any): boolean { + public isObject(item: any): boolean { return !Array.isArray(item) && typeof item == 'object' && item !== null @@ -256,7 +256,7 @@ class UtilsManager { * @param {LevelingOptions} levelingOptions Leveling options object to check. * @returns {LevelingOptions} Fixed Leveling options object. */ - checkOptions(options: CheckerOptions = {}, levelingOptions: LevelingOptions): LevelingOptions { + public checkOptions(options: CheckerOptions = {}, levelingOptions: LevelingOptions): LevelingOptions { const unset = (obj: object, key: String) => { const keys = key.split('.') let tmp = obj @@ -289,10 +289,10 @@ class UtilsManager { } for (let i of keys) { if (levelingOptions[i] == undefined) { - output[i] = DefaultOptions[i] if (!options.ignoreUnspecifiedOptions) problems.push(`options.${i} is not specified.`) } + else { output[i] = levelingOptions[i] } @@ -312,9 +312,9 @@ class UtilsManager { if (typeof output[i] !== typeof DefaultOptions[i]) { if (!options.ignoreInvalidTypes) { - if (i == 'workAmount') { + if (i == 'xp') { if (typeof output[i] !== 'number' && !Array.isArray(output[i])) { - problems.push(`options.${i} is not a ${i == 'workAmount' ? 'number or array' : typeof DefaultOptions[i]}. Received type: ${typeof output[i]}.`) + problems.push(`options.${i} is not a ${i == 'xp' ? 'number or array' : typeof DefaultOptions[i]}. Received type: ${typeof output[i]}.`) output[i] = DefaultOptions[i] } diff --git a/src/managers/XPManager.ts b/src/managers/XPManager.ts index f31bd18..8f7a82c 100644 --- a/src/managers/XPManager.ts +++ b/src/managers/XPManager.ts @@ -38,7 +38,7 @@ class XPManager extends Emitter { * @param {String | Guild} guild Guild or it's ID. * @returns {Number} Amount of XP. */ - get(member: string | GuildMember | User, guild: string | Guild): number { + public get(member: string | GuildMember | User, guild: string | Guild): number { const isUser = member instanceof GuildMember || member instanceof User const isGuild = guild instanceof Guild @@ -61,7 +61,7 @@ class XPManager extends Emitter { * @param {Boolean} onMessage The value will be true if the method was called on 'messageCreate' bot event. * @returns {Boolean} If set successfully: true, else: false. */ - set(xp: number, member: string | GuildMember | User, guild: string | Guild, onMessage?: boolean): boolean { + public set(xp: number, member: string | GuildMember | User, guild: string | Guild, onMessage?: boolean): boolean { const isUser = member instanceof GuildMember || member instanceof User const isGuild = guild instanceof Guild @@ -97,7 +97,7 @@ class XPManager extends Emitter { * @param {Boolean} onMessage The value will be true if the method was called on 'messageCreate' bot event. * @returns {Boolean} If added successfully: true, else: false. */ - add(xp: number, member: string | GuildMember | User, guild: string | Guild, onMessage: boolean = false): boolean { + public add(xp: number, member: string | GuildMember | User, guild: string | Guild, onMessage: boolean = false): boolean { const isUser = member instanceof GuildMember || member instanceof User const isGuild = guild instanceof Guild @@ -115,6 +115,7 @@ class XPManager extends Emitter { xp: userData.xp + xp, totalXP: userData.totalXP, level: userData.level, + gainedXP: xp, maxXP: userData.maxXP, difference: userData.difference, multiplier: userData.multiplier, @@ -132,7 +133,7 @@ class XPManager extends Emitter { * @param {String | Guild} guild Guild or it's ID. * @returns {Boolean} If subtracted successfully: true, else: false. */ - subtract(xp: number, member: string | GuildMember | User, guild: string | Guild): boolean { + public subtract(xp: number, member: string | GuildMember | User, guild: string | Guild): boolean { const isUser = member instanceof GuildMember || member instanceof User const isGuild = guild instanceof Guild diff --git a/src/structures/Errors.ts b/src/structures/Errors.ts index 1269c7b..98fb2c7 100644 --- a/src/structures/Errors.ts +++ b/src/structures/Errors.ts @@ -55,7 +55,7 @@ const LevelingErrors = { sendMessage: { invalidTypes: { - msg: 'The message must be a string or an object with message options or instance of MessageEmbed or MessageAttachment. Received type: ', + msg: 'The message must be a string or an object with message options or instance of EmbedBuilder or AttachmentBuilder. Received type: ', channel: 'The channel must be a string. Received type: ', },