simply-xp 2.0.0-beta.1 → 2.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,19 +10,22 @@
10
10
 
11
11
  [![Downloads](https://img.shields.io/npm/dt/simply-xp?style=for-the-badge)](https://www.npmjs.com/package/simply-xp)
12
12
  [![Version](https://img.shields.io/npm/v/simply-xp.svg?style=for-the-badge)](https://www.npmjs.com/package/simply-xp)
13
- [![CodeFactor](https://www.codefactor.io/repository/github/abadima/simply-xp/badge?style=for-the-badge)](https://www.codefactor.io/repository/github/abadima/simply-xp)
13
+ [![CodeFactor](https://www.codefactor.io/repository/github/abadima/simply-xp/badge/pre-release?style=for-the-badge)](https://www.codefactor.io/repository/github/abadima/simply-xp/overview/pre-release)
14
14
 
15
15
  [![Documentation](https://img.shields.io/badge/SimplyXP-Documentation-6b46d4?style=for-the-badge)](https://simplyxp.js.org/docs/next/intro/)
16
16
  [![Support](https://img.shields.io/badge/Discord-Support-5865F2?style=for-the-badge&logo=discord)](https://discord.gg/hjhnjYJNHX)
17
+
17
18
  </div>
18
19
 
19
20
  ---
21
+
20
22
  > CREDITS TO [RAHULETTO](https://github.com/rahuletto) FOR SIMPLY-XP **VERSION 1**
23
+
21
24
  ---
22
25
 
23
26
  <br>
24
27
 
25
- ## 🖥️ <b>[DEV] Installation</b>
28
+ ## 🖥️ <b>[BETA] Installation</b>
26
29
 
27
30
  ```shell
28
31
  npm install simply-xp@beta
@@ -41,48 +44,50 @@ yarn add simply-xp@beta
41
44
  ## ✅ V2 Additions
42
45
 
43
46
  - Add `auto_create`, `auto_clean`, `debug`, and `xp_rate` options to `connect()`.
44
- - Add `compareCard()`
45
- - Add `convertFrom()`
46
- - Add `db` class for extended database functionality
47
- - Add `https()`
48
- - Add `leaderboardCard()`
49
- - Add `migrate` class
50
- - Add `SQLite` Support
51
- - Add `roleSetup.getRoles()`
52
- - Add `registerPlugins()`
47
+ - Add `compareCard()`.
48
+ - Add `convertFrom()`.
49
+ - Add `db` class for extended database functionality.
50
+ - Add `https()` function.
51
+ - Add `leaderboardCard()`.
52
+ - Add `Migrate` class with `Migrate.roleSetup()` for migrating old level roles.
53
+ - Add `SQLite` support.
54
+ - Add `LevelRoles` system (replaces old `roleSetup` functionality).
55
+ - Add `registerPlugins()`.
53
56
  - Add `removeLevel()` and `removeXP()`.
54
- - Add `roleSetup.getRoles()`
55
- - Add `updateOptions()`
56
- - Add `xp_rate` Support For Unique Level Rates!
57
+ - Add `updateOptions()`.
58
+ - Add `xp_rate` support for unique level rates.
59
+ - Add `createdAt` property to `UserResult` and `LevelRoleResult`.
60
+ - Add `levelRole` column to `simply-xp-levelroles` table in SQLite.
57
61
 
58
62
  ## 🎉 V2 Changes
59
63
 
60
- - All functions returning either `UserResult` or `LevelRoleResult` now includes `lastUpdated` property.
61
- - Better Performance & Reduced RAM overhead.
62
- - Better Code Quality (EsLint)
63
- - Complete & Revamped Documentation
64
- - Complete TypeScript Rewrite
65
- - New Fonts
66
- - Reduced Package Size!
67
- - Renewed Logging System (`XpLog`)
68
- - Deleted `chart.js` dependency
69
- - `addLevel(), addXP(), setLevel(), setXP()` now has a `username` parameter, to automatically create the user if it doesn't exist.
70
- - `fetch()` now also returns `position`, and accepts `username` parameter
71
- - `leaderboard()` now supports Global Leaderboards, by simply not passing a `guildID` argument.
72
- - `roleSetup` functions now accept RoleID arrays! `["role1", "role2", "role3"]`.
73
- - `reset()` function now accepts `erase` and `username` as optional arguments
64
+ - All functions returning `UserResult` or `LevelRoleResult` now include `lastUpdated` and `createdAt` properties.
65
+ - `lvlrole` column renamed to `levelRole`.
66
+ - `connect()` now automatically creates missing `createdAt` and `levelRole` columns for SQLite tables.
67
+ - Improved `updateOne()` for SQLite with upsert support.
68
+ - Updated `registerPlugins()` to support major, minor, patch, and pre-release versions.
69
+ - Better performance and reduced RAM usage.
70
+ - Improved code quality (ESLint) and full TypeScript rewrite.
71
+ - Renewed logging system (`XpLog`).
72
+ - Reduced package size and new fonts.
73
+ - `addLevel()`, `addXP()`, `setLevel()`, `setXP()` now accept `username` to auto-create users if they don’t exist.
74
+ - `fetch()` now returns `position` and accepts `username`.
75
+ - `leaderboard()` supports global leaderboards by omitting `guildId`.
76
+ - `roleSetup` functions now replaced by `LevelRoles` class; old `roleSetup` arrays are migrated via `Migrate.roleSetup()`.
74
77
 
75
78
  ## ⚠️ V2 Breaking Changes
76
79
 
80
+ - Old `roleSetup` system removed; migrate to `LevelRoles`.
81
+ - `lvlRole()` removed; use `LevelRoles` or `roleSetup.getRoles()`.
82
+ - `create()` now requires `username`.
83
+ - `charts()` arguments revamped.
84
+ - `rank()` removed; use `rankCard()` with new arguments.
85
+ - `client.on()` replaced with `XpEvents.on()`.
77
86
  - All functions lose `client` and `message` arguments where applicable.
78
- - `create()` Now requires `username` argument.
79
- - `charts()` Requires new arguments, and is revamped.
80
- - `rank()` is **removed**, use `rankCard()` instead. (REQUIRES NEW ARGUMENTS)
81
- - `leaderboard()` replaces `userID` with `user` in `UserResult`.
82
- - `client.on()` => `XpEvents.on()` (READ DOCS)
83
- - `roleSetup` functions loses `client` argument.
84
- - `roleSetup.fetch()` => `roleSetup.list()`
87
+ - `roleSetup.fetch()` replaced with `roleSetup.list()`.
85
88
 
86
89
  ## ❌ V2 Removals
87
90
 
88
- - `lvlRole()` is removed, use `roleSetup.getRoles()` instead. (READ DOCS)
91
+ - `lvlRole()` removed.
92
+ - `migrate` and `db` classes will be removed in future; use `Migrate` and `Database` instead.
93
+ - Old `roleSetup` methods no longer supported.
package/lib/src/add.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { UserResult } from "./functions/database";
1
+ import { UserResult } from "./classes/Database";
2
2
  /**
3
3
  * Add XP to a user
4
4
  * @async
package/lib/src/add.js CHANGED
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Add XP to a user
4
3
  * @async
@@ -9,7 +8,8 @@
9
8
  * @link `Documentation:` https://simplyxp.js.org/docs/next/functions/addlevel
10
9
  * @returns {Promise<UserResult>} - Object of user data on success
11
10
  * @throws {XpFatal} - If parameters are not provided correctly
12
- */async function addLevel(e,a,t,l){if(!e)throw new xplogs_1.XpFatal({function:"addLevel()",message:"User ID was not provided"});if(!a)throw new xplogs_1.XpFatal({function:"addLevel()",message:"Guild ID was not provided"});if(isNaN(t))throw new xplogs_1.XpFatal({function:"addLevel()",message:"Level was not provided"});var o=await database_1.db.findOne({collection:"simply-xps",data:{user:e,guild:a}});if(o)return database_1.db.updateOne({collection:"simply-xps",data:{user:e,guild:a}},{collection:"simply-xps",data:{name:l||o?.name||e,user:e,guild:a,level:o.level+t,xp:(0,xp_1.convertFrom)(t+o.level),xp_rate:xp_1.xp.xp_rate}});if(xp_1.xp.auto_create&&l)return database_1.db.createOne({collection:"simply-xps",data:{guild:a,user:e,name:l,level:t,xp:(0,xp_1.convertFrom)(t),xp_rate:xp_1.xp.xp_rate}});throw new xplogs_1.XpFatal({function:"addLevel()",message:"User does not exist"})}
11
+ */
12
+ async function addLevel(e,a,t,l){if(!e)throw new xplogs_1.XpFatal({function:"addLevel()",message:"User ID was not provided"});if(!a)throw new xplogs_1.XpFatal({function:"addLevel()",message:"Guild ID was not provided"});if(isNaN(t))throw new xplogs_1.XpFatal({function:"addLevel()",message:"Level was not provided"});var s=await Database_1.Database.findOne({collection:"simply-xps",data:{user:e,guild:a}});if(s)return Database_1.Database.updateOne({collection:"simply-xps",data:{user:e,guild:a}},{collection:"simply-xps",data:{name:l||s?.name||e,user:e,guild:a,level:s.level+t,xp:(0,xp_1.convertFrom)(t+s.level),xp_rate:xp_1.xp.xp_rate}});if(xp_1.xp.auto_create&&l)return Database_1.Database.createOne({collection:"simply-xps",data:{guild:a,user:e,name:l,level:t,xp:(0,xp_1.convertFrom)(t),xp_rate:xp_1.xp.xp_rate}});throw new xplogs_1.XpFatal({function:"addLevel()",message:"User does not exist"});}
13
13
  /**
14
14
  * Add XP to a user.
15
15
  * @async
@@ -20,4 +20,4 @@
20
20
  * @link `Documentation:` https://simplyxp.js.org/docs/next/functions/addxp
21
21
  * @returns {Promise<XPResult>} - Object of user data on success.
22
22
  * @throws {XpFatal} - If parameters are not provided correctly.
23
- */async function addXP(e,a,t,l){var o;if(!("number"==typeof t||"object"==typeof xp_1.xp&&t.min&&t.max))throw new xplogs_1.XpFatal({function:"addXP()",message:"XP is not a number or object, make sure you are using the correct syntax"});if("object"==typeof t&&(t=Math.floor(Math.random()*(t.max-t.min)+t.min)),!e)throw new xplogs_1.XpFatal({function:"addXP()",message:"User ID was not provided"});if(!a)throw new xplogs_1.XpFatal({function:"addXP()",message:"Guild ID was not provided"});let s;if(o=await database_1.db.findOne({collection:"simply-xps",data:{user:e,guild:a}}))s=await database_1.db.updateOne({collection:"simply-xps",data:{user:e,guild:a}},{collection:"simply-xps",data:{user:e,guild:a,name:l||o?.name||e,level:(0,xp_1.convertFrom)(o.xp+t,"xp"),xp:o.xp+t,xp_rate:xp_1.xp.xp_rate}}).catch(e=>{throw new xplogs_1.XpFatal({function:"addXP()",message:e.stack})});else{if(!xp_1.xp.auto_create||!l)throw new xplogs_1.XpFatal({function:"addXP()",message:"User does not exist"});s=await database_1.db.createOne({collection:"simply-xps",data:{guild:a,user:e,name:l,level:(0,xp_1.convertFrom)(t,"xp"),xp:t,xp_rate:xp_1.xp.xp_rate}}).catch(e=>{throw new xplogs_1.XpFatal({function:"addXP()",message:e.stack})})}return l=xplogs_1.XpEvents.eventCallback,(t=o?.level&&s?.level?s.level!==o.level?s.level-o.level:0:0<s?.level?s.level:0)<0&&l?.levelDown&&"function"==typeof l.levelDown&&l.levelDown(s,await xp_1.roleSetup.getRoles(e,a,{includeNextRoles:!0})),0<t&&l?.levelUp&&"function"==typeof l.levelUp&&l.levelUp(s,await xp_1.roleSetup.getRoles(e,a)),{...s,levelDifference:t}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.addXP=exports.addLevel=void 0;const xplogs_1=require("./functions/xplogs"),database_1=require("./functions/database"),xp_1=require("../xp");exports.addLevel=addLevel,exports.addXP=addXP;
23
+ */async function addXP(e,a,t,l){var s;if(!("number"==typeof t||"object"==typeof xp_1.xp&&t.min&&t.max))throw new xplogs_1.XpFatal({function:"addXP()",message:"XP is not a number or object, make sure you are using the correct syntax"});if("object"==typeof t&&(t=Math.floor(Math.random()*(t.max-t.min)+t.min)),!e)throw new xplogs_1.XpFatal({function:"addXP()",message:"User ID was not provided"});if(!a)throw new xplogs_1.XpFatal({function:"addXP()",message:"Guild ID was not provided"});let o;if(s=await Database_1.Database.findOne({collection:"simply-xps",data:{user:e,guild:a}}))o=await Database_1.Database.updateOne({collection:"simply-xps",data:{user:e,guild:a}},{collection:"simply-xps",data:{user:e,guild:a,name:l||s?.name||e,level:(0,xp_1.convertFrom)(s.xp+t,"xp"),xp:s.xp+t,xp_rate:xp_1.xp.xp_rate}}).catch(e=>{throw new xplogs_1.XpFatal({function:"addXP()",message:e.stack});});else{if(!xp_1.xp.auto_create||!l)throw new xplogs_1.XpFatal({function:"addXP()",message:"User does not exist"});o=await Database_1.Database.createOne({collection:"simply-xps",data:{guild:a,user:e,name:l,level:(0,xp_1.convertFrom)(t,"xp"),xp:t,xp_rate:xp_1.xp.xp_rate}}).catch(e=>{throw new xplogs_1.XpFatal({function:"addXP()",message:e.stack});});}return l=xplogs_1.XpEvents.eventCallback,(t=s?.level&&o?.level?o.level!==s.level?o.level-s.level:0:0<o?.level?o.level:0)<0&&l?.levelDown&&"function"==typeof l.levelDown&&l.levelDown(o,await xp_1.LevelRoles.getUserRoles(e,a,{includeNext:!0})),0<t&&l?.levelUp&&"function"==typeof l.levelUp&&l.levelUp(o,await xp_1.LevelRoles.getUserRoles(e,a)),{...o,levelDifference:t};}Object.defineProperty(exports,"__esModule",{value:!0}),exports.addLevel=addLevel,exports.addXP=addXP;let Database_1=require("./classes/Database"),xplogs_1=require("./functions/xplogs"),xp_1=require("../xp");
@@ -1,6 +1,5 @@
1
- /// <reference types="node" />
2
- import { SKRSContext2D } from "@napi-rs/canvas";
3
1
  import { User } from "../xp";
2
+ import { SKRSContext2D } from "@napi-rs/canvas";
4
3
  export type CompareCardLocales = {
5
4
  level?: string;
6
5
  versus?: string;
package/lib/src/cards.js CHANGED
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Generate a simple comparison card
4
3
  * @async
@@ -10,7 +9,8 @@
10
9
  * @link `Documentation` https://simplyxp.js.org/docs/next/functions/compareCard
11
10
  * @returns {Promise<{attachment: Buffer, description: string, name: string}>}
12
11
  * @throws {XpFatal} - If parameters are not provided correctly or if the user is not found in the database
13
- */async function compareCard(e,a,l,o={},t={}){var r,n,i,s,f,d,c;if(!e?.id||!e?.name)throw new xplogs_1.XpFatal({function:"compareCard()",message:"Please provide a guild"});if(!(a?.id&&a?.username&&l?.id&&l?.username))throw new xplogs_1.XpFatal({function:"compareCard()",message:"Please provide two valid users!"});if(!a?.avatarURL.endsWith(".png")&&!a.avatarURL.endsWith(".jpg")&&!a.avatarURL.endsWith(".webp"))throw new xplogs_1.XpFatal({function:"compareCard()",message:"[USER 1] Avatar image must be a png, jpg, or webp"});await(0,xp_1.registerFont)(o?.font||(0,path_1.join)(__dirname,"fonts","Baloo2-ExtraBold.woff2"),"Baloo"),o?.fallbackFont&&await(0,xp_1.registerFont)(o.fallbackFont,"FallbackFont"),t?.level||(t.level="Level"),t?.versus||(t.versus="vs"),s=await(0,canvas_1.loadImage)(o?.background||"https://i.ibb.co/WnfXZjc/clouds.jpg").catch(()=>{throw new xplogs_1.XpFatal({function:"compareCard()",message:"Unable to load background image, is it valid and reachable?"})}),r=await(0,canvas_1.loadImage)(a.avatarURL).catch(()=>{throw new xplogs_1.XpFatal({function:"compareCard()",message:"[USER 1] Unable to load user's AvatarURL, is it valid and reachable?"})}),n=await(0,canvas_1.loadImage)(l.avatarURL).catch(()=>{throw new xplogs_1.XpFatal({function:"compareCard()",message:"[USER 2] Unable to load user's AvatarURL, is it valid and reachable?"})});let p=await xp_1.db.findOne({collection:"simply-xps",data:{guild:e.id,user:a.id}});if(!p){if(!xp_1.xp.auto_create||!l?.username)throw new xplogs_1.XpFatal({function:"compareCard()",message:"[USER 1] User not found in database"});p=await(0,xp_1.create)(a.id,e.id,a.username)}let g=await xp_1.db.findOne({collection:"simply-xps",data:{guild:e.id,user:l.id}});if(!g){if(!xp_1.xp.auto_create||!l?.username)throw new xplogs_1.XpFatal({function:"compareCard()",message:"[USER 2] User not found in database"});g=await(0,xp_1.create)(l.id,e.id,l.username)}return RoundedBox(i=(e=(0,canvas_1.createCanvas)(1080,400)).getContext("2d"),0,0,e.width,e.height,25),i.clip(),i.fillStyle=o?.light?"#ffffff":"#000000",i.fill(),i.globalAlpha=.6,i.drawImage(s,-5,0,1090,400),i.restore(),i.globalAlpha=1,s=o?.color||o?.light?"rgba(0,0,0,0.5)":"rgba(255,255,255,0.5)",f=o?.centerBarBg||o?.light?"rgba(0,0,0,0.4)":"rgba(255,255,255,0.4)",d=t.level+(" "+shortener(p.level,!0)),c=t.level+(" "+shortener(g.level,!0)),i.save(),i.textAlign="center",i.fillStyle="#ffffff",i.shadowColor="#000000",i.shadowBlur=6,i.shadowOffsetX=1,i.shadowOffsetY=1,i.font="40px Baloo, FallbackFont",i.fillText(`${a.username} ${t.versus} `+l.username,540,60),i.restore(),i.save(),i.beginPath(),i.arc(160,200,105,0,2*Math.PI,!0),i.closePath(),i.strokeStyle=s,i.lineWidth=5,i.stroke(),i.beginPath(),i.arc(160,200,100,0,2*Math.PI,!0),i.closePath(),i.clip(),i.fillStyle=s,i.fill(),i.drawImage(r,50,90,220,220),i.restore(),i.save(),i.beginPath(),i.arc(920,200,105,0,2*Math.PI,!0),i.closePath(),i.strokeStyle=s,i.lineWidth=5,i.stroke(),i.beginPath(),i.arc(920,200,100,0,2*Math.PI,!0),i.closePath(),i.clip(),i.fillStyle=s,i.fill(),i.drawImage(n,810,90,220,220),i.restore(),i.save(),i.globalAlpha=1,i.fillStyle="#ffffff",i.textAlign="center",i.font="25px Baloo, FallbackFont",o?.light&&(i.shadowColor="#000000",i.shadowBlur=5,i.shadowOffsetX=1,i.shadowOffsetY=1),i.fillText(d,160,350),i.fillText(c,920,350),i.restore(),i.save(),i.globalAlpha=1,RoundedBox(i,265,330,540,25,10),i.clip(),i.fillStyle=f,i.fill(),i.fillStyle="#ffffff",i.textAlign="center",i.font="22px Baloo, FallbackFont",i.fillText((p.xp>g.xp?"+":"-")+Math.abs(p.level-g.level),540,350),xp_1.xp.auto_clean&&(0,xp_1.clean)(),{attachment:e.toBuffer("image/png"),description:"Simply-XP Comparison Card",name:"compareCard.png"}}
12
+ */
13
+ async function compareCard(e,a,l,t={},o={}){var r,n,i,s,f,d;
14
14
  /**
15
15
  * Generate a simple leaderboard card
16
16
  * @async
@@ -21,7 +21,7 @@
21
21
  * @link `Documentation` https://simplyxp.js.org/docs/next/functions/leaderboard
22
22
  * @returns {Promise<{attachment: Buffer, description: string, name: string}>}
23
23
  * @throws {XpFatal} - If parameters are not provided correctly
24
- */async function leaderboardCard(a,e={},l,o={}){var t,r,n,i,s,f;if(!a||a.length<1)throw new xplogs_1.XpFatal({function:"leaderboardCard()",message:"There must be at least 1 user in the data array"});let d=void 0,c=void 0,p,g=(e?.artworkImage&&(d=await(0,canvas_1.loadImage)(e.artworkImage).catch(()=>{throw new xplogs_1.XpFatal({function:"leaderboardCard()",message:"Unable to load artwork image, is it valid?"})})),e?.backgroundImage&&(c=await(0,canvas_1.loadImage)(e.backgroundImage).catch(()=>{throw new xplogs_1.XpFatal({function:"leaderboardCard()",message:"Unable to load background image, is it valid?"})})),await(0,xp_1.registerFont)(e?.primaryFont||(0,path_1.join)(__dirname,"fonts","Baloo2-ExtraBold.woff2"),"Baloo"),e?.secondaryFont&&await(0,xp_1.registerFont)(e.secondaryFont,"SecondaryFont"),e?.fallbackFont&&await(0,xp_1.registerFont)(e.fallbackFont,"FallbackFont"),o.level||(o.level="LEVEL"),o.members||(o.members="Members"),a=a.slice(0,8),t=e?.secondaryFont?"SecondaryFont, FallbackFont":"Baloo, FallbackFont",p=e?.light?{artworkColors:e?.artworkColors||["#997fe1","#616bff"],backgroundColor:"#FFFFFF",borderColors:e?.borderColors||["#e0d440","#fffa6b"],evenColor:"#f0f0f0",oddColor:"#dcdcdc",primaryTextColor:"#000000",secondaryTextColor:"rgba(0,0,0,0.5)"}:{artworkColors:e?.artworkColors||["#6B46D4","#2e3cff"],backgroundColor:"#141414",borderColors:e?.borderColors||["#e0d440","#fffa6b"],evenColor:"#1e1e1e",oddColor:"#282828",primaryTextColor:"#ffffff",secondaryTextColor:"rgba(255,255,255,0.5)"},RoundedBox(n=(r=(0,canvas_1.createCanvas)(1350,1080)).getContext("2d"),0,0,r.width,r.height,20,{clip:!0}),(i=n.createLinearGradient(0,0,r.width,0)).addColorStop(.4,p.artworkColors[0]),i.addColorStop(1,p.artworkColors[1]),n.fillStyle=i,n.fillRect(0,0,r.width,220),d&&(n.fillStyle="#000000",n.fillRect(0,0,r.width,220),n.globalAlpha=.5,n.drawImage(d,0,0,r.width,220),n.globalAlpha=1),n.fillStyle=e.backgroundColor||p.backgroundColor,n.fillRect(0,220,r.width,1080),c&&(n.globalAlpha=.9,n.drawImage(c,0,220,r.width,1080),n.globalAlpha=1),l&&l?.imageURL&&l?.name&&(i=await(0,canvas_1.loadImage)(l.imageURL),n.save(),n.beginPath(),n.arc(150,110,90,0,2*Math.PI,!0),n.closePath(),n.clip(),n.drawImage(i,60,20,180,180),n.restore(),(i=n.createLinearGradient(0,0,0,220)).addColorStop(0,p.borderColors[0]),i.addColorStop(1,p.borderColors[1]),n.strokeStyle=i,n.lineWidth=8,n.beginPath(),n.arc(150,110,90,0,2*Math.PI,!0),n.stroke(),n.fillStyle=p.primaryTextColor,n.font="60px Baloo, FallbackFont",l?.memberCount?(n.fillText(l.name,270,110),n.fillStyle=p.secondaryTextColor,n.font="40px Baloo, FallbackFont",n.fillText(l.memberCount+" "+o.members,270,160)):n.fillText(l.name,270,130)),p.evenColor);s=e?.rowOpacity&&!isNaN(e?.rowOpacity)?e.rowOpacity:c?.5:1;for(let e=0;e<a.length;e++)f=300+90*e,n.globalAlpha=s,n.save(),1===a.length?RoundedBox(n,30,f,1290,90,20,{clip:!0,fill:{color:g}}):0===e?RoundedBox(n,30,f,1290,90,20,{clip:!0,fill:{color:g},roundCorners:{top:!0,bottom:!1}}):e===a.length-1?RoundedBox(n,30,f,1290,90,20,{clip:!0,fill:{color:g},roundCorners:{top:!1,bottom:!0}}):RoundedBox(n,30,f,1290,90,0,{fill:{color:g}}),n.restore(),n.globalAlpha=1,n.textAlign="left",n.font="30px "+t,n.fillStyle=p.secondaryTextColor,n.fillText(e+1+".",60,55+f),n.textAlign="left",n.font="40px "+t,n.fillStyle=p.primaryTextColor,n.fillText(a[e]?.name||a[e]?.user||"???",120,60+f),n.textAlign="right",n.font="30px "+t,n.fillStyle=p.primaryTextColor,n.fillText(shortener(a[e]?.level)||"???",1270,55+f),n.fillStyle=p.secondaryTextColor,n.fillText(o.level,1270-n.measureText(shortener(a[e]?.level)||"???").width-15,55+f),g=g===p.evenColor?p.oddColor:p.evenColor;return xp_1.xp.auto_clean&&(0,xp_1.clean)(),{attachment:r.toBuffer("image/png"),description:"Simply-XP Leaderboard Card",name:"leaderboard.png"}}
24
+ */if(!e?.id||!e?.name)throw new xplogs_1.XpFatal({function:"compareCard()",message:"Please provide a guild"});if(!(a?.id&&a?.username&&l?.id&&l?.username))throw new xplogs_1.XpFatal({function:"compareCard()",message:"Please provide two valid users!"});if(!a?.avatarURL.endsWith(".png")&&!a.avatarURL.endsWith(".jpg")&&!a.avatarURL.endsWith(".webp"))throw new xplogs_1.XpFatal({function:"compareCard()",message:"[USER 1] Avatar image must be a png, jpg, or webp"});await(0,xp_1.registerFont)(t?.font||(0,path_1.join)(__dirname,"fonts","Baloo2-ExtraBold.woff2"),"Baloo"),t?.fallbackFont&&await(0,xp_1.registerFont)(t.fallbackFont,"FallbackFont"),o?.level||(o.level="Level"),o?.versus||(o.versus="vs"),s=await(0,canvas_1.loadImage)(t?.background||"https://i.ibb.co/WnfXZjc/clouds.jpg").catch(()=>{throw new xplogs_1.XpFatal({function:"compareCard()",message:"Unable to load background image, is it valid and reachable?"});}),r=await(0,canvas_1.loadImage)(a.avatarURL).catch(()=>{throw new xplogs_1.XpFatal({function:"compareCard()",message:"[USER 1] Unable to load user's AvatarURL, is it valid and reachable?"});}),n=await(0,canvas_1.loadImage)(l.avatarURL).catch(()=>{throw new xplogs_1.XpFatal({function:"compareCard()",message:"[USER 2] Unable to load user's AvatarURL, is it valid and reachable?"});});let c=await xp_1.Database.findOne({collection:"simply-xps",data:{guild:e.id,user:a.id}});if(!c){if(!xp_1.xp.auto_create||!l?.username)throw new xplogs_1.XpFatal({function:"compareCard()",message:"[USER 1] User not found in database"});c=await(0,xp_1.create)(a.id,e.id,a.username);}let p=await xp_1.Database.findOne({collection:"simply-xps",data:{guild:e.id,user:l.id}});if(!p){if(!xp_1.xp.auto_create||!l?.username)throw new xplogs_1.XpFatal({function:"compareCard()",message:"[USER 2] User not found in database"});p=await(0,xp_1.create)(l.id,e.id,l.username);}return RoundedBox(i=(e=(0,canvas_1.createCanvas)(1080,400)).getContext("2d"),0,0,e.width,e.height,25),i.clip(),i.fillStyle=t?.light?"#ffffff":"#000000",i.fill(),i.globalAlpha=.6,i.drawImage(s,-5,0,1090,400),i.restore(),i.globalAlpha=1,s=t?.color||t?.light?"rgba(0,0,0,0.5)":"rgba(255,255,255,0.5)",t=t?.centerBarBg||t?.light?"rgba(0,0,0,0.4)":"rgba(255,255,255,0.4)",f=o.level+(" "+shortener(c.level,!0)),d=o.level+(" "+shortener(p.level,!0)),i.save(),i.textAlign="center",i.lineWidth=6,i.strokeStyle="#000000",i.font="40px Baloo, FallbackFont",i.strokeText(`${a.username} ${o.versus} `+l.username,540,60),i.fillStyle="#ffffff",i.fillText(`${a.username} ${o.versus} `+l.username,540,60),i.restore(),i.save(),i.beginPath(),i.arc(160,200,105,0,2*Math.PI,!0),i.closePath(),i.strokeStyle=s,i.lineWidth=5,i.stroke(),i.beginPath(),i.arc(160,200,100,0,2*Math.PI,!0),i.closePath(),i.clip(),i.fillStyle=s,i.fill(),i.drawImage(r,50,90,220,220),i.restore(),i.save(),i.beginPath(),i.arc(920,200,105,0,2*Math.PI,!0),i.closePath(),i.strokeStyle=s,i.lineWidth=5,i.stroke(),i.beginPath(),i.arc(920,200,100,0,2*Math.PI,!0),i.closePath(),i.clip(),i.fillStyle=s,i.fill(),i.drawImage(n,810,90,220,220),i.restore(),i.save(),i.textAlign="center",i.font="25px Baloo, FallbackFont",i.lineWidth=5,i.strokeStyle="#000000",i.fillStyle="#ffffff",i.strokeText(f,160,350),i.fillText(f,160,350),i.strokeText(d,920,350),i.fillText(d,920,350),i.restore(),i.save(),RoundedBox(i,265,330,540,25,10),i.clip(),i.fillStyle=t,i.fill(),i.textAlign="center",i.font="22px Baloo, FallbackFont",i.lineWidth=4,i.strokeStyle="rgba(0,0,0,0.7)",i.fillStyle="#ffffff",a=(c.xp>p.xp?"+":"-")+Math.abs(c.level-p.level),i.strokeText(a,540,350),i.fillText(a,540,350),i.restore(),xp_1.xp.auto_clean&&(0,xp_1.clean)(),{attachment:e.toBuffer("image/png"),description:"Simply-XP Comparison Card",name:"compareCard.png"};}async function leaderboardCard(a,e={},l,t={}){var o,r,n,i,s,f;
25
25
  /**
26
26
  * Generate a simple user rank card
27
27
  * @async
@@ -32,4 +32,4 @@
32
32
  * @link `Documentation` https://simplyxp.js.org/docs/next/functions/rankCard
33
33
  * @returns {Promise<{attachment: Buffer, description: string, name: string}>}
34
34
  * @throws {XpFatal} - If parameters are not provided correctly
35
- */async function rankCard(e,a,l={},o={}){var t,r,n,i,s,f,d,c,p,g,h,x;if(!e)throw new xplogs_1.XpFatal({function:"rankCard()",message:"No Guild Provided"});if(!a)throw new xplogs_1.XpFatal({function:"rankCard()",message:"No User Provided"});if(o?.level||(o.level="Level"),o?.next_level||(o.next_level="Next Level"),o?.xp||(o.xp="XP"),xplogs_1.XpLog.debug("rankCard()",`${l?.legacy?"LEGACY":"MODERN"} ENABLED`),!a||!a.id||!a.username)throw new xplogs_1.XpFatal({function:"rankCard()",message:"Invalid User Provided, user must contain id, username, and avatarURL."});await(0,xp_1.registerFont)(l?.font||(0,path_1.join)(__dirname,"fonts","Baloo2-ExtraBold.woff2"),"Baloo"),l?.fallbackFont&&await(0,xp_1.registerFont)(l.fallbackFont,"FallbackFont"),i=await(0,canvas_1.loadImage)(l?.background||(l?.legacy?"https://i.ibb.co/dck2Tnt/rank-card.webp":"https://i.ibb.co/WnfXZjc/clouds.jpg")).catch(()=>{throw new xplogs_1.XpFatal({function:"rankCard()",message:"Unable to load background image, is it valid and reachable?"})}),t=await(0,canvas_1.loadImage)(a.avatarURL).catch(()=>{throw new xplogs_1.XpFatal({function:"rankCard()",message:"Unable to load user's AvatarURL, is it valid and reachable??"})});let b=await xp_1.db.findOne({collection:"simply-xps",data:{guild:e.id,user:a.id}});if(!b){if(!xp_1.xp.auto_create)throw new xplogs_1.XpFatal({function:"rankCard()",message:"User not found in database"});b=await(0,xp_1.create)(a.id,e.id,a.username)}return r=await xp_1.db.find("simply-xps",e.id),b.position=1+r.sort((e,a)=>a.xp-e.xp).findIndex(e=>e.user===a.id)||1,(n=(r=(0,canvas_1.createCanvas)(1080,400)).getContext("2d")).save(),RoundedBox(n,0,0,r.width,r.height,25),n.clip(),n.fillStyle=l?.light?"#ffffff":"#000000",n.fill(),n.globalAlpha=l?.legacy?.8:.6,n.drawImage(i,-5,0,1090,400),n.restore(),i=l?.color||(l?.legacy?"#9900ff":l?.light?"rgba(0,0,0,0.5)":"rgba(255,255,255,0.5)"),s=l?.lvlbar||"#ffffff",f=l?.lvlbarBg||l?.legacy?"#FFFFFF":l?.light?"rgba(0,0,0,0.2)":"rgba(255,255,255,0.2)",d=shortener(b.xp)+(" "+o.xp),c=o.level+(" "+shortener(b.level)),p="{current} / {needed}",g=(0,xp_1.convertFrom)(b.level+1),h=(0,xp_1.convertFrom)(b.level),h=100*(b.xp-h)/(g-h)*(l?.legacy?660:530)/100,x="326815959358898189"===b.user?"#ade6d8":1===b.position?"#ADD8E6":2===b.position?"#C0C0C0":3===b.position?"#CD7F32":"#ffffff",l?.legacy?(n.save(),n.globalAlpha=.4,n.fillStyle=l?.light?"#ffffff":"#000000",n.fillRect(40,0,240,r.height),n.restore(),n.save(),RoundedBox(n,70,30,180,180,50,{clip:!0,fill:{color:i}}),RoundedBox(n,75,35,170,170,50,{clip:!0}),n.drawImage(t,70,30,180,180),n.restore(),n.save(),RoundedBox(n,70,320,180,50,20,{clip:!0}),n.fillStyle=i,n.fillRect(70,320,180,50),n.fillStyle="#ffffff",dynamicFont(n,d,160,358,160,32),n.restore(),n.save(),RoundedBox(n,70,240,180,50,20,{clip:!0}),n.fillStyle=i,n.fillRect(70,240,180,50),n.fillStyle="#ffffff",n.textAlign="center",dynamicFont(n,c,160,278,160,32),n.restore(),n.save(),n.textAlign="left",n.fillStyle="#ffffff",n.shadowColor="#000000",n.shadowBlur=15,n.shadowOffsetX=1,n.shadowOffsetY=1,n.font="39px Baloo, FallbackFont",n.fillText(a.username,395,80),n.restore(),n.save(),n.textAlign="right",n.fillStyle="#ffffff",n.shadowColor="#000000",n.shadowBlur=15,n.shadowOffsetX=1,n.shadowOffsetY=1,n.font="55px Baloo, FallbackFont",n.fillText("#"+b.position,r.width-55,80),n.restore(),n.save(),RoundedBox(n,390,305,660,70,20,{clip:!0}),n.fillStyle="#ffffff",dynamicFont(n,e.name,720,355,700,45),n.globalAlpha=.2,n.fillRect(390,305,660,70),n.restore(),n.save(),RoundedBox(n,390,145,660,50,20,{clip:!0}),n.fillStyle=f,n.globalAlpha=.2,n.fillRect(390,145,660,50),n.restore(),n.save(),RoundedBox(n,390,145,h,50,20,{clip:!0}),n.fillStyle=s,n.globalAlpha=.5,n.fillRect(390,145,h,50),n.restore(),n.save(),n.textAlign="left",n.fillStyle="#ffffff",n.globalAlpha=.8,n.font="30px Baloo, FallbackFont",n.fillText(o.next_level+": "+shortener(g)+" "+o.xp,390,230),n.restore(),d=p.replace(/{needed}/g,shortener(g)).replace(/{current}/g,shortener(b.xp)),n.textAlign="center",n.fillStyle="#474747",n.globalAlpha=1,n.font="30px Baloo, FallbackFont",n.fillText(d,730,180)):(n.save(),n.textAlign="center",n.fillStyle="#ffffff",n.shadowColor="#000000",n.shadowBlur=5,n.shadowOffsetX=1,n.shadowOffsetY=1,n.font="40px Baloo, FallbackFont",n.fillText(a.username,540,80),n.restore(),n.save(),n.beginPath(),n.arc(160,200,105,0,2*Math.PI,!0),n.closePath(),n.lineWidth=5,n.strokeStyle=i,n.stroke(),n.beginPath(),n.arc(160,200,100,0,2*Math.PI,!0),n.closePath(),n.clip(),n.fillStyle=i,n.fill(),n.drawImage(t,50,90,220,220),n.restore(),n.save(),n.beginPath(),n.arc(230,130,30,0,2*Math.PI,!0),n.closePath(),n.strokeStyle=i,n.lineWidth=5,n.stroke(),n.beginPath(),n.arc(230,130,30,0,2*Math.PI,!0),n.closePath(),n.fillStyle=x,n.fill(),n.clip(),n.fillStyle="#000000",dynamicFont(n,shortener(b.position,!0),230,138,45,30),n.restore(),n.save(),n.fillStyle="#ffffff",l?.light&&(n.shadowColor="#000000",n.shadowBlur=5,n.shadowOffsetX=1,n.shadowOffsetY=1),n.textAlign="center",n.font="25px Baloo, FallbackFont",n.fillText(c,160,350),n.restore(),n.save(),RoundedBox(n,265,330,540,25,10,{clip:!0,fill:{color:f}}),RoundedBox(n,270,335,h,15,5,{clip:!0,fill:{color:s}}),n.restore(),n.save(),n.textAlign="center",n.fillStyle=l?.light?"rgba(0,0,0,0.6)":"rgba(255,255,255,0.6)",n.font="22px Baloo, FallbackFont",n.fillText(p.replace(/{needed}/g,shortener(g)).replace(/{current}/g,shortener(b.xp)),540,320),n.save(),n.fillStyle="#ffffff",n.textAlign="center",l?.light&&(n.shadowColor="#000000",n.shadowBlur=5,n.shadowOffsetX=1,n.shadowOffsetY=1),n.font="25px Baloo, FallbackFont",n.fillText(o.level+" "+shortener(b.level+1),920,350),n.restore()),xp_1.xp.auto_clean&&(0,xp_1.clean)(),{attachment:r.toBuffer("image/png"),description:"Simply-XP Rank Card",name:"rank.png"}}function RoundedBox(e,a,l,o,t,r,n){var i=n?.roundCorners||{top:!0,bottom:!0};e.beginPath(),e.moveTo(a+(i.top?r:0),l),e.lineTo(a+o-(i.top?r:0),l),i.top&&e.quadraticCurveTo(a+o,l,a+o,l+r),e.lineTo(a+o,l+t-(i.bottom?r:0)),i.bottom&&e.quadraticCurveTo(a+o,l+t,a+o-r,l+t),e.lineTo(a+(i.bottom?r:0),l+t),i.bottom&&e.quadraticCurveTo(a,l+t,a,l+t-r),e.lineTo(a,l+(i.top?r:0)),i.top&&e.quadraticCurveTo(a,l,a+r,l),e.closePath(),n?.fill&&(n?.clip&&e.clip(),n.fill?.color&&(e.fillStyle=n.fill.color),n.fill?.alpha&&(e.globalAlpha=n.fill.alpha),e.fillRect(a,l,o,t)),n?.stroke&&(n.stroke?.color&&(e.strokeStyle=n.stroke.color),n.stroke?.width&&(e.lineWidth=n.stroke.width),e.stroke()),n?.clip&&e.clip()}function shortener(e,a){let l="",o=0;if(!e||0===e)return"0";if(e>Number.MAX_SAFE_INTEGER)return"∞";for(;1e3<=e&&o<8;)e/=1e3,o++;switch(o){case 0:l="";break;case 1:l="K";break;case 2:l="M";break;case 3:l="B";break;case 4:l="T";break;case 5:l="Qa";break;case 6:l="Qi";break;default:l="S+"}return""+e.toFixed(0===o||a?0:2)+l}function dynamicFont(e,a,l,o,t,r){let n=r;for(;0<n&&(e.font=n+"px Baloo, FallbackFont",!(e.measureText(a).width<t));)n--;e.textAlign="center",e.fillText(a,l,o)}Object.defineProperty(exports,"__esModule",{value:!0}),exports.RoundedBox=exports.rankCard=exports.leaderboardCard=exports.compareCard=void 0;const canvas_1=require("@napi-rs/canvas"),xp_1=require("../xp"),xplogs_1=require("./functions/xplogs"),path_1=require("path");exports.compareCard=compareCard,exports.leaderboardCard=leaderboardCard,exports.rankCard=rankCard,exports.RoundedBox=RoundedBox;
35
+ */if(!a||a.length<1)throw new xplogs_1.XpFatal({function:"leaderboardCard()",message:"There must be at least 1 user in the data array"});let d=void 0,c=void 0,p,g=(e?.artworkImage&&(d=await(0,canvas_1.loadImage)(e.artworkImage).catch(()=>{throw new xplogs_1.XpFatal({function:"leaderboardCard()",message:"Unable to load artwork image, is it valid?"});})),e?.backgroundImage&&(c=await(0,canvas_1.loadImage)(e.backgroundImage).catch(()=>{throw new xplogs_1.XpFatal({function:"leaderboardCard()",message:"Unable to load background image, is it valid?"});})),await(0,xp_1.registerFont)(e?.primaryFont||(0,path_1.join)(__dirname,"fonts","Baloo2-ExtraBold.woff2"),"Baloo"),e?.secondaryFont&&await(0,xp_1.registerFont)(e.secondaryFont,"SecondaryFont"),e?.fallbackFont&&await(0,xp_1.registerFont)(e.fallbackFont,"FallbackFont"),t.level||(t.level="LEVEL"),t.members||(t.members="Members"),a=a.slice(0,8),o=e?.secondaryFont?"SecondaryFont, FallbackFont":"Baloo, FallbackFont",p=e?.light?{artworkColors:e?.artworkColors||["#997fe1","#616bff"],backgroundColor:"#FFFFFF",borderColors:e?.borderColors||["#e0d440","#fffa6b"],evenColor:e?.rowColors?.[0]||"#f0f0f0",oddColor:e?.rowColors?.[1]||"#dcdcdc",primaryTextColor:"#000000",secondaryTextColor:"rgba(0,0,0,0.5)"}:{artworkColors:e?.artworkColors||["#6B46D4","#2e3cff"],backgroundColor:"#141414",borderColors:e?.borderColors||["#e0d440","#fffa6b"],evenColor:e?.rowColors?.[0]||"#1e1e1e",oddColor:e?.rowColors?.[1]||"#282828",primaryTextColor:"#ffffff",secondaryTextColor:"rgba(255,255,255,0.5)"},RoundedBox(n=(r=(0,canvas_1.createCanvas)(1350,1080)).getContext("2d"),0,0,r.width,r.height,20,{clip:!0}),(i=n.createLinearGradient(0,0,r.width,0)).addColorStop(.4,p.artworkColors[0]),i.addColorStop(1,p.artworkColors[1]),n.fillStyle=i,n.fillRect(0,0,r.width,220),d&&(n.fillStyle="#000000",n.fillRect(0,0,r.width,220),n.globalAlpha=.5,n.drawImage(d,0,0,r.width,220),n.globalAlpha=1),n.fillStyle=e.backgroundColor||p.backgroundColor,n.fillRect(0,220,r.width,1080),c&&(n.globalAlpha=.9,n.drawImage(c,0,220,r.width,1080),n.globalAlpha=1),l&&l?.imageURL&&l?.name&&(i=await(0,canvas_1.loadImage)(l.imageURL),n.save(),n.beginPath(),n.arc(150,110,90,0,2*Math.PI,!0),n.closePath(),n.clip(),n.drawImage(i,60,20,180,180),n.restore(),(i=n.createLinearGradient(0,0,0,220)).addColorStop(0,p.borderColors[0]),i.addColorStop(1,p.borderColors[1]),n.strokeStyle=i,n.lineWidth=8,n.beginPath(),n.arc(150,110,90,0,2*Math.PI,!0),n.stroke(),n.fillStyle=p.primaryTextColor,n.font="60px Baloo, FallbackFont",l?.memberCount?(n.fillText(l.name,270,110),n.fillStyle=p.secondaryTextColor,n.font="40px Baloo, FallbackFont",n.fillText(l.memberCount+" "+t.members,270,160)):n.fillText(l.name,270,130)),p.evenColor);s=e?.rowOpacity&&!isNaN(e?.rowOpacity)?e.rowOpacity:c?.5:1;for(let e=0;e<a.length;e++)f=300+90*e,n.globalAlpha=s,n.save(),1===a.length?RoundedBox(n,30,f,1290,90,20,{clip:!0,fill:{color:g}}):0===e?RoundedBox(n,30,f,1290,90,20,{clip:!0,fill:{color:g},roundCorners:{top:!0,bottom:!1}}):e===a.length-1?RoundedBox(n,30,f,1290,90,20,{clip:!0,fill:{color:g},roundCorners:{top:!1,bottom:!0}}):RoundedBox(n,30,f,1290,90,0,{fill:{color:g}}),n.restore(),n.globalAlpha=1,n.textAlign="left",n.font="30px "+o,n.fillStyle=p.secondaryTextColor,n.fillText(e+1+".",60,55+f),n.textAlign="left",n.font="40px "+o,n.fillStyle=p.primaryTextColor,n.fillText(a[e]?.name||a[e]?.user||"???",120,60+f),n.textAlign="right",n.font="30px "+o,n.fillStyle=p.primaryTextColor,n.fillText(shortener(a[e]?.level)||"???",1270,55+f),n.fillStyle=p.secondaryTextColor,n.fillText(t.level,1270-n.measureText(shortener(a[e]?.level)||"???").width-15,55+f),g=g===p.evenColor?p.oddColor:p.evenColor;return xp_1.xp.auto_clean&&(0,xp_1.clean)(),{attachment:r.toBuffer("image/png"),description:"Simply-XP Leaderboard Card",name:"leaderboard.png"};}async function rankCard(e,a,l={},t={}){var o,r,n,i,s,f,d,c,p,g,x,h;if(!e)throw new xplogs_1.XpFatal({function:"rankCard()",message:"No Guild Provided"});if(!a)throw new xplogs_1.XpFatal({function:"rankCard()",message:"No User Provided"});if(t?.level||(t.level="Level"),t?.next_level||(t.next_level="Next Level"),t?.xp||(t.xp="XP"),xplogs_1.XpLog.debug("rankCard()",`${l?.legacy?"LEGACY":"MODERN"} ENABLED`),!a||!a.id||!a.username)throw new xplogs_1.XpFatal({function:"rankCard()",message:"Invalid User Provided, user must contain id, username, and avatarURL."});await(0,xp_1.registerFont)(l?.font||(0,path_1.join)(__dirname,"fonts","Baloo2-ExtraBold.woff2"),"Baloo"),l?.fallbackFont&&await(0,xp_1.registerFont)(l.fallbackFont,"FallbackFont"),i=await(0,canvas_1.loadImage)(l?.background||(l?.legacy?"https://i.ibb.co/dck2Tnt/rank-card.webp":"https://i.ibb.co/WnfXZjc/clouds.jpg")).catch(()=>{throw new xplogs_1.XpFatal({function:"rankCard()",message:"Unable to load background image, is it valid and reachable?"});}),o=await(0,canvas_1.loadImage)(a.avatarURL).catch(()=>{throw new xplogs_1.XpFatal({function:"rankCard()",message:"Unable to load user's AvatarURL, is it valid and reachable??"});});let b=await xp_1.Database.findOne({collection:"simply-xps",data:{guild:e.id,user:a.id}});if(!b){if(!xp_1.xp.auto_create)throw new xplogs_1.XpFatal({function:"rankCard()",message:"User not found in database"});b=await(0,xp_1.create)(a.id,e.id,a.username);}return r=await xp_1.Database.find("simply-xps",e.id),b.position=1+r.sort((e,a)=>a.xp-e.xp).findIndex(e=>e.user===a.id)||1,(n=(r=(0,canvas_1.createCanvas)(1080,400)).getContext("2d")).save(),RoundedBox(n,0,0,r.width,r.height,25),n.clip(),n.fillStyle=l?.light?"#ffffff":"#000000",n.fill(),n.globalAlpha=l?.legacy?.8:.6,n.drawImage(i,-5,0,1090,400),n.restore(),i=l?.color||(l?.legacy?"#9900ff":l?.light?"rgba(0,0,0,0.5)":"rgba(255,255,255,0.5)"),s=l?.lvlbar||"#ffffff",f=l?.lvlbarBg||l?.legacy?"#FFFFFF":l?.light?"rgba(0,0,0,0.2)":"rgba(255,255,255,0.2)",d=shortener(b.xp)+(" "+t.xp),c=t.level+(" "+shortener(b.level)),p="{current} / {needed}",g=(0,xp_1.convertFrom)(b.level+1),x=(0,xp_1.convertFrom)(b.level),x=100*(b.xp-x)/(g-x)*(l?.legacy?660:530)/100,h="326815959358898189"===b.user?"#ade6d8":1===b.position?"#ADD8E6":2===b.position?"#C0C0C0":3===b.position?"#CD7F32":"#ffffff",l?.legacy?(n.save(),n.globalAlpha=.4,n.fillStyle=l?.light?"#ffffff":"#000000",n.fillRect(40,0,240,r.height),n.restore(),n.save(),RoundedBox(n,70,30,180,180,50,{clip:!0,fill:{color:i}}),RoundedBox(n,75,35,170,170,50,{clip:!0}),n.drawImage(o,70,30,180,180),n.restore(),n.save(),RoundedBox(n,70,320,180,50,20,{clip:!0}),n.fillStyle=i,n.fillRect(70,320,180,50),n.fillStyle="#ffffff",dynamicFont(n,d,160,355,160,32),n.restore(),n.save(),RoundedBox(n,70,240,180,50,20,{clip:!0}),n.fillStyle=i,n.fillRect(70,240,180,50),n.fillStyle="#ffffff",n.textAlign="center",dynamicFont(n,c,160,275,160,32),n.restore(),n.save(),n.textAlign="left",n.font="39px Baloo, FallbackFont",n.fillStyle="#ffffff",n.lineWidth=4,n.strokeStyle="#000000",n.strokeText(a.username,395,80),n.fillText(a.username,395,80),n.restore(),n.save(),n.textAlign="right",n.font="55px Baloo, FallbackFont",n.fillStyle="#ffffff",n.lineWidth=4,n.strokeStyle="#000000",n.strokeText("#"+b.position,r.width-55,80),n.fillText("#"+b.position,r.width-55,80),n.restore(),n.save(),RoundedBox(n,390,305,660,70,20,{clip:!0}),n.globalAlpha=.2,n.fillStyle="#ffffff",n.fillRect(390,305,660,70),n.globalAlpha=1,dynamicFont(n,e.name,720,355,700,45),n.restore(),n.save(),RoundedBox(n,390,145,660,50,20,{clip:!0}),n.globalAlpha=.2,n.fillStyle=f,n.fillRect(390,145,660,50),n.restore(),n.save(),RoundedBox(n,390,145,x,50,20,{clip:!0}),n.globalAlpha=.5,n.fillStyle=s,n.fillRect(390,145,x,50),n.restore(),n.save(),n.textAlign="left",n.font="30px Baloo, FallbackFont",n.fillStyle="#ffffff",n.globalAlpha=.8,n.fillText(`${t.next_level}: ${shortener(g)} `+t.xp,390,230),n.restore(),n.textAlign="center",n.font="30px Baloo, FallbackFont",n.fillStyle="#474747",n.globalAlpha=1,d=p.replace(/{needed}/g,shortener(g)).replace(/{current}/g,shortener(b.xp)),n.fillText(d,730,180)):(n.save(),n.textAlign="center",n.font="40px Baloo, FallbackFont",n.lineWidth=4,n.strokeStyle="#000000",n.strokeText(a.username,540,80),n.fillStyle="#ffffff",n.fillText(a.username,540,80),n.restore(),n.save(),n.beginPath(),n.arc(160,200,105,0,2*Math.PI),n.strokeStyle=i,n.lineWidth=5,n.stroke(),n.beginPath(),n.arc(160,200,100,0,2*Math.PI),n.clip(),n.fillStyle=i,n.fill(),n.drawImage(o,50,90,220,220),n.restore(),n.save(),n.beginPath(),n.arc(230,130,30,0,2*Math.PI),n.strokeStyle=i,n.lineWidth=5,n.stroke(),n.beginPath(),n.arc(230,130,30,0,2*Math.PI),n.fillStyle=h,n.fill(),n.clip(),n.fillStyle="#000000",dynamicFont(n,shortener(b.position,!0),230,138,45,30),n.restore(),n.save(),n.textAlign="center",n.font="25px Baloo, FallbackFont",n.lineWidth=3,n.strokeStyle=(l?.light,"#000000"),n.strokeText(c,160,350),n.fillStyle="#ffffff",n.fillText(c,160,350),n.restore(),n.save(),RoundedBox(n,265,330,540,25,10,{clip:!0,fill:{color:f}}),RoundedBox(n,270,335,x,15,5,{clip:!0,fill:{color:s}}),n.restore(),n.save(),n.textAlign="center",n.font="22px Baloo, FallbackFont",n.fillStyle=l?.light?"rgba(0,0,0,0.6)":"rgba(255,255,255,0.6)",n.fillText(p.replace(/{needed}/g,shortener(g)).replace(/{current}/g,shortener(b.xp)),540,320),n.restore(),n.save(),n.textAlign="center",n.font="25px Baloo, FallbackFont",e=t.level+" "+shortener(b.level+1),n.lineWidth=3,n.strokeStyle=(l?.light,"#000000"),n.strokeText(e,920,350),n.fillStyle="#ffffff",n.fillText(e,920,350),n.restore()),xp_1.xp.auto_clean&&(0,xp_1.clean)(),{attachment:r.toBuffer("image/png"),description:"Simply-XP Rank Card",name:"rank.png"};}function RoundedBox(e,a,l,t,o,r,n){var i=n?.roundCorners||{top:!0,bottom:!0};e.beginPath(),e.moveTo(a+(i.top?r:0),l),e.lineTo(a+t-(i.top?r:0),l),i.top&&e.quadraticCurveTo(a+t,l,a+t,l+r),e.lineTo(a+t,l+o-(i.bottom?r:0)),i.bottom&&e.quadraticCurveTo(a+t,l+o,a+t-r,l+o),e.lineTo(a+(i.bottom?r:0),l+o),i.bottom&&e.quadraticCurveTo(a,l+o,a,l+o-r),e.lineTo(a,l+(i.top?r:0)),i.top&&e.quadraticCurveTo(a,l,a+r,l),e.closePath(),n?.fill&&(n?.clip&&e.clip(),n.fill?.color&&(e.fillStyle=n.fill.color),n.fill?.alpha&&(e.globalAlpha=n.fill.alpha),e.fillRect(a,l,t,o)),n?.stroke&&(n.stroke?.color&&(e.strokeStyle=n.stroke.color),n.stroke?.width&&(e.lineWidth=n.stroke.width),e.stroke()),n?.clip&&e.clip();}function shortener(e,a){let l="",t=0;if(!e||0===e)return"0";if(e>Number.MAX_SAFE_INTEGER)return"∞";for(;1e3<=e&&t<8;)e/=1e3,t++;switch(t){case 0:l="";break;case 1:l="K";break;case 2:l="M";break;case 3:l="B";break;case 4:l="T";break;case 5:l="Qa";break;case 6:l="Qi";break;default:l="S+";}return""+e.toFixed(0===t||a?0:2)+l;}function dynamicFont(e,a,l,t,o,r){let n=r;for(;0<n&&(e.font=n+"px Baloo, FallbackFont",!(e.measureText(a).width<o));)n--;e.textAlign="center",e.fillText(a,l,t);}Object.defineProperty(exports,"__esModule",{value:!0}),exports.compareCard=compareCard,exports.leaderboardCard=leaderboardCard,exports.rankCard=rankCard,exports.RoundedBox=RoundedBox;let xp_1=require("../xp"),canvas_1=require("@napi-rs/canvas"),xplogs_1=require("./functions/xplogs"),path_1=require("path");
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  /**
3
2
  * Chart options
4
3
  * @property {string} font - Font of the chart
@@ -9,7 +8,7 @@ export interface ChartOptions {
9
8
  fallbackFont?: string;
10
9
  font?: string;
11
10
  limit?: 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;
12
- theme?: "blue" | "dark" | "discord" | "green" | "orange" | "red" | "space" | "yellow";
11
+ theme?: "blue" | "dark" | "discord" | "green" | "light" | "orange" | "pink" | "red" | "space" | "yellow";
13
12
  type?: "bar" | "doughnut" | "pie";
14
13
  }
15
14
  /**
package/lib/src/charts.js CHANGED
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Creates a chart
4
3
  * @async
@@ -7,4 +6,5 @@
7
6
  * @link `Documentation:` https://simplyxp.js.org/docs/next/functions/charts
8
7
  * @returns {Promise<{attachment: Buffer, description: string, name: string}>} Chart attachment
9
8
  * @throws {XpFatal} If invalid parameters are provided, or if there are not enough users to create a chart
10
- */async function charts(e,r={}){var t,a,o,F,l,i,n,s,h;if(!e)throw new xplogs_1.XpFatal({function:"charts()",message:"No Guild ID Provided"});if(!r)throw new xplogs_1.XpFatal({function:"charts()",message:"No Options Provided"});r.theme&&["blue","dark","discord","green","orange","red","space","yellow"].includes(r.theme)||(xplogs_1.XpLog.warn("charts()","Invalid theme provided, defaulting to discord"),r.theme="discord"),r.type&&["bar","doughnut","pie"].includes(r.type)||(xplogs_1.XpLog.warn("charts()","Invalid type provided, defaulting to bar chart"),r.type="bar");let c;if((t=await(0,xp_1.leaderboard)(e,Math.min(Math.max(r?.limit||10,2),10)).catch(e=>{throw new xplogs_1.XpFatal({function:"charts()",message:e.message})})).length<2)throw new xplogs_1.XpFatal({function:"charts()",message:"Not enough users to create a chart"});switch(t.sort((e,t)=>t.position-e.position),await(0,xp_1.registerFont)(r?.font||(0,path_1.join)(__dirname,"fonts","Baloo2-ExtraBold.woff2"),"Baloo"),r.fallbackFont&&await(0,xp_1.registerFont)(r.fallbackFont,"FallbackFont"),r.theme){case"blue":c={background:"#1e1e3c",barColor:"#747fff",pieColors:["#747fff","#2832C2","#59788E","#00d2e7","#281E5D","#a9f5ff","#000e3f","#30edc2","#186c84","#0098ff"],textColor:"#FFFFFF"};break;case"dark":c={background:"#1e1e1e",barColor:"#747474",pieColors:["#1B1D1F","#454C53","#72787F","#999999","#9EA4AA","#CCCCCC","#C9CDD2","#DEDEDE","#E8EBED","#FFFFFF"],textColor:"#FFFFFF"};break;case"discord":c={background:"#36393f",barColor:"#5865F2",pieColors:["#5865F2","#57F287","#FEE75C","#EB459E","#ED4245","#FFFFFF","#000000","#FAA61A","#C04DF9","#00AAFF"],textColor:"#FFFFFF"};break;case"green":c={background:"#1e321e",barColor:"#74ff7f",pieColors:["#00FF00","#008000","#7FFF00","#32CD32","#228B22","#006400","#9ACD32","#00FA9A","#ADFF2F","#7CFC00"],textColor:"#FFFFFF"};break;case"orange":c={background:"#321e1e",barColor:"#ff9f74",pieColors:["#FF8C00","#FF5E0E","#FF4500","#FF6347","#E26310","#F5761A","#FD673A","#FFA500","#FF7F50","#FFD700"],textColor:"#FFFFFF"};break;case"red":c={background:"#321e1e",barColor:"#ff7474",pieColors:["#FF0000","#FF2400","#FF4500","#FF6347","#FF7F50","#FF8C00","#FFA07A","#FFA500","#FFC0CB","#FFD700"],textColor:"#FFFFFF"};break;case"space":c={background:"#001F3F",barColor:"#192E5B",pieColors:["#192E5B","#1F3F7F","#264FA3","#2C5FC7","#337FEA","#3D8FFF","#4D9FFF","#5DAFFF","#6DBFFF","#7DCFFF"],textColor:"#FFFFFF"};break;case"yellow":c={background:"#32321e",barColor:"#ffff74",pieColors:["#FFFD37","#FFEF00","#FDFF00","#DAA520","#F4C430","#E4D00A","#D2B55B","#FFFFE0","#FFFACD","#F5DEB3"],textColor:"#FFFFFF"}}const d=(0,canvas_1.createCanvas)(920,600),p=d.getContext("2d"),f=Math.max(...t.map(e=>e.level));if((0,cards_1.RoundedBox)(p,0,0,d.width,d.height,25,{clip:!0}),p.fillStyle=c.background,p.fillRect(0,0,d.width,d.height),"space"===r.theme){(e=p.createRadialGradient(d.width/2,d.height/2,1,d.width/2,d.height/2,Math.max(d.width,d.height))).addColorStop(0,"#000000"),e.addColorStop(1,"#001F3F"),p.fillStyle=e,p.fillRect(0,0,d.width,d.height),(e=p.createRadialGradient(150,150,10,150,150,100)).addColorStop(0,"#F2F2F2"),e.addColorStop(.8,"#D3D3D3"),e.addColorStop(1,"#001F3F"),p.fillStyle=e,p.beginPath(),p.arc(150,150,100,0,2*Math.PI),p.fill(),a=["#6B6B6B","#AA8F00","#473E83","#456579"];for(let e=0;e<a.length;e++)o=Math.random()*d.width,F=Math.random()*d.height,l=50*Math.random()+30,p.beginPath(),p.arc(o,F,l,0,2*Math.PI),p.fillStyle=a[e]||"#FFFFFF",p.fill();p.filter="blur(5px)",p.drawImage(d,0,0),p.filter="none";for(let e=0;e<100;e++)i=Math.random()*d.width,n=Math.random()*d.height,s=2*Math.random(),p.beginPath(),p.arc(i,n,s,0,2*Math.PI),p.fillStyle="#FFFFFF",p.fill()}let g=d.width-40,C=d.height-40;switch(r.type){case"bar":{h=p.measureText(f.toString()).width,g=d.width-h-100,C=d.height-140;const u=g/t.length-20,b=h+60,m=d.height-70;await Promise.all(t.map(async(e,t)=>{var a,o=(e.level===1/0?1:e.level/f)*C,t=b+t*(20+u),F=m-o,o=(p.save(),(0,cards_1.RoundedBox)(p,t,F,u,o,10,{clip:!0,fill:{color:c.barColor}}),p.restore(),t+u/2),t=(p.fillStyle=c.textColor,p.font="22px Baloo, FallbackFont",e.level.toString()),l=p.measureText(t).width,F=F-10,t=(p.fillText(t,o-l/2,F),e?.name||e.user),l=p.measureText(t).width,F=(p.font=Math.min(Math.floor(u/l*16),18)+"px Baloo, FallbackFont",l=p.measureText(t).width,30+m);"space"===r.theme&&(a=o-(e=l+20)/2,p.fillStyle="rgba(0, 0, 0, 0.5)",p.fillRect(a,F-18,e,25)),p.fillStyle=c.textColor,p.fillText(t,o-l/2,F)}))}break;case"doughnut":{const x=t.reduce((e,t)=>e+t.level,0),w=Math.min(g,C)/3,D=.6*w;let a=-Math.PI/2;const v=d.width/2,y=d.height/2;await Promise.all(t.map(async(e,t)=>{e=a+2*Math.PI*(e.level/x),p.fillStyle=c.pieColors[t%c.pieColors.length]||"#FFFFFF",p.beginPath(),p.moveTo(v+w*Math.cos(a),y+w*Math.sin(a)),p.arc(v,y,w,a,e),p.lineTo(v+D*Math.cos(e),y+D*Math.sin(e)),p.arc(v,y,D,e,a,!0),p.closePath(),p.fill(),a=e}))}break;case"pie":{const k=t.reduce((e,t)=>e+t.level,0),A=Math.min(g,C)/3;let a=-Math.PI/2;const E=d.width/2,M=d.height/2;await Promise.all(t.map(async(e,t)=>{e=a+2*Math.PI*(e.level/k),p.fillStyle=c.pieColors[t%c.pieColors.length]||"#FFFFFF",p.beginPath(),p.moveTo(E,M),p.arc(E,M,A,a,e),p.closePath(),p.fill(),a=e}))}break;default:throw new xplogs_1.XpFatal({function:"charts()",message:"Invalid chart type provided"})}if(["doughnut","pie"].includes(r.type)){const _=d.height-20-20*t.length;p.fillStyle="rgba(0,0,0,0.25)",p.fillRect(15,_-5,200,20*t.length+5),p.font="12px Baloo, FallbackFont",await Promise.all(t.map(async(e,t)=>{var a=c.pieColors[t%c.pieColors.length],t=_+20*t;p.fillStyle=a||"#FFFFFF",p.fillRect(20,t,15,15),p.fillStyle=c.textColor,p.fillText(e?.name||e.user,40,11.5+t)}))}return xp_1.xp.auto_clean&&(0,xp_1.clean)(),{attachment:d.toBuffer("image/png"),description:"Chart",name:"chart.png"}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.charts=void 0;const xp_1=require("../xp"),canvas_1=require("@napi-rs/canvas"),path_1=require("path"),cards_1=require("./cards"),xplogs_1=require("./functions/xplogs");exports.charts=charts;
9
+ */
10
+ async function charts(F,n={}){var e,t,a,o,l,r,i,h,c;if(!F)throw new xplogs_1.XpFatal({function:"charts()",message:"No Guild ID Provided"});if(!n)throw new xplogs_1.XpFatal({function:"charts()",message:"No Options Provided"});n.theme&&["blue","dark","discord","green","light","orange","pink","red","space","yellow"].includes(n.theme)||(xplogs_1.XpLog.warn("charts()","Invalid theme provided, defaulting to discord"),n.theme="discord"),n.type&&["bar","doughnut","pie"].includes(n.type)||(xplogs_1.XpLog.warn("charts()","Invalid type provided, defaulting to bar chart"),n.type="bar");let s;if((e=await(0,xp_1.leaderboard)(F,Math.min(Math.max(n?.limit||10,2),10)).catch(F=>{throw new xplogs_1.XpFatal({function:"charts()",message:F.message});})).length<2)throw new xplogs_1.XpFatal({function:"charts()",message:"Not enough users to create a chart"});switch(await(0,xp_1.registerFont)(n?.font||(0,path_1.join)(__dirname,"fonts","Baloo2-ExtraBold.woff2"),"Baloo"),n.fallbackFont&&await(0,xp_1.registerFont)(n.fallbackFont,"FallbackFont"),n.theme){case"blue":s={background:"#1e1e3c",barColor:"#747fff",pieColors:["#5A6BFF","#52FFF2","#6FB6FF","#30EDC2","#3F8CFF","#1BB8A3","#8CD9FF","#2F53FF","#0098FF","#A9F5FF"],textColor:"#FFFFFF"};break;case"dark":s={background:"#1e1e1e",barColor:"#747474",pieColors:["#FF7A7A","#39FF9D","#4C8BF5","#FFE066","#2BD9FF","#FF5EDB","#C47BFF","#6ED0FF","#FFA53A","#FFCC66"],textColor:"#FFFFFF"};break;case"discord":s={background:"#36393f",barColor:"#5865F2",pieColors:["#5865F2","#57F287","#FEE75C","#EB459E","#ED4245","#FFFFFF","#000000","#FAA61A","#C04DF9","#00AAFF"],textColor:"#FFFFFF"};break;case"green":s={background:"#1e321e",barColor:"#74ff7f",pieColors:["#66FFB2","#4DFFDF","#A8FF66","#32FF9C","#7CFFA3","#3AD7C9","#00D47A","#59FFC2","#1ED1A6","#7AFFCE"],textColor:"#FFFFFF"};break;case"light":s={background:"#f2f2f2",barColor:"#1c1c1c",pieColors:["#FF7A7A","#6ED0FF","#FFCC66","#C47BFF","#2BD9FF","#FFA53A","#FF5EDB","#39FF9D","#FFE066","#4C8BF5"],textColor:"#000000"};break;case"orange":s={background:"#321e1e",barColor:"#ff9f74",pieColors:["#FF8A4C","#FF6E35","#FFD28C","#FF7A45","#FFAA66","#FFC999","#FF9A5E","#FFB76B","#FF8F52","#FFD28C"],textColor:"#FFFFFF"};break;case"pink":s={background:"#3c1e3c",barColor:"#ff74ff",pieColors:["#FF8BFF","#FF6BD1","#A87CFF","#FFB6FF","#7DF7FF","#8FA6FF","#5FA8FF","#CE5CFF","#FF4FA3","#DFA0FF"],textColor:"#FFFFFF"};break;case"red":s={background:"#321e1e",barColor:"#ff7474",pieColors:["#FF6B6B","#FFD166","#FF4F5C","#FFB266","#FF7A85","#FFC099","#FF6F91","#FF8F4D","#FF9A7A","#FFA8B0"],textColor:"#FFFFFF"};break;case"space":s={background:"#001F3F",barColor:"#192E5B",pieColors:["#192E5B","#264FA3","#337FEA","#2C5FC7","#1F3F7F","#3D8FFF","#4D9FFF","#5DAFFF","#6DBFFF","#7DCFFF"],textColor:"#FFFFFF"};break;case"yellow":s={background:"#32321e",barColor:"#ffff74",pieColors:["#FFEF99","#FFE266","#FFB84D","#FFF6C2","#FFD966","#e6ff77ff","#FFCC33","#E6A82E","#D4A741","#FFE8AA"],textColor:"#FFFFFF"};}let d=(0,canvas_1.createCanvas)(920,600),f=d.getContext("2d"),p=Math.max(...e.map(F=>F.level));if((0,cards_1.RoundedBox)(f,0,0,d.width,d.height,25,{clip:!0}),f.fillStyle=s.background,f.fillRect(0,0,d.width,d.height),"space"===n.theme){(F=f.createRadialGradient(d.width/2,d.height/2,1,d.width/2,d.height/2,Math.max(d.width,d.height))).addColorStop(0,"#000000"),F.addColorStop(1,"#001F3F"),f.fillStyle=F,f.fillRect(0,0,d.width,d.height),(F=f.createRadialGradient(150,150,10,150,150,100)).addColorStop(0,"#F2F2F2"),F.addColorStop(.8,"#D3D3D3"),F.addColorStop(1,"#001F3F"),f.fillStyle=F,f.beginPath(),f.arc(150,150,100,0,2*Math.PI),f.fill(),t=["#6B6B6B","#AA8F00","#473E83","#456579"];for(let F=0;F<t.length;F++)a=Math.random()*d.width,o=Math.random()*d.height,l=50*Math.random()+30,f.beginPath(),f.arc(a,o,l,0,2*Math.PI),f.fillStyle=t[F]||"#FFFFFF",f.fill();f.filter="blur(5px)",f.drawImage(d,0,0),f.filter="none";for(let F=0;F<100;F++)r=Math.random()*d.width,i=Math.random()*d.height,h=2*Math.random(),f.beginPath(),f.arc(r,i,h,0,2*Math.PI),f.fillStyle="#FFFFFF",f.fill();}let C=d.width-40,g=d.height-40;switch(n.type){case"bar":{c=f.measureText(p.toString()).width,C=d.width-c-100,g=d.height-140;let r=C/e.length-20,i=c+60,h=d.height-70;e.map((F,e)=>{var t,a=(F.level===1/0?1:F.level/p)*g,e=i+e*(20+r),o=h-a,a=(f.save(),(0,cards_1.RoundedBox)(f,e,o,r,a,10,{clip:!0,fill:{color:s.barColor}}),f.restore(),e+r/2),e=(f.fillStyle=s.textColor,f.font="22px Baloo, FallbackFont",F.level.toString()),l=f.measureText(e).width,o=o-10,e=(f.fillText(e,a-l/2,o),F?.name||F.user),l=f.measureText(e).width,o=(f.font=Math.min(Math.floor(r/l*16),18)+"px Baloo, FallbackFont",l=f.measureText(e).width,30+h);"space"===n.theme&&(t=a-(F=l+20)/2,f.fillStyle="rgba(0, 0, 0, 0.5)",f.fillRect(t,o-18,F,25)),f.fillStyle=s.textColor,f.fillText(e,a-l/2,o);});}break;case"doughnut":{let t=e.reduce((F,e)=>F+e.level,0),a=Math.min(C,g)/3,o=.6*a,l=-Math.PI/2,r=d.width/2,i=d.height/2;e.map((F,e)=>{F=l+2*Math.PI*(F.level/t),f.fillStyle=s.pieColors[e%s.pieColors.length]||"#FFFFFF",f.beginPath(),f.moveTo(r+a*Math.cos(l),i+a*Math.sin(l)),f.arc(r,i,a,l,F),f.lineTo(r+o*Math.cos(F),i+o*Math.sin(F)),f.arc(r,i,o,F,l,!0),f.closePath(),f.fill(),l=F;});}break;case"pie":{let t=e.reduce((F,e)=>F+e.level,0),a=Math.min(C,g)/3,o=-Math.PI/2,l=d.width/2,r=d.height/2;e.map((F,e)=>{F=o+2*Math.PI*(F.level/t),f.fillStyle=s.pieColors[e%s.pieColors.length]||"#FFFFFF",f.beginPath(),f.moveTo(l,r),f.arc(l,r,a,o,F),f.closePath(),f.fill(),o=F;});}break;default:throw new xplogs_1.XpFatal({function:"charts()",message:"Invalid chart type provided"});}if(["doughnut","pie"].includes(n.type)){let a=d.height-20-20*e.length;f.fillStyle="rgba(0,0,0,0.25)",f.fillRect(15,a-5,200,20*e.length+5),f.font="12px Baloo, FallbackFont",e.map((F,e)=>{var t=s.pieColors[e%s.pieColors.length],e=a+20*e;f.fillStyle=t||"#FFFFFF",f.fillRect(20,e,15,15),f.fillStyle=s.textColor,f.fillText(F?.name||F.user,40,11.5+e);});}return xp_1.xp.auto_clean&&(0,xp_1.clean)(),{attachment:d.toBuffer("image/png"),description:"Chart",name:"chart.png"};}Object.defineProperty(exports,"__esModule",{value:!0}),exports.charts=charts;let xp_1=require("../xp"),xplogs_1=require("./functions/xplogs"),canvas_1=require("@napi-rs/canvas"),cards_1=require("./cards"),path_1=require("path");
@@ -3,7 +3,7 @@ import { Collection } from "mongodb";
3
3
  * Options for creating a user document.
4
4
  * @property {string} collection - The collection to create the document in.
5
5
  * @property {object} data - The data to create the document with.
6
- * @property {string} data.guild - The guild ID.
6
+ * @property {string} [data.guild] - The guild ID.
7
7
  * @property {string} [data.user] - The user ID.
8
8
  * @property {string} [data.name] - The username.
9
9
  * @property {number} [data.level] - The level.
@@ -24,14 +24,15 @@ export interface UserOptions {
24
24
  }
25
25
  /**
26
26
  * The result of a user document.
27
- * @property {string} [_id] - The ID of the document.
27
+ * @property {string} _id - The ID of the document.
28
28
  * @property {string} user - The user ID.
29
- * @property {string} [name] - The username.
29
+ * @property {string} name - The username.
30
30
  * @property {string} guild - The guild ID.
31
- * @property {string} lastUpdated - ISO String of the last time the user was updated.
32
31
  * @property {number} level - The level.
33
32
  * @property {number} xp - The XP.
34
- * @property {number} [xp_rate] - The XP rate.
33
+ * @property {number} xp_rate - The XP rate.
34
+ * @property {string} createdAt - ISO String of the time the user was created.
35
+ * @property {string} lastUpdated - ISO String of the last time the user was updated.
35
36
  */
36
37
  export interface UserResult {
37
38
  _id?: string;
@@ -39,57 +40,67 @@ export interface UserResult {
39
40
  guild: string;
40
41
  user: string;
41
42
  name?: string;
42
- lastUpdated: string;
43
43
  level: number;
44
44
  xp: number;
45
45
  xp_rate?: number;
46
+ createdAt?: string;
47
+ lastUpdated: string;
46
48
  }
47
49
  /**
48
50
  * Options for creating a level role document.
49
51
  * @property {string} collection - The collection to create the document in.
50
52
  * @property {object} data - The data to create the document with.
51
- * @property {string} data.guild - The guild ID.
52
- * @property {object} data.lvlrole - The level role data.
53
- * @property {number} data.lvlrole.lvl - The level.
54
- * @property {string | Array<string>} [data.lvlrole.role] - The role ID(s).
53
+ * @property {string} [data.guild] - The guild ID.
54
+ * @property {object} [data.levelrole] - The level role data.
55
+ * @property {number} [data.levelrole.level] - The level.
56
+ * @property {Array<string>} [data.levelrole.roles] - The role ID(s).
55
57
  */
56
58
  export interface LevelRoleOptions {
57
59
  collection: "simply-xp-levelroles";
58
60
  data: {
59
61
  guild: string;
60
- lvlrole: {
61
- lvl: number | null;
62
- role?: string | Array<string> | null;
62
+ levelrole?: {
63
+ level: number | null;
64
+ roles?: Array<string> | null;
63
65
  };
64
66
  };
65
67
  }
66
68
  /**
67
69
  * The result of a level role document.
68
- * @property {string} [_id] - The ID of the document.
70
+ * @property {string} _id - The ID of the document.
69
71
  * @property {string} guild - The guild ID.
70
- * @property {object} lvlrole - The level role data.
71
- * @property {number} lvlrole.lvl - The level.
72
- * @property {string | Array<string>} [lvlrole.role] - The role ID(s).
72
+ * @property {object} levelrole - V2: The level role data.
73
+ * @property {number} [levelrole.level] - V2: The level.
74
+ * @property {Array<string>} [levelrole.roles] - V2: The role ID(s).
75
+ * @property {string} createdAt - ISO String of the time the level role was created.
73
76
  * @property {string} lastUpdated - ISO String of the last time the level role was updated.
74
77
  */
75
78
  export type LevelRoleResult = {
76
79
  _id?: string;
77
80
  guild: string;
78
- lvlrole: {
79
- lvl: number;
80
- role?: string | Array<string>;
81
+ levelrole: {
82
+ level: number;
83
+ roles?: Array<string>;
81
84
  };
85
+ createdAt?: string;
82
86
  lastUpdated: string;
83
87
  };
88
+ /**
89
+ * Update options for updateOne method.
90
+ * @property {boolean} [upsert] - Whether to insert a new document if no document matches the filter.
91
+ */
92
+ export interface UpdateOptions {
93
+ upsert?: boolean;
94
+ }
84
95
  /**
85
96
  * Database class providing methods to interact with the database.
86
- * @class db
97
+ * @class Database
87
98
  */
88
- export declare class db {
99
+ export declare class Database {
89
100
  /**
90
101
  * Gets a collection from the database.
91
102
  * @param {collection} collection - The collection to get.
92
- * @link https://simplyxp.js.org/docs/next/handlers/database#getCollection Documentation
103
+ * @link `Documentation:` https://simplyxp.js.org/docs/next/Classes/database#getCollection
93
104
  * @returns {Collection} The collection.
94
105
  * @throws {XpFatal} Throws an error if there is no database connection, or database type is invalid.
95
106
  */
@@ -99,7 +110,7 @@ export declare class db {
99
110
  *
100
111
  * @async
101
112
  * @param {UserOptions | LevelRoleOptions} query - The document to create.
102
- * @link https://simplyxp.js.org/docs/next/handlers/database#createOne Documentation
113
+ * @link `Documentation:` https://simplyxp.js.org/docs/next/Classes/database#dbcreateone
103
114
  * @returns {Promise<UserResult | LevelRoleResult>} The created document.
104
115
  * @throws {XpFatal} Throws an error if there is no database connection.
105
116
  */
@@ -108,7 +119,7 @@ export declare class db {
108
119
  * Deletes multiple documents from the database.
109
120
  * @async
110
121
  * @param {UserOptions | LevelRoleOptions} query - The documents to delete.
111
- * @link https://simplyxp.js.org/docs/next/handlers/database#deleteMany Documentation
122
+ * @link https://simplyxp.js.org/docs/next/Classes/database#dbdeletemany Documentation
112
123
  * @returns {Promise<boolean>} `true` if the documents were successfully deleted, otherwise `false`.
113
124
  * @throws {XpFatal} Throws an error if there is no database connection.
114
125
  */
@@ -118,7 +129,7 @@ export declare class db {
118
129
  *
119
130
  * @async
120
131
  * @param {UserOptions | LevelRoleOptions} query - The document to delete.
121
- * @link https://simplyxp.js.org/docs/next/handlers/database#deleteOne Documentation
132
+ * @link `Documentation:` https://simplyxp.js.org/docs/next/Classes/database#dbdeleteone
122
133
  * @returns {Promise<boolean>} `true` if the document was successfully deleted, otherwise `false`.
123
134
  * @throws {XpFatal} Throws an error if there is no database connection.
124
135
  */
@@ -128,7 +139,7 @@ export declare class db {
128
139
  *
129
140
  * @async
130
141
  * @param {UserOptions | LevelRoleOptions} query - The query to search for the document.
131
- * @link https://simplyxp.js.org/docs/next/handlers/database#findOne Documentation
142
+ * @link `Documentation:` https://simplyxp.js.org/docs/next/Classes/database#dbfindone
132
143
  * @returns {Promise<UserResult | LevelRoleResult>} The found document.
133
144
  * @throws {XpFatal} Throws an error if there is no database connection.
134
145
  */
@@ -139,7 +150,7 @@ export declare class db {
139
150
  * @async
140
151
  * @param {"simply-xps" | "simply-xp-levelroles"} collection - The collection to search for multiple documents.
141
152
  * @param {string} guild - The guild ID to search for.
142
- * @link https://simplyxp.js.org/docs/next/handlers/database#find Documentation
153
+ * @link `Documentation:` https://simplyxp.js.org/docs/next/Classes/database#dbfind
143
154
  * @returns {Promise<UserResult[] | LevelRoleResult[]>} An array of found documents.
144
155
  * @throws {XpFatal} Throws an error if there is no database connection.
145
156
  */
@@ -147,7 +158,7 @@ export declare class db {
147
158
  /**
148
159
  * Finds all documents in a collection.
149
160
  * @param {"simply-xps" | "simply-xp-levelroles"} collection - The collection to search for all documents.
150
- * @link https://simplyxp.js.org/docs/next/handlers/database#findAll Documentation
161
+ * @link `Documentation:` https://simplyxp.js.org/docs/next/Classes/database#dbfindall
151
162
  * @returns {Promise<UserResult[] | LevelRoleResult[]>} An array of found documents.
152
163
  * @throws {XpFatal} Throws an error if there is no database connection.
153
164
  */
@@ -158,10 +169,15 @@ export declare class db {
158
169
  * @async
159
170
  * @param {UserOptions | LevelRoleOptions} filter - The document to update.
160
171
  * @param {UserOptions | LevelRoleOptions} update - The document update data.
161
- * @param {object} [options] - MongoDB options for updating the document.
162
- * @link https://simplyxp.js.org/docs/next/handlers/database#updateOne Documentation
172
+ * @param {UpdateOptions} [options] - MongoDB options for updating the document.
173
+ * @link `Documentation:` https://simplyxp.js.org/docs/next/Classes/database#dbupdateone
163
174
  * @returns {Promise<UserResult | LevelRoleResult>} The updated document.
164
175
  * @throws {XpFatal} Throws an error if there is no database connection.
165
176
  */
166
- static updateOne(filter: UserOptions | LevelRoleOptions, update: UserOptions | LevelRoleOptions, options?: object): Promise<UserResult | LevelRoleResult>;
177
+ static updateOne(filter: UserOptions | LevelRoleOptions, update: UserOptions | LevelRoleOptions, options?: UpdateOptions): Promise<UserResult | LevelRoleResult>;
167
178
  }
179
+ /**
180
+ * Exports the `Database` class as `db`.
181
+ * @deprecated Use `Database` class instead, this will be removed in the near future.
182
+ */
183
+ export declare const db: typeof Database;
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Handle database errors
3
+ * @param {Error} error
4
+ * @param {string} functionName
5
+ * @returns {void}
6
+ * @private
7
+ */
8
+ function handleError(e,a){throw new xplogs_1.XpFatal({function:"Database."+a,message:e});}function parseFlags(e){return"flags"in e&&"string"==typeof e.flags&&(e.flags=JSON.parse(e.flags)),e;}Object.defineProperty(exports,"__esModule",{value:!0}),exports.db=exports.Database=void 0;let xplogs_1=require("../functions/xplogs"),xp_1=require("../../xp");class Database{
9
+ /**
10
+ * Gets a collection from the database.
11
+ * @param {collection} collection - The collection to get.
12
+ * @link `Documentation:` https://simplyxp.js.org/docs/next/Classes/database#getCollection
13
+ * @returns {Collection} The collection.
14
+ * @throws {XpFatal} Throws an error if there is no database connection, or database type is invalid.
15
+ */
16
+ static getCollection(e){if(!xp_1.xp.database)throw new xplogs_1.XpFatal({function:"getCollection()",message:"No database connection"});if("mongodb"!==xp_1.xp.dbType)throw new xplogs_1.XpFatal({function:"getCollection()",message:"MongoDB has to be your database type to use this function."});return xp_1.xp.database.db().collection(e);}
17
+ /**
18
+ * Creates one document in the database.
19
+ *
20
+ * @async
21
+ * @param {UserOptions | LevelRoleOptions} query - The document to create.
22
+ * @link `Documentation:` https://simplyxp.js.org/docs/next/Classes/database#dbcreateone
23
+ * @returns {Promise<UserResult | LevelRoleResult>} The created document.
24
+ * @throws {XpFatal} Throws an error if there is no database connection.
25
+ */static async createOne(e){if(!xp_1.xp.database)throw new xplogs_1.XpFatal({function:"createOne()",message:"No database connection"});var a=(new Date).toISOString();switch(xp_1.xp.dbType){case"mongodb":await this.getCollection(e.collection).insertOne({...e.data,createdAt:a,lastUpdated:a}).catch(e=>handleError(e,"createOne()"));break;case"sqlite":"simply-xps"===e.collection?xp_1.xp.database.prepare("INSERT INTO \"simply-xps\" (user, guild, level, name, xp, xp_rate, flags, createdAt, lastUpdated) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)").run(e.data.user,e.data.guild,e.data.level,e.data?.name,e.data.xp,e.data.xp_rate,JSON.stringify(e.data?.flags),a,a):xp_1.xp.database.prepare("INSERT INTO \"simply-xp-levelroles\" (gid, levelrole, createdAt, lastUpdated) VALUES (?, ?, ?, ?)").run(e.data.guild,JSON.stringify(e.data.levelrole),a,a);}return exports.db.findOne(e);}
26
+ /**
27
+ * Deletes multiple documents from the database.
28
+ * @async
29
+ * @param {UserOptions | LevelRoleOptions} query - The documents to delete.
30
+ * @link https://simplyxp.js.org/docs/next/Classes/database#dbdeletemany Documentation
31
+ * @returns {Promise<boolean>} `true` if the documents were successfully deleted, otherwise `false`.
32
+ * @throws {XpFatal} Throws an error if there is no database connection.
33
+ */static async deleteMany(e){if(!xp_1.xp.database)throw new xplogs_1.XpFatal({function:"deleteMany()",message:"No database connection"});let a;switch(xp_1.xp.dbType){case"mongodb":a=await this.getCollection(e.collection).deleteMany(e.data).catch(e=>handleError(e,"deleteMany()"));break;case"sqlite":a=("simply-xps"===e.collection?xp_1.xp.database.prepare("DELETE FROM \"simply-xps\" WHERE guild = ?"):xp_1.xp.database.prepare("DELETE FROM \"simply-xp-levelroles\" WHERE gid = ?")).run(e.data.guild);}return!!a;}
34
+ /**
35
+ * Deletes one document from the database.
36
+ *
37
+ * @async
38
+ * @param {UserOptions | LevelRoleOptions} query - The document to delete.
39
+ * @link `Documentation:` https://simplyxp.js.org/docs/next/Classes/database#dbdeleteone
40
+ * @returns {Promise<boolean>} `true` if the document was successfully deleted, otherwise `false`.
41
+ * @throws {XpFatal} Throws an error if there is no database connection.
42
+ */static async deleteOne(e){if(!xp_1.xp.database)throw new xplogs_1.XpFatal({function:"deleteOne()",message:"No database connection"});switch(xp_1.xp.dbType){case"mongodb":return 0<(await this.getCollection(e.collection).deleteOne(e.data).catch(e=>handleError(e,"deleteOne()"))).deletedCount;case"sqlite":return"simply-xps"===e.collection?0<xp_1.xp.database.prepare("DELETE FROM \"simply-xps\" WHERE guild = ? AND user = ?").run(e.data.guild,e.data.user).changes:0<xp_1.xp.database.prepare("DELETE FROM \"simply-xp-levelroles\" WHERE gid = ? AND levelrole = ?").run(e.data.guild,e.data.levelrole).changes;}}
43
+ /**
44
+ * Finds one document in the database.
45
+ *
46
+ * @async
47
+ * @param {UserOptions | LevelRoleOptions} query - The query to search for the document.
48
+ * @link `Documentation:` https://simplyxp.js.org/docs/next/Classes/database#dbfindone
49
+ * @returns {Promise<UserResult | LevelRoleResult>} The found document.
50
+ * @throws {XpFatal} Throws an error if there is no database connection.
51
+ */static async findOne(e){if(!xp_1.xp.database)throw new xplogs_1.XpFatal({function:"findOne()",message:"No database connection"});switch(xp_1.xp.dbType){case"mongodb":return this.getCollection(e.collection).findOne(e.data).catch(e=>handleError(e,"findOne()"));case"sqlite":var a;return"simply-xps"===e.collection?xp_1.xp.database.prepare("SELECT * FROM \"simply-xps\" WHERE guild = ? AND user = ?").get(e.data.guild,e.data.user):(e.data.levelrole||handleError(new Error("levelrole is undefined"),"findOne()"),(a=xp_1.xp.database.prepare("SELECT * FROM \"simply-xp-levelroles\" WHERE gid = ? AND json_extract(levelrole, '$.level') = ?").get(e.data.guild,e.data.levelrole.level))?(a.levelrole=JSON.parse(a.levelrole),a):null);}}
52
+ /**
53
+ * Finds multiple documents in the database.
54
+ *
55
+ * @async
56
+ * @param {"simply-xps" | "simply-xp-levelroles"} collection - The collection to search for multiple documents.
57
+ * @param {string} guild - The guild ID to search for.
58
+ * @link `Documentation:` https://simplyxp.js.org/docs/next/Classes/database#dbfind
59
+ * @returns {Promise<UserResult[] | LevelRoleResult[]>} An array of found documents.
60
+ * @throws {XpFatal} Throws an error if there is no database connection.
61
+ */static async find(e,a){if(!xp_1.xp.database)throw new xplogs_1.XpFatal({function:"find()",message:"No database connection"});switch(xp_1.xp.dbType){case"mongodb":return xp_1.xp.database.db().collection(e).find({guild:a}).toArray().catch(e=>handleError(e,"find()"));case"sqlite":return"simply-xps"===e?xp_1.xp.database.prepare("SELECT * FROM \"simply-xps\" WHERE guild = ?").all(a).map(e=>parseFlags(e)):xp_1.xp.database.prepare("SELECT * FROM \"simply-xp-levelroles\" WHERE gid = ?").all(a).map(e=>(e.levelrole&&"string"==typeof e.levelrole&&(e.levelrole=JSON.parse(e.levelrole)),e));}}
62
+ /**
63
+ * Finds all documents in a collection.
64
+ * @param {"simply-xps" | "simply-xp-levelroles"} collection - The collection to search for all documents.
65
+ * @link `Documentation:` https://simplyxp.js.org/docs/next/Classes/database#dbfindall
66
+ * @returns {Promise<UserResult[] | LevelRoleResult[]>} An array of found documents.
67
+ * @throws {XpFatal} Throws an error if there is no database connection.
68
+ */static async findAll(e){if(!xp_1.xp.database)throw new xplogs_1.XpFatal({function:"findAll()",message:"No database connection"});switch(xp_1.xp.dbType){case"mongodb":return xp_1.xp.database.db().collection(e).find().toArray().catch(e=>handleError(e,"findAll()"));case"sqlite":return"simply-xps"===e?xp_1.xp.database.prepare("SELECT * FROM \"simply-xps\"").all().map(e=>parseFlags(e)):xp_1.xp.database.prepare("SELECT * FROM \"simply-xp-levelroles\"").all();}}
69
+ /**
70
+ * Updates one document in the database.
71
+ *
72
+ * @async
73
+ * @param {UserOptions | LevelRoleOptions} filter - The document to update.
74
+ * @param {UserOptions | LevelRoleOptions} update - The document update data.
75
+ * @param {UpdateOptions} [options] - MongoDB options for updating the document.
76
+ * @link `Documentation:` https://simplyxp.js.org/docs/next/Classes/database#dbupdateone
77
+ * @returns {Promise<UserResult | LevelRoleResult>} The updated document.
78
+ * @throws {XpFatal} Throws an error if there is no database connection.
79
+ */static async updateOne(e,a,t){var l,s,p,n,o,r;if(!xp_1.xp.database)throw new xplogs_1.XpFatal({function:"updateOne()",message:"No database connection"});switch(xp_1.xp.dbType){case"mongodb":await this.getCollection(a.collection).updateOne(e.data,{$set:{...a.data,lastUpdated:(new Date).toISOString()}},t).catch(e=>handleError(e,"updateOne()"));break;case"sqlite":if(e.collection!==a.collection)throw new xplogs_1.XpFatal({function:"updateOne()",message:"Collection mismatch, expected same collection on both filter and update."});if(s=[],p=[],n=(new Date).toISOString(),"simply-xps"===a.collection){for(l of["level","name","xp","xp_rate","flags"])void 0!==(o=a.data[l])&&(s.push(l+" = ?"),p.push("flags"===l?JSON.stringify(o):o));s.push("lastUpdated = ?"),p.push(n),r=[e.data.guild,e.data.user],p.push(...r),r=xp_1.xp.database.prepare(`UPDATE "simply-xps" SET ${s.join(", ")} WHERE guild = ? AND user = ?`).run(...p),t?.upsert&&0===r.changes&&Database.createOne({collection:"simply-xps",data:{guild:e.data.guild,user:e.data.user,name:a.data.name||e.data.user,level:a.data.level||0,xp:a.data.xp||0,xp_rate:a.data.xp_rate||xp_1.xp.xp_rate,flags:a.data.flags||[]}});}else"simply-xp-levelroles"===a.collection&&(s.push("levelrole = ?","lastUpdated = ?"),p.push(JSON.stringify(a.data.levelrole),n),r=[e.data.guild,JSON.stringify(e.data.levelrole)],p.push(...r),n=xp_1.xp.database.prepare(`UPDATE "simply-xp-levelroles" SET ${s.join(", ")} WHERE gid = ? AND levelrole = ?`).run(...p),t?.upsert)&&0===n.changes&&Database.createOne({collection:"simply-xp-levelroles",data:{guild:e.data.guild,levelrole:a.data.levelrole}});}return exports.db.findOne(a);}}exports.Database=Database,exports.db=Database;