Compare commits

...

2 commits

Author SHA1 Message Date
Slincnik
9f82e45a67
feat: new client, commands handlers 2024-12-05 19:13:43 +03:00
484364ba8f modules yipee 2024-12-05 20:15:07 +05:00
52 changed files with 938 additions and 1661 deletions

3
.gitignore vendored
View file

@ -13,6 +13,3 @@ Thumbs.db
# Node
node_modules
# Dashboard DB
/json.sqlite

4
.gitmodules vendored
View file

@ -1,4 +0,0 @@
[submodule "dashboard/dashboard-core"]
path = dashboard/dashboard-core
url = https://git.jonnybro.ru/jonny_bro/dashboard-core
branch = main

View file

@ -15,7 +15,6 @@ JaBa offers:
* Slash and Context commands.
* Supports commands in DMs.
* Localization support (any language; English, Russian and Ukrainian for now).
* Dashboard for changing various settings.
* Basic messages monitoring (updating and deletion).
## Commands
@ -30,10 +29,6 @@ JaBa does many thing, here is **8 main categories**:
* **General**: `afk`, `avatar`, `boosters`, `minecraft`, `remindme`, `shorturl`, `serverinfo`, `userinfo`, `whois` and **7** more!
* **Bot's owner commands**: `eval`, `servers`, `reload` and **2** more!
## *Kinda* Cool Dashboard
JaBa has it's own dashboard to change server's settings!
## Get The Bot
### Ready To Use
@ -54,7 +49,6 @@ Use [this instruction](https://github.com/JonnyBro/JaBa/wiki/Self-Hosting) to le
* [Full commands list](https://dash.jababot.ru/commands)
* [Discord](https://discord.gg/Ptkj2n9nzZ)
* [Github](https://github.com/JonnyBro/JaBa/)
* [Dashboard](https://dash.jababot.ru)
## Support
@ -64,7 +58,7 @@ If you want to contribute, feel free to fork this repo and making a pull request
## TODO
* [ ] Refactor [tictactoe](./helpers/tictactoe.js).
* [ ] Finish and release *dashboard-core* submodule.
* [ ] Rewrite dashboard.
## License

View file

@ -11,4 +11,4 @@ class BaseEvent {
}
}
module.exports = BaseEvent;
export default BaseEvent;

View file

@ -1,32 +1,41 @@
const { Client, Collection, SlashCommandBuilder, ContextMenuCommandBuilder, EmbedBuilder, PermissionsBitField, ChannelType } = require("discord.js"),
{ GiveawaysManager } = require("discord-giveaways"),
{ REST } = require("@discordjs/rest"),
{ Player: DiscordPlayer } = require("discord-player"),
{ SpotifyExtractor } = require("@discord-player/extractor"),
{ YoutubeiExtractor } = require("discord-player-youtubei"),
{ Routes } = require("discord-api-types/v10");
import { Client, Collection, SlashCommandBuilder, ContextMenuCommandBuilder, EmbedBuilder, PermissionsBitField, ChannelType } from "discord.js";
import { GiveawaysManager } from "discord-giveaways";
import { REST } from "@discordjs/rest";
import { Player } from "discord-player";
import { SpotifyExtractor } from "@discord-player/extractor";
import { YoutubeiExtractor } from "discord-player-youtubei";
import { Routes } from "discord-api-types/v10";
import { join, sep } from "path";
import { promises as fs } from "fs";
import { setTimeout } from "timers/promises";
import mongoose from "mongoose";
const BaseEvent = require("./BaseEvent.js"),
BaseCommand = require("./BaseCommand.js").default,
path = require("path"),
fs = require("fs").promises,
mongoose = require("mongoose");
import config from "../config.js";
import * as emojis from "../emojis.json";
import langs from "../languages/language-meta.js";
import logger from "../helpers/logger.js";
import * as funcs from "../helpers/functions.js";
import BaseEvent from "./BaseEvent.js";
import BaseCommand from "./BaseCommand.js";
import guild from "./Guild.js";
import user from "./User.js";
import member from "./Member.js";
class JaBaClient extends Client {
constructor(options) {
super(options);
this.config = require("../config");
this.customEmojis = require("../emojis");
this.languages = require("../languages/language-meta");
this.config = config;
this.customEmojis = emojis;
this.languages = langs;
this.commands = new Collection();
this.logger = require("../helpers/logger");
this.wait = require("node:timers/promises").setTimeout;
this.functions = require("../helpers/functions");
this.guildsData = require("../base/Guild");
this.usersData = require("../base/User");
this.membersData = require("../base/Member");
this.dashboard = require("../dashboard/dashboard");
this.logger = logger;
this.wait = setTimeout;
this.functions = funcs;
this.guildsData = guild.default;
this.usersData = user.default;
this.membersData = member.default;
this.databaseCache = {};
this.databaseCache.users = new Collection();
@ -43,7 +52,7 @@ class JaBaClient extends Client {
* @returns {Promise<void>} A Promise that resolves when the client is fully initialized.
*/
async init() {
this.player = new DiscordPlayer(this);
this.player = new Player(this);
await this.player.extractors.register(YoutubeiExtractor, {
authentication: this.config.youtubeCookie,
@ -74,13 +83,13 @@ class JaBaClient extends Client {
})
).id;
if (track.durationMS > 1)
if (track.durationMS > 1) {
setTimeout(() => {
const message = queue.metadata.channel.messages.cache.get(m);
if (message && message.deletable) message.delete();
}, track.durationMS);
else
} else {
setTimeout(
() => {
const message = queue.metadata.channel.messages.cache.get(m);
@ -89,6 +98,7 @@ class JaBaClient extends Client {
},
5 * 60 * 1000,
);
}
});
this.player.events.on("emptyQueue", queue => queue.metadata.channel.send(this.translate("music/play:QUEUE_ENDED", null, queue.metadata.data.guild.language)));
this.player.events.on("emptyChannel", queue => queue.metadata.channel.send(this.translate("music/play:STOP_EMPTY", null, queue.metadata.data.guild.language)));
@ -113,9 +123,7 @@ class JaBaClient extends Client {
mongoose
.connect(this.config.mongoDB)
.then(() => {
this.logger.log("Connected to the MongoDB database.");
})
.then(this.logger.log("Connected to the MongoDB database."))
.catch(e => {
this.logger.error(`Unable to connect to the MongoDB database.\nError: ${e.message}\n${e.stack}`);
});
@ -134,8 +142,8 @@ class JaBaClient extends Client {
*/
async loadCommands(dir) {
const rest = new REST().setToken(this.config.token),
filePath = path.join(__dirname, dir),
folders = (await fs.readdir(filePath)).map(file => path.join(filePath, file));
filePath = join(__dirname, dir),
folders = (await fs.readdir(filePath)).map(file => join(filePath, file));
const commands = [];
for (const folder of folders) {
@ -144,7 +152,7 @@ class JaBaClient extends Client {
for (const file of files) {
if (!file.endsWith(".js")) continue;
const Command = require(path.join(folder, file));
const Command = require(join(folder, file));
if (!(Command.prototype instanceof BaseCommand)) continue;
@ -165,8 +173,8 @@ class JaBaClient extends Client {
await rest.put(route, { body: commands });
this.logger.log("Successfully registered application commands.");
} catch (err) {
this.logger.error("Error registering application commands:", err);
} catch (e) {
this.logger.error("Error registering application commands:", e);
}
}
@ -178,7 +186,7 @@ class JaBaClient extends Client {
*/
async loadCommand(dir, file) {
try {
const Command = require(path.join(dir, `${file}.js`));
const Command = require(join(dir, `${file}.js`));
if (!(Command.prototype instanceof BaseCommand)) {
return this.logger.error(`Tried to load a non-command file: "${file}.js"`);
@ -190,8 +198,8 @@ class JaBaClient extends Client {
if (typeof command.onLoad === "function") await command.onLoad(this);
this.logger.log(`Successfully loaded "${file}" command file. (Command: ${command.command.name})`);
} catch (error) {
this.logger.error(`Error loading command "${file}":`, error);
} catch (e) {
this.logger.error(`Error loading command "${file}":`, e);
}
}
@ -202,7 +210,7 @@ class JaBaClient extends Client {
* @returns {void} This method does not return a value.
*/
unloadCommand(dir, name) {
delete require.cache[require.resolve(`${dir}${path.sep}${name}.js`)];
delete require.cache[require.resolve(`${dir}${sep}${name}.js`)];
return;
}
@ -213,15 +221,15 @@ class JaBaClient extends Client {
* @returns {Promise<void>} This method does not return a value.
*/
async loadEvents(dir) {
const filePath = path.join(__dirname, dir);
const filePath = join(__dirname, dir);
const files = await fs.readdir(filePath);
for (const file of files) {
const fullPath = path.join(filePath, file);
const fullPath = join(filePath, file);
const stat = await fs.lstat(fullPath);
if (stat.isDirectory()) {
await this.loadEvents(path.join(dir, file));
await this.loadEvents(join(dir, file));
continue;
}
@ -244,8 +252,8 @@ class JaBaClient extends Client {
event.once ? this.once(event.name, event.execute.bind(event, this)) : this.on(event.name, event.execute.bind(event, this));
this.logger.log(`Successfully loaded "${file}" event. (Event: ${event.name})`);
} catch (error) {
this.logger.error(`Error loading event "${file}":`, error);
} catch (e) {
this.logger.error(`Error loading event "${file}":`, e);
}
}
}
@ -348,6 +356,7 @@ class JaBaClient extends Client {
await memberData.save();
const guildData = await this.getGuildData(guildId);
if (guildData) {
guildData.members.push(memberData._id);
await guildData.save();
@ -377,4 +386,4 @@ class JaBaClient extends Client {
}
}
module.exports = JaBaClient;
export default JaBaClient;

View file

@ -1,55 +1,57 @@
const mongoose = require("mongoose"),
Schema = mongoose.Schema,
languages = require("../languages/language-meta.json");
import { model, Schema } from "mongoose";
import { langs } from "../languages/language-meta.js";
module.exports = mongoose.model("Guild", new Schema({
id: { type: String },
export default model(
"Guild",
new Schema({
id: { type: String },
membersData: { type: Object, default: {} },
members: [{ type: Schema.Types.ObjectId, ref: "Member" }],
membersData: { type: Object, default: {} },
members: [{ type: Schema.Types.ObjectId, ref: "Member" }],
language: { type: String, default: languages.find(l => l.default).name },
plugins: {
type: Object,
default: {
welcome: {
enabled: false,
message: null,
channel: null,
withImage: null,
language: { type: String, default: langs.find(l => l.default).name },
plugins: {
type: Object,
default: {
welcome: {
enabled: false,
message: null,
channel: null,
withImage: null,
},
goodbye: {
enabled: false,
message: null,
channel: null,
withImage: null,
},
autorole: {
enabled: false,
role: null,
},
automod: {
enabled: false,
ignored: [],
},
warnsSanctions: {
kick: null,
ban: null,
},
monitoring: {
messageUpdate: null,
messageDelete: null,
},
tickets: {
count: 0,
ticketLogs: null,
transcriptionLogs: null,
ticketsCategory: null,
},
suggestions: null,
reports: null,
birthdays: null,
modlogs: null,
},
goodbye: {
enabled: false,
message: null,
channel: null,
withImage: null,
},
autorole: {
enabled: false,
role: null,
},
automod: {
enabled: false,
ignored: [],
},
warnsSanctions: {
kick: null,
ban: null,
},
monitoring: {
messageUpdate: null,
messageDelete: null,
},
tickets: {
count: 0,
ticketLogs: null,
transcriptionLogs: null,
ticketsCategory: null,
},
suggestions: null,
reports: null,
birthdays: null,
modlogs: null,
},
},
}));
}),
);

View file

@ -1,33 +1,36 @@
const mongoose = require("mongoose");
import { model, Schema } from "mongoose";
module.exports = mongoose.model("Member", new mongoose.Schema({
id: { type: String },
guildID: { type: String },
export default model(
"Member",
new Schema({
id: { type: String },
guildID: { type: String },
money: { type: Number, default: 0 },
workStreak: { type: Number, default: 0 },
bankSold: { type: Number, default: 0 },
exp: { type: Number, default: 0 },
level: { type: Number, default: 0 },
transactions: { type: Array, default: [] },
money: { type: Number, default: 0 },
workStreak: { type: Number, default: 0 },
bankSold: { type: Number, default: 0 },
exp: { type: Number, default: 0 },
level: { type: Number, default: 0 },
transactions: { type: Array, default: [] },
registeredAt: { type: Number, default: Date.now() },
registeredAt: { type: Number, default: Date.now() },
cooldowns: {
type: Object,
default: {
work: 0,
rob: 0,
cooldowns: {
type: Object,
default: {
work: 0,
rob: 0,
},
},
},
sanctions: { type: Array, default: [] },
mute: {
type: Object,
default: {
muted: false,
case: null,
endDate: null,
sanctions: { type: Array, default: [] },
mute: {
type: Object,
default: {
muted: false,
case: null,
endDate: null,
},
},
},
}));
}),
);

View file

@ -1,5 +1,5 @@
const mongoose = require("mongoose"),
Canvas = require("@napi-rs/canvas");
import { Schema, model } from "mongoose";
import { createCanvas, loadImage } from "@napi-rs/canvas";
const genToken = () => {
let token = "";
@ -9,7 +9,7 @@ const genToken = () => {
return token;
};
const userSchema = new mongoose.Schema({
const userSchema = new Schema({
id: { type: String },
rep: { type: Number, default: 0 },
@ -88,17 +88,17 @@ const userSchema = new mongoose.Schema({
});
userSchema.method("getAchievements", async function () {
const canvas = Canvas.createCanvas(1800, 250),
const canvas = createCanvas(1800, 250),
ctx = canvas.getContext("2d");
const images = [
await Canvas.loadImage(`./assets/img/achievements/achievement${this.achievements.work.achieved ? "_colored" : ""}1.png`),
await Canvas.loadImage(`./assets/img/achievements/achievement${this.achievements.firstCommand.achieved ? "_colored" : ""}2.png`),
await Canvas.loadImage(`./assets/img/achievements/achievement${this.achievements.married.achieved ? "_colored" : ""}3.png`),
await Canvas.loadImage(`./assets/img/achievements/achievement${this.achievements.slots.achieved ? "_colored" : ""}4.png`),
await Canvas.loadImage(`./assets/img/achievements/achievement${this.achievements.tip.achieved ? "_colored" : ""}5.png`),
await Canvas.loadImage(`./assets/img/achievements/achievement${this.achievements.rep.achieved ? "_colored" : ""}6.png`),
await Canvas.loadImage(`./assets/img/achievements/achievement${this.achievements.invite.achieved ? "_colored" : ""}7.png`),
await loadImage(`./assets/img/achievements/achievement${this.achievements.work.achieved ? "_colored" : ""}1.png`),
await loadImage(`./assets/img/achievements/achievement${this.achievements.firstCommand.achieved ? "_colored" : ""}2.png`),
await loadImage(`./assets/img/achievements/achievement${this.achievements.married.achieved ? "_colored" : ""}3.png`),
await loadImage(`./assets/img/achievements/achievement${this.achievements.slots.achieved ? "_colored" : ""}4.png`),
await loadImage(`./assets/img/achievements/achievement${this.achievements.tip.achieved ? "_colored" : ""}5.png`),
await loadImage(`./assets/img/achievements/achievement${this.achievements.rep.achieved ? "_colored" : ""}6.png`),
await loadImage(`./assets/img/achievements/achievement${this.achievements.invite.achieved ? "_colored" : ""}7.png`),
];
let dim = 0;
@ -107,7 +107,7 @@ userSchema.method("getAchievements", async function () {
dim += 200;
}
return (await canvas.encode("png"));
return await canvas.encode("png");
});
module.exports = mongoose.model("User", userSchema);
export default model("User", userSchema);

57
base/newClient.js Normal file
View file

@ -0,0 +1,57 @@
import { Client, Collection, REST, Routes } from "discord.js";
import { config } from "../config.js";
import { glob } from "glob";
import { dirname } from "node:path";
export class ExtendedClient extends Client {
commands = new Collection();
__dirname = dirname(new URL(import.meta.url).pathname);
rest = new REST().setToken(config.token);
/**
* @param {import("discord.js").ClientOptions} options
*/
constructor(options) {
super(options);
}
init() {
this.registerModules();
this.login(config.token);
}
async importFile(filePath) {
return (await import(`file://${filePath}`))?.default;
}
async registerModules() {
await this.registerCommands(this.__dirname);
}
async registerCommands(baseDir) {
const commandFiles = await glob(`${baseDir}/../newCommands/*/*.js`);
const slashCommands = [];
for (const filePath of commandFiles) {
try {
const command = await this.importFile(filePath);
if (!command.data.name) return;
this.commands.set(command.data.name, command);
slashCommands.push(command.data.toJSON());
} catch (error) {
console.error(`Error loading command ${filePath}:`, error);
}
}
if (!slashCommands.length) return;
try {
const route = config.production ? Routes.applicationCommands(config.userId) : Routes.applicationGuildCommands(config.userId, config.support.id);
const data = await this.rest.put(route, { body: slashCommands });
console.log(`Successfully registered ${data.length} application commands.`);
} catch (error) {
console.log(error);
}
}
}

18
base/newCommand.js Normal file
View file

@ -0,0 +1,18 @@
export default class Command {
constructor(options) {
/**
* @type {import("discord.js").ApplicationCommandData}
*/
this.data = options.data;
/**
* @type {Boolean}
*/
this.ownerOnly = !!options.ownerOnly || false;
/**
* @param {import("discord.js").CommandInteraction} [interaction]
* @param {import('./newClient.js').ExtendedClient} [client]
* @param {import("discord.js").CommandInteractionOptionResolver} [args]
*/
this.execute = function () {};
}
}

View file

@ -103,7 +103,8 @@ class Config extends BaseCommand {
? interaction.translate("administration/config:WELCOME_CONTENT", {
channel: `<#${guildData.plugins.welcome.channel}>`,
withImage: guildData.plugins.welcome.withImage ? interaction.translate("common:YES") : interaction.translate("common:NO"),
}) : interaction.translate("common:DISABLED"),
})
: interaction.translate("common:DISABLED"),
inline: true,
},
{
@ -112,7 +113,8 @@ class Config extends BaseCommand {
? interaction.translate("administration/config:GOODBYE_CONTENT", {
channel: `<#${guildData.plugins.goodbye.channel}>`,
withImage: guildData.plugins.goodbye.withImage ? interaction.translate("common:YES") : interaction.translate("common:NO"),
}) : interaction.translate("common:DISABLED"),
})
: interaction.translate("common:DISABLED"),
inline: true,
},
{
@ -125,19 +127,22 @@ class Config extends BaseCommand {
(guildData.plugins.warnsSanctions.kick
? interaction.translate("administration/config:KICK_CONTENT", {
count: guildData.plugins.warnsSanctions.kick,
}) : interaction.translate("administration/config:KICK_NOT_DEFINED")) +
})
: interaction.translate("administration/config:KICK_NOT_DEFINED")) +
"\n" +
(guildData.plugins.warnsSanctions.ban
? interaction.translate("administration/config:BAN_CONTENT", {
count: guildData.plugins.warnsSanctions.ban,
}) : interaction.translate("administration/config:BAN_NOT_DEFINED")),
})
: interaction.translate("administration/config:BAN_NOT_DEFINED")),
},
{
name: interaction.translate("administration/config:AUTOMOD_TITLE"),
value: guildData.plugins.automod.enabled
? interaction.translate("administration/config:AUTOMOD_CONTENT", {
channels: guildData.plugins.automod.ignored.map(ch => ` ${ch}`),
}) : interaction.translate("common:DISABLED"),
})
: interaction.translate("common:DISABLED"),
},
{
name: interaction.translate("administration/config:MONITORING_CHANNELS"),
@ -156,10 +161,6 @@ class Config extends BaseCommand {
`${interaction.translate("administration/config:TICKETLOGS")}: ${guildData.plugins?.tickets?.ticketLogs ? `<#${guildData.plugins?.tickets?.ticketLogs}>` : `*${interaction.translate("common:NOT_DEFINED")}*`}\n` +
`${interaction.translate("administration/config:TRANSCRIPTIONLOGS")}: ${guildData.plugins?.tickets?.transcriptionLogs ? `<#${guildData.plugins?.tickets?.transcriptionLogs}>` : `*${interaction.translate("common:NOT_DEFINED")}*`}\n`,
},
{
name: interaction.translate("administration/config:DASHBOARD_TITLE"),
value: `[${interaction.translate("administration/config:DASHBOARD_CONTENT")}](${client.config.dashboard.domain})`,
},
],
});
@ -215,13 +216,14 @@ async function changeSetting(interaction, setting, state, channel) {
content: `${interaction.translate(`administration/config:${settingSplitted.length === 2 ? settingSplitted[1].toUpperCase() : setting.toUpperCase()}`)}: **${interaction.translate("common:ENABLED")}** (${channel.toString()})`,
ephemeral: true,
});
} else
} else {
return interaction.reply({
content: `${interaction.translate(`administration/config:${settingSplitted.length === 2 ? settingSplitted[1].toUpperCase() : setting.toUpperCase()}`)}: ${
data.plugins[setting] ? `**${interaction.translate("common:ENABLED")}** (<#${data.plugins[setting]}>)` : `**${interaction.translate("common:DISABLED")}**`
}`,
ephemeral: true,
});
}
}
} else {
if (!state) {
@ -245,13 +247,14 @@ async function changeSetting(interaction, setting, state, channel) {
content: `${interaction.translate(`administration/config:${setting.toUpperCase()}`)}: **${interaction.translate("common:ENABLED")}** (${channel.toString()})`,
ephemeral: true,
});
} else
} else {
return interaction.reply({
content: `${interaction.translate(`administration/config:${setting.toUpperCase()}`)}: ${
data.plugins[setting] ? `**${interaction.translate("common:ENABLED")}** (<#${data.plugins[setting]}>)` : `**${interaction.translate("common:DISABLED")}**`
}`,
ephemeral: true,
});
}
}
}
}

View file

@ -91,7 +91,6 @@ class Stats extends BaseCommand {
{
name: client.customEmojis.link + " " + interaction.translate("general/stats:LINKS_TITLE"),
value: interaction.translate("misc:STATS_FOOTER", {
dashboardLink: client.config.dashboard.domain,
supportLink: "https://discord.gg/Ptkj2n9nzZ",
inviteLink: client.generateInvite({ scopes: ["bot", "applications.commands"], permissions: [PermissionsBitField.Flags.Administrator] }),
owner: client.config.owner.id,

View file

@ -1,4 +1,4 @@
export const config = {
export default {
/* The token of your Discord Bot */
token: "XXXXXXXXXXXXXXXXXXXXXXXXXXXX",
/* UserID of your Discord Bot */
@ -22,19 +22,23 @@ export const config = {
invite: "https://discord.gg/discord", // Invite link to the support server
},
/* Dashboard configuration */
dashboard: {
/* dashboard: {
enabled: false, // Whether the dashboard is enabled or not
maintanceKey: "letmein", // Maintance key
port: 80, // Dashboard port
domain: "http://localhost", // The base URL of the dashboard without / at the end
secret: "XXXXXXXXXXXXXXXXXXXXXXXXXXXX", // Your Bot's Client Secret
logs: "123456789098765432", // The channel ID for logs
},
}, */
/* Embeds defaults */
embed: {
color: "#00FF00", // Color
footer: {
text: "My Discord Bot | v" + require("./package.json").version, // Footer text
text:
"My Discord Bot | v" +
import("./package.json", {
with: { type: "json" },
}).version, // Footer text
},
},
/* Bot's owner informations */

@ -1 +0,0 @@
Subproject commit 42cb44000f844f17b0d9e12e15a45ab60f3dcdb7

View file

@ -1,221 +0,0 @@
const SoftUI = require("./dashboard-core/theme/dbd-soft-ui"),
DBD = require("./dashboard-core/index"),
settings = require("./settings");
const { PermissionsBitField } = require("discord.js");
const locales = {
"en-US": require("../languages/en-US/dashboard.json"),
"ru-RU": require("../languages/ru-RU/dashboard.json"),
"uk-UA": require("../languages/uk-UA/dashboard.json"),
};
/**
*
* @param {import("../base/Client")} client
*/
module.exports.load = async client => {
const commands = client.commands.map(v => {
return {
commandName: v.command.name,
commandDescription: client.translate(`${v.category.toLowerCase()}/${v.command.name}:DESCRIPTION`),
commandUsage: client.translate(`${v.category.toLowerCase()}/${v.command.name}:USAGE`),
commandAlias: "",
_category: v.category,
};
});
let categories = [];
commands.forEach(c => {
if (!categories.includes(c._category)) categories.push(c._category);
});
categories = categories.map(c => {
return {
category: c,
categoryId: c.toLowerCase(),
subTitle: "",
hideAlias: true,
hideDescription: false,
hideSidebarItem: c === "Owner" || c === "IAT" ? true : false,
list: commands.filter(v => v._category === c),
};
});
const Dashboard = new DBD.Dashboard({
port: client.config.dashboard.port,
client: {
id: client.user.id,
secret: client.config.dashboard.secret,
},
cookiesSecret: client.config.dashboard.secret,
domain: client.config.dashboard.domain,
redirectUri: `${client.config.dashboard.domain}/discord/callback`,
bot: client,
ownerIDs: [client.config.owner.id],
requiredPermissions: PermissionsBitField.Flags.ViewChannel,
invite: {
clientId: client.user.id,
scopes: ["bot", "applications.commands"],
permissions: "8",
redirectUri: `${client.config.dashboard.domain}`,
},
supportServer: {
slash: "/support",
inviteUrl: client.config.support.invite,
},
rateLimits: {
manage: {
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
message: "You are ratelimited!", // Message returned if user should be rate limited, could be also JSON/HTML
store: null, // <Rate Limiter Store> - if null, new MemoryStore()
// supported stores: https://www.npmjs.com/package/express-rate-limit#store
},
guildPage: {
windowMs: 15 * 60 * 1000,
max: 100,
message: "You are ratelimited!",
store: null,
},
settingsUpdatePostAPI: {
windowMs: 15 * 60 * 1000,
max: 100,
message: "You are ratelimited!",
store: null,
},
},
useTheme404: true,
useThemeMaintenance: true,
useUnderMaintenance: false,
underMaintenanceAccessKey: client.config.dashboard.maintanceKey,
underMaintenanceAccessPage: "/get-access",
underMaintenance: {
title: "Under Maintenance",
contentTitle: "This page is under maintenance",
texts: [
"<br>",
"We still want to change for the better for you.",
"Therefore, we are introducing technical updates so that we can allow you to enjoy the quality of our services.",
"<br>",
`Come back to us later or join our <a href="${client.config.support.invite}">Discord Support Server</a>`,
],
},
theme: SoftUI({
customThemeOptions: {
// eslint-disable-next-line no-unused-vars
index: async ({ req, res, config }) => {
const user = req.session?.user;
const username = (user?.discriminator === "0" ? user?.username : user?.tag) || "Guest";
let users = 0;
client.guilds.cache.forEach(g => {
users += g.memberCount;
});
const cards = [
{
title: "Current User",
icon: "single-02",
getValue: username,
},
{
title: "Playing music in this much servers",
icon: "settings-gear-65",
getValue: client.player.nodes.cache.size,
},
{
title: "Users Count",
icon: "favourite-28",
getValue: users,
},
{
title: "Servers Count",
icon: "notification-70",
getValue: `${client.guilds.cache.size - 1} out of 2000`,
progressBar: {
enabled: true,
getProgress: Math.round(((client.guilds.cache.size - 1) / 2000) * 100),
},
},
];
return {
values: [],
graph: {},
cards,
};
},
},
websiteName: `${client.user.username} Dashboard`,
colorScheme: "blue",
supporteMail: "",
icons: {
favicon: client.user.avatarURL(),
noGuildIcon: "https://pnggrid.com/wp-content/uploads/2021/05/Discord-Logo-Circle-1024x1024.png",
sidebar: {
darkUrl: client.user.avatarURL(),
lightUrl: client.user.avatarURL(),
hideName: false,
borderRadius: "1rem",
alignCenter: true,
},
},
index: {
card: {
category: "JaBa Bot",
title: "Simple bot made by <a href=\"https://github.com/JonnyBro\">Jonny_Bro</a>",
description: "JaBa's dashboard",
image: "",
link: {
enabled: false,
url: "https://github.com/JonnyBro",
},
},
graph: {
enabled: false,
lineGraph: true,
title: "Memory Usage",
tag: "Memory (MB)",
max: 100,
},
},
notify: {
errors: {
settingsSave: "Failed to save setttings",
},
success: {
settingsSave: "Successfully saved setttings.",
login: "Successfully logged in.",
logout: "Successfully logged out.",
},
},
preloader: {
image: "",
spinner: true,
text: "Page is loading",
},
commands: categories,
locales: {
enUS: locales["en-US"],
ruRU: locales["ru-RU"],
ukUA: locales["uk-UA"],
},
}),
customPages: [
DBD.customPagesTypes.redirectToUrl("/github", () => {
return "https://github.com/JonnyBro/JaBa";
}),
DBD.customPagesTypes.redirectToUrl("/updates", () => {
return "https://github.com/JonnyBro/JaBa/blob/main/dashboard/docs/updates.md";
}),
],
settings: settings(client),
});
await Dashboard.init().then(() => {
client.logger.ready(`Dashboard launched on port ${client.config.dashboard.port}`);
}).catch(err => {
client.logger.error(`Dashboard failed to initialize:\n${err}`);
});
};

View file

@ -1,459 +0,0 @@
const SoftUI = require("./dashboard-core/theme/dbd-soft-ui"),
DBD = require("./dashboard-core/index");
const { PermissionsBitField, ChannelType } = require("discord.js");
module.exports = client => [
{
categoryId: "main",
categoryName: "Main settings",
categoryDescription: "Setup your bot here!",
categoryPermissions: PermissionsBitField.Flags.ManageGuild,
categoryOptionsList: [
{
optionId: "lang",
optionName: "Language",
optionDescription: "Change bot's language on the server",
optionType: DBD.formTypes.select({
English: "en-US",
Russian: "ru-RU",
Ukrainian: "uk-UA",
}),
getActualSet: async ({ guild }) => {
const guildData = await client.getGuildData(guild.id);
return guildData.language;
},
setNew: async ({ guild, newData }) => {
const guildData = await client.getGuildData(guild.id);
guildData.language = newData;
await guildData.save();
return;
},
},
{
optionId: "welcome",
optionName: "Welcome Message",
optionDescription: "Setup welcome message on the server",
optionType: SoftUI.formTypes.multiRow([
{
optionId: "welcome_enable",
optionName: "Enabled",
optionDescription: "Toggle welcome messages sending",
optionType: DBD.formTypes.switch(),
getActualSet: async ({ guild }) => {
const guildData = await client.getGuildData(guild.id);
return guildData.plugins.welcome.enabled;
},
setNew: async ({ guild, newData }) => {
const guildData = await client.getGuildData(guild.id);
guildData.plugins.welcome.enabled = newData;
await guildData.save();
return;
},
},
{
optionId: "welcome_image",
optionName: "Add Image",
optionDescription: "Toggle sending an image with welcome message",
optionType: DBD.formTypes.switch(),
getActualSet: async ({ guild }) => {
const guildData = await client.getGuildData(guild.id);
return guildData.plugins.welcome.withImage;
},
setNew: async ({ guild, newData }) => {
const guildData = await client.getGuildData(guild.id);
guildData.plugins.welcome.withImage = newData;
await guildData.save();
return;
},
},
{
optionId: "welcome_message",
optionName: "Message",
optionDescription: "Change welcome message (You can use {user}, {server} and {membercount} wildcards)",
optionType: DBD.formTypes.input("Welcome, {user}!", 2, 100, false, false),
getActualSet: async ({ guild }) => {
const guildData = await client.getGuildData(guild.id);
return guildData.plugins.welcome.message;
},
setNew: async ({ guild, newData }) => {
const guildData = await client.getGuildData(guild.id);
guildData.plugins.welcome.message = newData !== "" ? newData : null;
await guildData.save();
return;
},
},
{
optionId: "welcome_channel",
optionName: "Channel",
optionDescription: "Select a channel for welcome messages",
optionType: DBD.formTypes.channelsSelect(false, [ChannelType.GuildText]),
getActualSet: async ({ guild }) => {
const guildData = await client.getGuildData(guild.id);
return guildData.plugins.welcome.channel;
},
setNew: async ({ guild, newData }) => {
const guildData = await client.getGuildData(guild.id);
guildData.plugins.welcome.channel = newData !== "" ? newData : null;
await guildData.save();
return;
},
},
]),
},
{
optionId: "goodbye",
optionName: "Goodbye Message",
optionDescription: "Setup goodbye message on the server",
optionType: SoftUI.formTypes.multiRow([
{
optionId: "goodbye_enable",
optionName: "Enabled",
optionDescription: "Toggle goodbye messages sending",
optionType: DBD.formTypes.switch(),
getActualSet: async ({ guild }) => {
const guildData = await client.getGuildData(guild.id);
return guildData.plugins.goodbye.enabled;
},
setNew: async ({ guild, newData }) => {
const guildData = await client.getGuildData(guild.id);
guildData.plugins.goodbye.enabled = newData;
await guildData.save();
return;
},
},
{
optionId: "goodbye_image",
optionName: "Add Image",
optionDescription: "Toggle sending an image with goodbye message",
optionType: DBD.formTypes.switch(),
getActualSet: async ({ guild }) => {
const guildData = await client.getGuildData(guild.id);
return guildData.plugins.goodbye.withImage;
},
setNew: async ({ guild, newData }) => {
const guildData = await client.getGuildData(guild.id);
guildData.plugins.goodbye.withImage = newData;
await guildData.save();
return;
},
},
{
optionId: "goodbye_message",
optionName: "Message",
optionDescription: "Change goodbye message (You can use {user}, {server} and {membercount} wildcards)",
optionType: DBD.formTypes.input("goodbye, {user}!", 2, 100, false, false),
getActualSet: async ({ guild }) => {
const guildData = await client.getGuildData(guild.id);
return guildData.plugins.goodbye.message;
},
setNew: async ({ guild, newData }) => {
const guildData = await client.getGuildData(guild.id);
guildData.plugins.goodbye.message = newData !== "" ? newData : null;
await guildData.save();
return;
},
},
{
optionId: "goodbye_channel",
optionName: "Channel",
optionDescription: "Select a channel for goodbye messages",
optionType: DBD.formTypes.channelsSelect(false, [ChannelType.GuildText]),
getActualSet: async ({ guild }) => {
const guildData = await client.getGuildData(guild.id);
return guildData.plugins.goodbye.channel;
},
setNew: async ({ guild, newData }) => {
const guildData = await client.getGuildData(guild.id);
guildData.plugins.goodbye.channel = newData !== "" ? newData : null;
await guildData.save();
return;
},
},
]),
},
{
optionId: "autorole",
optionName: "Auto Role",
optionDescription: "Setup auto role on the server",
optionType: SoftUI.formTypes.multiRow([
{
optionId: "autorole_enable",
optionName: "Enabled",
optionDescription: "Toggle auto role granting for new members",
optionType: DBD.formTypes.switch(),
getActualSet: async ({ guild }) => {
const guildData = await client.getGuildData(guild.id);
return guildData.plugins.autorole.enabled;
},
setNew: async ({ guild, newData }) => {
const guildData = await client.getGuildData(guild.id);
guildData.plugins.autorole.enabled = newData;
await guildData.save();
return;
},
},
{
optionId: "autorole_role",
optionName: "Role",
optionDescription: "Select a role for auto role. Select \"-\" to disable",
optionType: DBD.formTypes.rolesSelect(false, false, true),
getActualSet: async ({ guild }) => {
const guildData = await client.getGuildData(guild.id);
return guildData.plugins.autorole.role;
},
setNew: async ({ guild, newData }) => {
const guildData = await client.getGuildData(guild.id);
guildData.plugins.autorole.role = newData !== "" ? newData : null;
await guildData.save();
return;
},
},
]),
},
{
optionId: "automod",
optionName: "Auto Mod",
optionDescription: "Setup auto mod on the server",
optionType: SoftUI.formTypes.multiRow([
{
optionId: "automod_enable",
optionName: "Enabled",
optionDescription: "Toggle auto mod. It will remove invite links from non-moderators",
optionType: DBD.formTypes.switch(),
getActualSet: async ({ guild }) => {
const guildData = await client.getGuildData(guild.id);
return guildData.plugins.automod.enabled;
},
setNew: async ({ guild, newData }) => {
const guildData = await client.getGuildData(guild.id);
guildData.plugins.automod.enabled = newData;
await guildData.save();
return;
},
},
{
optionId: "automod_ignore",
optionName: "Ignore Channels",
optionDescription: "Select a channels for auto mod to ignore",
optionType: DBD.formTypes.channelsMultiSelect(false, false, [ChannelType.GuildText]),
getActualSet: async ({ guild }) => {
const guildData = await client.getGuildData(guild.id);
return guildData.plugins.automod.ignored;
},
setNew: async ({ guild, newData }) => {
const guildData = await client.getGuildData(guild.id);
guildData.plugins.automod.ignored = newData;
await guildData.save();
return;
},
},
]),
},
{
optionId: "monitoring",
optionName: "Monitoring Channels",
optionDescription: "Setup monitoring channels on the server",
optionType: SoftUI.formTypes.multiRow([
{
optionId: "monitoring_messageupdate",
optionName: "Message Update Channel",
optionDescription: "Select a channel for messages update logs to go to. Select \"-\" to disable",
optionType: DBD.formTypes.channelsSelect(false, [ChannelType.GuildText]),
getActualSet: async ({ guild }) => {
const guildData = await client.getGuildData(guild.id);
return guildData.plugins?.monitoring?.messageUpdate;
},
setNew: async ({ guild, newData }) => {
const guildData = await client.getGuildData(guild.id);
if (guildData.plugins.monitoring === undefined) guildData.plugins.monitoring = {};
guildData.plugins.monitoring.messageUpdate = newData !== "" ? newData : null;
await guildData.save();
return;
},
},
{
optionId: "monitoring_messagedelete",
optionName: "Message Deletion Channel",
optionDescription: "Select a channel for messages deletion logs to go to. Select \"-\" to disable",
optionType: DBD.formTypes.channelsSelect(false, [ChannelType.GuildText]),
getActualSet: async ({ guild }) => {
const guildData = await client.getGuildData(guild.id);
return guildData.plugins?.monitoring?.messageDelete;
},
setNew: async ({ guild, newData }) => {
const guildData = await client.getGuildData(guild.id);
if (guildData.plugins.monitoring === undefined) guildData.plugins.monitoring = {};
guildData.plugins.monitoring.messageDelete = newData !== "" ? newData : null;
await guildData.save();
return;
},
},
]),
},
{
optionId: "channels",
optionName: "Special Channels",
optionDescription: "Setup special channels on the server. Select \"-\" to disable",
optionType: SoftUI.formTypes.multiRow([
{
optionId: "channels_suggestions",
optionName: "Suggestions Channel",
optionDescription: "Select a channel for suggestions to go to",
optionType: DBD.formTypes.channelsSelect(false, [ChannelType.GuildText]),
getActualSet: async ({ guild }) => {
const guildData = await client.getGuildData(guild.id);
return guildData.plugins.suggestions;
},
setNew: async ({ guild, newData }) => {
const guildData = await client.getGuildData(guild.id);
guildData.plugins.suggestions = newData !== "" ? newData : null;
await guildData.save();
return;
},
},
{
optionId: "channels_reports",
optionName: "Reports Channel",
optionDescription: "Select a channel for reports to go to. Select \"-\" to disable",
optionType: DBD.formTypes.channelsSelect(false, [ChannelType.GuildText]),
getActualSet: async ({ guild }) => {
const guildData = await client.getGuildData(guild.id);
return guildData.plugins.reports;
},
setNew: async ({ guild, newData }) => {
const guildData = await client.getGuildData(guild.id);
guildData.plugins.reports = newData !== "" ? newData : null;
await guildData.save();
return;
},
},
{
optionId: "channels_birthdays",
optionName: "Birthdays Channel",
optionDescription: "Select a channel for birthdays message to go to. Select \"-\" to disable",
optionType: DBD.formTypes.channelsSelect(false, [ChannelType.GuildText]),
getActualSet: async ({ guild }) => {
const guildData = await client.getGuildData(guild.id);
return guildData.plugins.birthdays;
},
setNew: async ({ guild, newData }) => {
const guildData = await client.getGuildData(guild.id);
guildData.plugins.birthdays = newData !== "" ? newData : null;
await guildData.save();
return;
},
},
{
optionId: "channels_modlogs",
optionName: "Moderation Logs Channel",
optionDescription: "Select a channel for moderation logs to go to (warns). Select \"-\" to disable",
optionType: DBD.formTypes.channelsSelect(false, [ChannelType.GuildText]),
getActualSet: async ({ guild }) => {
const guildData = await client.getGuildData(guild.id);
return guildData.plugins.modlogs;
},
setNew: async ({ guild, newData }) => {
const guildData = await client.getGuildData(guild.id);
guildData.plugins.modlogs = newData !== "" ? newData : null;
await guildData.save();
return;
},
},
]),
},
],
},
{
categoryId: "test",
categoryName: "test settings",
categoryDescription: "ooga booga",
categoryPermissions: PermissionsBitField.Flags.ViewChannel,
categoryOptionsList: [
{
optionType: DBD.formTypes.embedBuilder({
username: "JaBa",
avatarURL: "https://cdn.discordapp.com/avatars/708637495054565426/af98d49ebc9bf28b40b45ed5a0a623b4.png?size=4096",
}),
},
],
},
];

View file

@ -18,7 +18,7 @@ export default [
rules: {
"arrow-body-style": ["error", "as-needed"],
camelcase: "error",
curly: "error",
curly: ["error", "multi-line"],
eqeqeq: ["error", "always"],
"no-console": "off",
"no-var": "error",

View file

@ -1,5 +1,5 @@
const { InteractionType } = require("discord.js");
const BaseEvent = require("../base/BaseEvent");
import { InteractionType } from "discord.js";
import BaseEvent from "../base/BaseEvent";
class CommandHandler extends BaseEvent {
constructor() {
@ -33,12 +33,10 @@ class CommandHandler extends BaseEvent {
if (interaction.type !== InteractionType.ApplicationCommand || !interaction.isCommand()) return;
// IAT Guild Command Check
if (command?.dirname.includes("IAT") && interaction.guildId !== "1039187019957555252")
return interaction.reply({ content: "IAT only", ephemeral: true });
if (command?.dirname.includes("IAT") && interaction.guildId !== "1039187019957555252") return interaction.reply({ content: "IAT only", ephemeral: true });
// Owner-only command check
if (command.ownerOnly && interaction.user.id !== client.config.owner.id)
return interaction.error("misc:OWNER_ONLY", null, { ephemeral: true });
if (command.ownerOnly && interaction.user.id !== client.config.owner.id) return interaction.error("misc:OWNER_ONLY", null, { ephemeral: true });
// First command achievement check
const { firstCommand } = interaction.data.user.achievements;
@ -68,4 +66,4 @@ class CommandHandler extends BaseEvent {
}
}
module.exports = CommandHandler;
export default CommandHandler;

View file

@ -1,4 +1,4 @@
const BaseEvent = require("../../base/BaseEvent");
import BaseEvent from "../../base/BaseEvent";
class guildBanAdd extends BaseEvent {
constructor() {
@ -26,8 +26,10 @@ class guildBanAdd extends BaseEvent {
await ban.user.send({
embeds: [embed],
});
} catch (e) { /**/ }
} catch {
/**/
}
}
}
module.exports = guildBanAdd;
export default guildBanAdd;

View file

@ -1,4 +1,4 @@
const BaseEvent = require("../../base/BaseEvent");
import BaseEvent from "../../base/BaseEvent";
class GuildCreate extends BaseEvent {
constructor() {
@ -62,12 +62,13 @@ class GuildCreate extends BaseEvent {
const logChannel = client.channels.cache.get(client.config.support.logs);
if (logChannel)
if (logChannel) {
await logChannel.send({
embeds: [embed],
});
}
}
}
}
module.exports = GuildCreate;
export default GuildCreate;

View file

@ -1,4 +1,4 @@
const BaseEvent = require("../../base/BaseEvent");
import BaseEvent from "../../base/BaseEvent";
class GuildDelete extends BaseEvent {
constructor() {
@ -25,13 +25,13 @@ class GuildDelete extends BaseEvent {
const logChannel = client.channels.cache.get(client.config.support.logs);
if (logChannel)
if (logChannel) {
await logChannel.send({
embeds: [embed],
});
else client.logger.warn(`Log channel not found for guild deletion: ${guild.name}`);
} else client.logger.warn(`Log channel not found for guild deletion: ${guild.name}`);
}
}
}
module.exports = GuildDelete;
export default GuildDelete;

View file

@ -1,4 +1,4 @@
const BaseEvent = require("../../base/BaseEvent");
import BaseEvent from "../../base/BaseEvent";
class GuildMemberAdd extends BaseEvent {
constructor() {
@ -46,4 +46,4 @@ class GuildMemberAdd extends BaseEvent {
}
}
module.exports = GuildMemberAdd;
export default GuildMemberAdd;

View file

@ -1,4 +1,4 @@
const BaseEvent = require("../../base/BaseEvent");
import BaseEvent from "../../base/BaseEvent";
class GuildMemberRemove extends BaseEvent {
constructor() {
@ -37,4 +37,4 @@ class GuildMemberRemove extends BaseEvent {
}
}
module.exports = GuildMemberRemove;
export default GuildMemberRemove;

View file

@ -1,4 +1,4 @@
const BaseEvent = require("../../base/BaseEvent");
import BaseEvent from "../../base/BaseEvent";
class GuildMemberUpdate extends BaseEvent {
constructor() {
@ -44,4 +44,4 @@ class GuildMemberUpdate extends BaseEvent {
}
}
module.exports = GuildMemberUpdate;
export default GuildMemberUpdate;

View file

@ -1,5 +1,5 @@
const { PermissionsBitField, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("discord.js");
const BaseEvent = require("../base/BaseEvent");
import { PermissionsBitField, ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
import BaseEvent from "../base/BaseEvent";
const xpCooldown = {};
@ -23,7 +23,7 @@ class MessageCreate extends BaseEvent {
if (message.guild) {
if (!message.member) await message.guild.members.fetch(message.author.id);
data.guild = await client.getGuildData(message.guildId);
data.member = await client.getMemberData(message.author.id, message.guildId);
}
@ -69,8 +69,7 @@ class MessageCreate extends BaseEvent {
if (msg.content) embed.addFields([{ name: message.translate("misc:QUOTE_CONTENT"), value: msg.content }]);
if (msg.attachments.size > 0) {
if (msg.attachments.find(a => a.contentType.includes("image/")))
embed.setImage(msg.attachments.find(a => a.contentType.includes("image/")).url);
if (msg.attachments.find(a => a.contentType.includes("image/"))) embed.setImage(msg.attachments.find(a => a.contentType.includes("image/")).url);
embed.addFields([
{
@ -160,4 +159,4 @@ class MessageCreate extends BaseEvent {
}
}
module.exports = MessageCreate;
export default MessageCreate;

View file

@ -1,4 +1,4 @@
const BaseEvent = require("../../base/BaseEvent");
import BaseEvent from "../../base/BaseEvent";
class messageDelete extends BaseEvent {
constructor() {
@ -40,4 +40,4 @@ class messageDelete extends BaseEvent {
}
}
module.exports = messageDelete;
export default messageDelete;

View file

@ -1,4 +1,4 @@
const BaseEvent = require("../../base/BaseEvent");
import BaseEvent from "../../base/BaseEvent";
class messageUpdate extends BaseEvent {
constructor() {
@ -42,4 +42,4 @@ class messageUpdate extends BaseEvent {
}
}
module.exports = messageUpdate;
export default messageUpdate;

View file

@ -1,5 +1,5 @@
const { ActivityType } = require("discord.js");
const BaseEvent = require("../base/BaseEvent");
import { ActivityType } from "discord.js";
import BaseEvent from "../base/BaseEvent";
class Ready extends BaseEvent {
constructor() {
@ -28,8 +28,6 @@ class Ready extends BaseEvent {
const checkReminds = require("../helpers/checkReminds");
checkReminds.init(client);
if (client.config.dashboard.enabled) await client.dashboard.load(client);
client.logger.ready(`Loaded a total of ${commands.length} command(s).`);
client.logger.ready(`${client.user.getUsername()}, ready to serve ${users} members in ${servers} servers.`);
console.timeEnd("botReady");
@ -63,4 +61,4 @@ class Ready extends BaseEvent {
}
}
module.exports = Ready;
export default Ready;

View file

@ -1,5 +1,5 @@
const { ButtonBuilder, ActionRowBuilder, ButtonStyle, ChannelType, PermissionsBitField } = require("discord.js");
const BaseEvent = require("../base/BaseEvent");
import { ButtonBuilder, ActionRowBuilder, ButtonStyle, ChannelType, PermissionsBitField } from "discord.js";
import BaseEvent from "../base/BaseEvent";
class CommandHandler extends BaseEvent {
constructor() {
@ -60,9 +60,13 @@ class CommandHandler extends BaseEvent {
});
await logChannel.send({ embeds: [logEmbed] });
await interaction.success("tickets/createticketembed:TICKET_CREATED", {
channel: channel.toString(),
}, { ephemeral: true });
await interaction.success(
"tickets/createticketembed:TICKET_CREATED",
{
channel: channel.toString(),
},
{ ephemeral: true },
);
await channel.send(`<@${interaction.user.id}>`);
@ -75,14 +79,8 @@ class CommandHandler extends BaseEvent {
description: interaction.translate("tickets/createticketembed:TICKET_CREATED_DESC"),
});
const closeButton = new ButtonBuilder()
.setCustomId("close_ticket")
.setLabel(interaction.translate("tickets/closeticket:CLOSE_TICKET"))
.setStyle(ButtonStyle.Danger);
const transcriptButton = new ButtonBuilder()
.setCustomId("transcript_ticket")
.setLabel(interaction.translate("tickets/closeticket:TRANSCRIPT_TICKET"))
.setStyle(ButtonStyle.Secondary);
const closeButton = new ButtonBuilder().setCustomId("close_ticket").setLabel(interaction.translate("tickets/closeticket:CLOSE_TICKET")).setStyle(ButtonStyle.Danger);
const transcriptButton = new ButtonBuilder().setCustomId("transcript_ticket").setLabel(interaction.translate("tickets/closeticket:TRANSCRIPT_TICKET")).setStyle(ButtonStyle.Secondary);
const row = new ActionRowBuilder().addComponents(closeButton, transcriptButton);
guildData.plugins.tickets.count++;
@ -135,14 +133,18 @@ class CommandHandler extends BaseEvent {
});
transcript += "---- TICKET CLOSED ----\n";
if (transcriptionLogs !== null) interaction.guild.channels.cache.get(transcriptionLogs).send({ content: interaction.translate("tickets/closeticket:TRANSCRIPT", { channel: `<#${interaction.channelId}>` }), files: [{ attachment: Buffer.from(transcript), name: `${interaction.channel.name}.txt` }] });
if (transcriptionLogs !== null) {
interaction.guild.channels.cache
.get(transcriptionLogs)
.send({ content: interaction.translate("tickets/closeticket:TRANSCRIPT", { channel: `<#${interaction.channelId}>` }), files: [{ attachment: Buffer.from(transcript), name: `${interaction.channel.name}.txt` }] });
}
try {
await interaction.user.send({
content: interaction.translate("tickets/closeticket:TRANSCRIPT", { channel: interaction.channel.name }),
files: [{ attachment: Buffer.from(transcript), name: `${interaction.channel.name}.txt` }],
});
} catch (e) {
} catch {
interaction.followUp({ content: interaction.translate("misc:CANT_DM"), ephemeral: true });
}
}
@ -181,7 +183,7 @@ class CommandHandler extends BaseEvent {
content: interaction.translate("tickets/closeticket:TRANSCRIPT", { channel: `<#${interaction.channelId}>` }),
files: [{ attachment: Buffer.from(transcript), name: `${interaction.channel.name}.txt` }],
});
} catch (error) {
} catch {
interaction.followUp({ content: interaction.translate("misc:CANT_DM"), ephemeral: true });
}
} else return;
@ -189,4 +191,4 @@ class CommandHandler extends BaseEvent {
}
}
module.exports = CommandHandler;
export default CommandHandler;

View file

@ -1,4 +1,4 @@
const { CronJob } = require("cron");
import { CronJob } from "cron";
/**
*
@ -61,5 +61,9 @@ async function checkBirthdays(client) {
}
}
module.exports.init = async client => new CronJob("0 5 * * *", checkBirthdays(client), null, true, "Europe/Moscow");
module.exports.run = async client => await checkBirthdays(client);
export async function init(client) {
new CronJob("0 5 * * *", checkBirthdays(client), null, true, "Europe/Moscow");
}
export async function run(client) {
await checkBirthdays(client);
}

View file

@ -56,5 +56,11 @@ async function checkReminds(client) {
});
}
module.exports.init = async client => setInterval(async () => await checkReminds(client), 1000);
module.exports.run = async client => await checkReminds(client);
export async function init(client) {
setInterval(async () => {
await checkReminds(client);
}, 1000);
}
export async function run(client) {
await checkReminds(client);
}

View file

@ -1,5 +1,4 @@
// Thanks Stackoverflow <3
function setDaysTimeout(callback, days) {
// 86400 seconds in a day
const msInDay = 86400 * 1000;
@ -19,7 +18,7 @@ function setDaysTimeout(callback, days) {
*
* @param {import("../base/Client")} client
*/
module.exports.init = async function (client) {
export async function init(client) {
setDaysTimeout(async () => {
const timestamp = Date.now() + 29 * 24 * 60 * 60 * 1000; // 29 days
const members = client.membersData.find({ transactions: { $gt: [] } });
@ -66,4 +65,4 @@ module.exports.init = async function (client) {
}
});
}, 30);
};
}

View file

@ -1,4 +1,4 @@
const { Message, BaseInteraction, User, GuildMember } = require("discord.js");
import { Message, BaseInteraction, User, GuildMember } from "discord.js";
/**
*

View file

@ -1,147 +1,137 @@
const moment = require("moment");
import moment from "moment";
module.exports = {
/**
* Asynchronously iterates over a collection and executes a callback function for each item.
*
* @param {any[]} collection - The collection to iterate over.
* @param {(item: any) => Promise<void>} callback - The async callback function to execute for each item in the collection.
* @returns {Promise<void>} A promise that resolves when all items in the collection have been processed.
*/
async asyncForEach(collection, callback) {
const allPromises = collection.map(async key => {
await callback(key);
});
/**
* Asynchronously iterates over a collection and executes a callback function for each item.
*
* @param {any[]} collection - The collection to iterate over.
* @param {(item: any) => Promise<void>} callback - The async callback function to execute for each item in the collection.
* @returns {Promise<void>} A promise that resolves when all items in the collection have been processed.
*/
export async function asyncForEach(collection, callback) {
const allPromises = collection.map(async key => {
await callback(key);
});
return await Promise.all(allPromises);
},
return await Promise.all(allPromises);
}
/**
* Sorts an array by the specified key in ascending order.
*
* @param {any[]} array - The array to sort.
* @param {string} key - The key to sort the array by.
* @returns {any[]} The sorted array.
*/
sortByKey(array, key) {
return array.sort(function (a, b) {
const x = a[key];
const y = b[key];
return x < y ? 1 : x > y ? -1 : 0;
});
},
/**
* Sorts an array by the specified key in ascending order.
*
* @param {any[]} array - The array to sort.
* @param {string} key - The key to sort the array by.
* @returns {any[]} The sorted array.
*/
export function sortByKey(array, key) {
return array.sort(function (a, b) {
const x = a[key];
const y = b[key];
return x < y ? 1 : x > y ? -1 : 0;
});
}
/**
* Shuffles the elements of the provided array in-place.
*
* @param {any[]} pArray - The array to shuffle.
* @returns {any[]} The shuffled array.
*/
shuffle(pArray) {
const array = [];
/**
* Shuffles the elements of the provided array in-place.
*
* @param {any[]} pArray - The array to shuffle.
* @returns {any[]} The shuffled array.
*/
export function shuffle(pArray) {
const array = [];
pArray.forEach(element => array.push(element));
pArray.forEach(element => array.push(element));
let currentIndex = array.length,
temporaryValue,
randomIndex;
let currentIndex = array.length,
temporaryValue,
randomIndex;
while (currentIndex !== 0) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
while (currentIndex !== 0) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
return array;
},
/**
* Generates a random integer between the specified minimum and maximum values (inclusive).
*
* @param {number} [min=0] - The minimum value (inclusive).
* @param {number} [max=100] - The maximum value (inclusive).
* @returns {number} A random integer between min and max.
*/
export function randomNum(min = 0, max = 100) {
min = Math.floor(min);
max = Math.floor(max);
/**
* Generates a random integer between the specified minimum and maximum values (inclusive).
*
* @param {number} [min=0] - The minimum value (inclusive).
* @param {number} [max=100] - The maximum value (inclusive).
* @returns {number} A random integer between min and max.
*/
randomNum(min = 0, max = 100) {
min = Math.floor(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1) + min);
}
/**
* Formats a date for the specified client and locale.
*
* @param {Object} client - The client object containing language data.
* @param {string} date - The date to format.
* @param {string} [format=null] - The date format to use. If not provided, the default format for the client's language will be used.
* @param {string} [locale=client.defaultLanguage.name] - The locale to use for formatting the date.
* @returns {string} The formatted date.
*/
export function printDate(client, date, format = null, locale = client.defaultLanguage.name) {
const languageData = client.languages.find(language => language.name === locale);
if (format === "" || format === null) format = languageData.defaultMomentFormat;
return moment(new Date(date)).locale(languageData.moment).format(format);
}
/**
* Formats a time value relative to the current time.
*
* @param {Object} client - The client object containing language data.
* @param {string|number|Date} time - The time value to format.
* @param {boolean} [type=false] - If true, formats the time as "X time ago", otherwise formats it as "in X time".
* @param {boolean} [prefix=true] - If true, includes a prefix like "in" or "ago" in the formatted time.
* @param {string} [locale=client.defaultLanguage.name] - The locale to use for formatting the time.
* @returns {string} The formatted time value.
*/
export function convertTime(client, time, type = false, prefix = true, locale = client.defaultLanguage.name) {
const languageData = client.languages.find(language => language.name === locale);
const m = moment(time).locale(languageData.moment);
return type ? m.toNow(!prefix) : m.fromNow(!prefix);
}
return Math.floor(Math.random() * (max - min + 1) + min);
},
/**
* Generates the appropriate noun form based on the given number and noun forms.
*
* @param {number} number - The number to use for determining the noun form.
* @param {string} one - The noun form for the singular case.
* @param {string} two - The noun form for the dual case.
* @param {string} five - The noun form for the plural case.
* @returns {string} The appropriate noun form based on the given number.
*/
export function getNoun(number, one, two, five) {
let n = Math.abs(number);
n %= 100;
if (n >= 5 && n <= 20) return five;
n %= 10;
if (n === 1) return one;
if (n >= 2 && n <= 4) return two;
return five;
}
/**
* Formats a date for the specified client and locale.
*
* @param {Object} client - The client object containing language data.
* @param {string} date - The date to format.
* @param {string} [format=null] - The date format to use. If not provided, the default format for the client's language will be used.
* @param {string} [locale=client.defaultLanguage.name] - The locale to use for formatting the date.
* @returns {string} The formatted date.
*/
printDate(client, date, format = null, locale = client.defaultLanguage.name) {
const languageData = client.languages.find(language => language.name === locale);
if (format === "" || format === null) format = languageData.defaultMomentFormat;
return moment(new Date(date)).locale(languageData.moment).format(format);
},
/**
* Formats a time value relative to the current time.
*
* @param {Object} client - The client object containing language data.
* @param {string|number|Date} time - The time value to format.
* @param {boolean} [type=false] - If true, formats the time as "X time ago", otherwise formats it as "in X time".
* @param {boolean} [prefix=true] - If true, includes a prefix like "in" or "ago" in the formatted time.
* @param {string} [locale=client.defaultLanguage.name] - The locale to use for formatting the time.
* @returns {string} The formatted time value.
*/
convertTime(client, time, type = false, prefix = true, locale = client.defaultLanguage.name) {
const languageData = client.languages.find(language => language.name === locale);
const m = moment(time).locale(languageData.moment);
return type ? m.toNow(!prefix) : m.fromNow(!prefix);
},
/**
* Generates the appropriate noun form based on the given number and noun forms.
*
* @param {number} number - The number to use for determining the noun form.
* @param {string} one - The noun form for the singular case.
* @param {string} two - The noun form for the dual case.
* @param {string} five - The noun form for the plural case.
* @returns {string} The appropriate noun form based on the given number.
*/
getNoun(number, one, two, five) {
let n = Math.abs(number);
n %= 100;
if (n >= 5 && n <= 20) return five;
n %= 10;
if (n === 1) return one;
if (n >= 2 && n <= 4) return two;
return five;
},
/**
* Function to apply text on a canvas with dynamic font size based on the width constraint.
*
* @param {import("@napi-rs/canvas").Canvas} canvas - The canvas object where the text will be applied.
* @param {string} text - The string of text that needs to be applied on the canvas.
* @param {number} defaultFontSize - The initial font size for the text. It is expected to decrease with each iteration.
* @param {number} width - The maximum width that the text can occupy before it has to shrink down.
* @param {string} font - The name of the font used for drawing the text on the canvas.
*
* @return {string} - The final calculated font size in a format '<size>px <family>'.
*/
applyText(canvas, text, defaultFontSize, width, font) {
const ctx = canvas.getContext("2d");
do ctx.font = `${(defaultFontSize -= 1)}px ${font}`;
while (ctx.measureText(text).width > width);
return ctx.font;
},
};
/**
* Function to apply text on a canvas with dynamic font size based on the width constraint.
*
* @param {import("@napi-rs/canvas").Canvas} canvas - The canvas object where the text will be applied.
* @param {string} text - The string of text that needs to be applied on the canvas.
* @param {number} defaultFontSize - The initial font size for the text. It is expected to decrease with each iteration.
* @param {number} width - The maximum width that the text can occupy before it has to shrink down.
* @param {string} font - The name of the font used for drawing the text on the canvas.
*
* @return {string} - The final calculated font size in a format '<size>px <family>'.
*/
export function applyText(canvas, text, defaultFontSize, width, font) {
const ctx = canvas.getContext("2d");
do ctx.font = `${(defaultFontSize -= 1)}px ${font}`;
while (ctx.measureText(text).width > width);
return ctx.font;
}

View file

@ -1,19 +1,19 @@
const i18next = require("i18next"),
Backend = require("i18next-fs-backend"),
path = require("path"),
fs = require("fs").promises;
import { use, init, getFixedT } from "i18next";
import Backend from "i18next-fs-backend";
import { join, resolve } from "path";
import { promises as fs } from "fs";
async function walkDirectory(dir, namespaces = [], folderName = "") {
const files = await fs.readdir(dir);
const languages = [];
for (const file of files) {
const stat = await fs.stat(path.join(dir, file));
const stat = await fs.stat(join(dir, file));
if (stat.isDirectory()) {
const isLanguage = file.includes("-");
if (isLanguage) languages.push(file);
const folder = await walkDirectory(path.join(dir, file), namespaces, isLanguage ? "" : `${file}/`);
const folder = await walkDirectory(join(dir, file), namespaces, isLanguage ? "" : `${file}/`);
namespaces = folder.namespaces;
} else {
@ -27,16 +27,16 @@ async function walkDirectory(dir, namespaces = [], folderName = "") {
};
}
module.exports = async () => {
export default async () => {
const options = {
loadPath: path.resolve(__dirname, "../languages/{{lng}}/{{ns}}.json"),
loadPath: resolve(__dirname, "../languages/{{lng}}/{{ns}}.json"),
};
const { namespaces, languages } = await walkDirectory(path.resolve(__dirname, "../languages/"));
const { namespaces, languages } = await walkDirectory(resolve(__dirname, "../languages/"));
i18next.use(Backend);
use(Backend);
await i18next.init({
await init({
backend: options,
debug: false,
fallbackLng: "en-US",
@ -47,5 +47,5 @@ module.exports = async () => {
preload: languages,
});
return new Map(languages.map(item => [item, i18next.getFixedT(item)]));
return new Map(languages.map(item => [item, getFixedT(item)]));
};

View file

@ -1,4 +1,4 @@
const { bgBlue, black, green } = require("chalk");
import { bgBlue, black, green } from "chalk";
function dateTimePad(value, digits) {
let number = value;
@ -25,28 +25,28 @@ function format(tDate) {
);
}
module.exports = class Logger {
static log(content) {
export default {
log(content) {
return console.log(`[${format(new Date(Date.now()))}]: ${bgBlue("LOG")} ${content}`);
}
},
static warn(content) {
warn(content) {
return console.log(`[${format(new Date(Date.now()))}]: ${black.bgYellow("WARN")} ${content}`);
}
},
static error(content) {
error(content) {
return console.log(`[${format(new Date(Date.now()))}]: ${black.bgRed("ERROR")} ${content}`);
}
},
static debug(content) {
debug(content) {
return console.log(`[${format(new Date(Date.now()))}]: ${green("DEBUG")} ${content}`);
}
},
static cmd(content) {
cmd(content) {
return console.log(`[${format(new Date(Date.now()))}]: ${black.bgWhite("CMD")} ${content}`);
}
},
static ready(content) {
ready(content) {
return console.log(`[${format(new Date(Date.now()))}]: ${black.bgGreen("READY")} ${content}`);
}
},
};

View file

@ -1,7 +1,7 @@
// Thanks to simply-djs for this =)
// TODO: Refactor this please...
const { ButtonBuilder, ActionRowBuilder, ButtonStyle, ComponentType } = require("discord.js");
import { ButtonBuilder, ActionRowBuilder, ButtonStyle, ComponentType } from "discord.js";
/**
* @param {import("discord.js").ChatInputCommandInteraction} interaction
@ -15,7 +15,7 @@ const { ButtonBuilder, ActionRowBuilder, ButtonStyle, ComponentType } = require(
* @param {string} options.idleEmoji Emoji for "nothing"
* @returns {Promise<import("discord.js").User>}
*/
async function tictactoe(interaction, options = {}) {
export async function tictactoe(interaction, options = {}) {
// eslint-disable-next-line no-async-promise-executor
return new Promise(async resolve => {
try {
@ -25,41 +25,47 @@ async function tictactoe(interaction, options = {}) {
if (interaction.commandId) {
opponent = interaction.options.getUser(options.userSlash || "user");
if (!opponent)
if (!opponent) {
return interaction.reply({
content: interaction.translate("fun/tictactoe:NO_USER"),
ephemeral: true,
});
}
if (opponent.bot)
if (opponent.bot) {
return interaction.reply({
content: interaction.translate("fun/tictactoe:BOT_USER"),
ephemeral: true,
});
}
if (opponent.id == (interaction.user ? interaction.user : interaction.author).id)
if (opponent.id === (interaction.user ? interaction.user : interaction.author).id) {
return interaction.reply({
content: interaction.translate("misc:CANT_YOURSELF"),
ephemeral: true,
});
}
} else if (!interaction.commandId) {
opponent = interaction.mentions.members.first()?.user;
if (!opponent)
if (!opponent) {
return interaction.reply({
content: interaction.translate("fun/tictactoe:NO_USER"),
});
}
if (opponent.bot)
if (opponent.bot) {
return interaction.reply({
content: interaction.translate("fun/tictactoe:BOT_USER"),
ephemeral: true,
});
}
if (opponent.id === interaction.member.id)
if (opponent.id === interaction.member.id) {
return interaction.reply({
content: interaction.translate("misc:CANT_YOURSELF"),
});
}
}
const footer = options.embedFooter || client.config.embed.footer,
@ -97,25 +103,26 @@ async function tictactoe(interaction, options = {}) {
});
collector.on("collect", async button => {
if (button.user.id !== opponent.id)
if (button.user.id !== opponent.id) {
return button.reply({
content: interaction.translate("fun/tictactoe:REQUEST_SEND", {
opponent: opponent.id,
}),
ephemeral: true,
});
}
if (button.customId == "declinettt") {
if (button.customId === "declinettt") {
button.deferUpdate();
return collector.stop("decline");
} else if (button.customId == "acceptttt") {
} else if (button.customId === "acceptttt") {
button.deferUpdate();
collector.stop();
const fighters = [(interaction.user ? interaction.user : interaction.author).id, opponent.id].sort(() => (Math.random() > 0.5 ? 1 : -1));
const x_emoji = options.xEmoji || "❌";
const o_emoji = options.oEmoji || "⭕";
const xEmoji = options.xEmoji || "❌";
const oEmoji = options.oEmoji || "⭕";
const dashmoji = options.idleEmoji || "";
@ -175,32 +182,32 @@ async function tictactoe(interaction, options = {}) {
});
let msg;
if (interaction.commandId)
if (interaction.commandId) {
msg = await interaction.editReply({
embeds: [
epm.setDescription(
interaction.translate("fun/tictactoe:WAITING", {
user: Args.userid,
emoji: client.emojis.cache.get(o_emoji) || "⭕",
emoji: client.emojis.cache.get(oEmoji) || "⭕",
}),
),
],
});
else if (!interaction.commandId)
} else if (!interaction.commandId) {
msg = await button.message.edit({
embeds: [
epm.setDescription(
interaction.translate("fun/tictactoe:WAITING", {
user: Args.userid,
emoji: client.emojis.cache.get(o_emoji) || "⭕",
emoji: client.emojis.cache.get(oEmoji) || "⭕",
}),
),
],
});
}
await ttt(msg);
// eslint-disable-next-line no-inner-declarations
async function ttt(m) {
Args.userid = fighters[Args.user];
const won = {
@ -222,214 +229,212 @@ async function tictactoe(interaction, options = {}) {
const c = new ActionRowBuilder().addComponents([c1, c2, c3]);
const buttons = [a, b, c];
if (Args.a1.emoji == o_emoji && Args.b1.emoji == o_emoji && Args.c1.emoji == o_emoji) won["<:O_:863314110560993340>"] = true;
if (Args.a1.emoji === oEmoji && Args.b1.emoji === oEmoji && Args.c1.emoji === oEmoji) won["<:O_:863314110560993340>"] = true;
if (Args.a2.emoji == o_emoji && Args.b2.emoji == o_emoji && Args.c2.emoji == o_emoji) won["<:O_:863314110560993340>"] = true;
if (Args.a2.emoji === oEmoji && Args.b2.emoji === oEmoji && Args.c2.emoji === oEmoji) won["<:O_:863314110560993340>"] = true;
if (Args.a3.emoji == o_emoji && Args.b3.emoji == o_emoji && Args.c3.emoji == o_emoji) won["<:O_:863314110560993340>"] = true;
if (Args.a3.emoji === oEmoji && Args.b3.emoji === oEmoji && Args.c3.emoji === oEmoji) won["<:O_:863314110560993340>"] = true;
if (Args.a1.emoji == o_emoji && Args.b2.emoji == o_emoji && Args.c3.emoji == o_emoji) won["<:O_:863314110560993340>"] = true;
if (Args.a1.emoji === oEmoji && Args.b2.emoji === oEmoji && Args.c3.emoji === oEmoji) won["<:O_:863314110560993340>"] = true;
if (Args.a3.emoji == o_emoji && Args.b2.emoji == o_emoji && Args.c1.emoji == o_emoji) won["<:O_:863314110560993340>"] = true;
if (Args.a3.emoji === oEmoji && Args.b2.emoji === oEmoji && Args.c1.emoji === oEmoji) won["<:O_:863314110560993340>"] = true;
if (Args.a1.emoji == o_emoji && Args.a2.emoji == o_emoji && Args.a3.emoji == o_emoji) won["<:O_:863314110560993340>"] = true;
if (Args.a1.emoji === oEmoji && Args.a2.emoji === oEmoji && Args.a3.emoji === oEmoji) won["<:O_:863314110560993340>"] = true;
if (Args.b1.emoji == o_emoji && Args.b2.emoji == o_emoji && Args.b3.emoji == o_emoji) won["<:O_:863314110560993340>"] = true;
if (Args.b1.emoji === oEmoji && Args.b2.emoji === oEmoji && Args.b3.emoji === oEmoji) won["<:O_:863314110560993340>"] = true;
if (Args.c1.emoji == o_emoji && Args.c2.emoji == o_emoji && Args.c3.emoji == o_emoji) won["<:O_:863314110560993340>"] = true;
if (Args.c1.emoji === oEmoji && Args.c2.emoji === oEmoji && Args.c3.emoji === oEmoji) won["<:O_:863314110560993340>"] = true;
if (won["<:O_:863314110560993340>"] != false)
if (Args.user == 0) {
if (won["<:O_:863314110560993340>"] !== false) {
if (Args.user === 0) {
const won = await client.users.fetch(fighters[1]).catch(console.error);
resolve(won);
if (options.resultBtn === true)
return m
.edit({
content: interaction.translate("fun/tictactoe:WON", {
winner: fighters[1],
emoji: client.emojis.cache.get(o_emoji) || "⭕",
}),
components: buttons,
if (options.resultBtn === true) {
return m.edit({
content: interaction.translate("fun/tictactoe:WON", {
winner: fighters[1],
emoji: client.emojis.cache.get(oEmoji) || "⭕",
}),
components: buttons,
embeds: [
epm.setDescription(
interaction.translate("fun/tictactoe:WON", {
winner: fighters[1],
emoji: client.emojis.cache.get(o_emoji) || "⭕",
}),
),
],
});
else if (!options.resultBtn || options.resultBtn === false)
return m
.edit({
content: interaction.translate("fun/tictactoe:WON", {
winner: fighters[1],
emoji: client.emojis.cache.get(o_emoji) || "⭕",
}),
embeds: [
epm.setDescription(
interaction.translate("fun/tictactoe:WON", {
winner: fighters[1],
emoji: client.emojis.cache.get(oEmoji) || "⭕",
}),
),
],
});
} else if (!options.resultBtn || options.resultBtn === false) {
return m.edit({
content: interaction.translate("fun/tictactoe:WON", {
winner: fighters[1],
emoji: client.emojis.cache.get(oEmoji) || "⭕",
}),
embeds: [
epm.setDescription(
`${interaction.translate("fun/tictactoe:WON", {
winner: fighters[1],
emoji: client.emojis.cache.get(o_emoji) || "⭕",
})}\n\`\`\`\n${Args.a1.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.a2.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.a3.emoji
.replace(o_emoji, "⭕")
.replace(x_emoji, "❌")}\n${Args.b1.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.b2.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.b3.emoji
.replace(o_emoji, "⭕")
.replace(x_emoji, "❌")}\n${Args.c1.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.c2.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.c3.emoji
.replace(o_emoji, "⭕")
.replace(x_emoji, "❌")}\n\`\`\``.replaceAll(dashmoji, ""),
),
],
components: [],
});
} else if (Args.user == 1) {
embeds: [
epm.setDescription(
`${interaction.translate("fun/tictactoe:WON", {
winner: fighters[1],
emoji: client.emojis.cache.get(oEmoji) || "⭕",
})}\n\`\`\`\n${Args.a1.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.a2.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.a3.emoji
.replace(oEmoji, "⭕")
.replace(xEmoji, "❌")}\n${Args.b1.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.b2.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.b3.emoji
.replace(oEmoji, "⭕")
.replace(xEmoji, "❌")}\n${Args.c1.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.c2.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.c3.emoji
.replace(oEmoji, "⭕")
.replace(xEmoji, "❌")}\n\`\`\``.replaceAll(dashmoji, ""),
),
],
components: [],
});
}
} else if (Args.user === 1) {
const won = await client.users.fetch(fighters[0]).catch(console.error);
resolve(won);
if (options.resultBtn === true)
return m
.edit({
content: interaction.translate("fun/tictactoe:WON", {
winner: fighters[0],
emoji: client.emojis.cache.get(o_emoji) || "⭕",
}),
components: buttons,
embeds: [
epm.setDescription(
interaction.translate("fun/tictactoe:WON", {
winner: fighters[0],
emoji: client.emojis.cache.get(o_emoji) || "⭕",
}),
),
],
});
else if (!options.resultBtn || options.resultBtn === false)
return m
.edit({
content: interaction.translate("fun/tictactoe:WON", {
winner: fighters[0],
emoji: client.emojis.cache.get(o_emoji) || "⭕",
}),
if (options.resultBtn === true) {
return m.edit({
content: interaction.translate("fun/tictactoe:WON", {
winner: fighters[0],
emoji: client.emojis.cache.get(oEmoji) || "⭕",
}),
components: buttons,
embeds: [
epm.setDescription(
interaction.translate("fun/tictactoe:WON", {
winner: fighters[0],
emoji: client.emojis.cache.get(oEmoji) || "⭕",
}),
),
],
});
} else if (!options.resultBtn || options.resultBtn === false) {
return m.edit({
content: interaction.translate("fun/tictactoe:WON", {
winner: fighters[0],
emoji: client.emojis.cache.get(oEmoji) || "⭕",
}),
embeds: [
epm.setDescription(
`${interaction.translate("fun/tictactoe:WON", {
winner: fighters[0],
emoji: client.emojis.cache.get(o_emoji) || "⭕",
})}\n\`\`\`\n${Args.a1.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.a2.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.a3.emoji
.replace(o_emoji, "⭕")
.replace(x_emoji, "❌")}\n${Args.b1.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.b2.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.b3.emoji
.replace(o_emoji, "⭕")
.replace(x_emoji, "❌")}\n${Args.c1.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.c2.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.c3.emoji
.replace(o_emoji, "⭕")
.replace(x_emoji, "❌")}\n\`\`\``.replaceAll(dashmoji, ""),
),
],
components: [],
});
embeds: [
epm.setDescription(
`${interaction.translate("fun/tictactoe:WON", {
winner: fighters[0],
emoji: client.emojis.cache.get(oEmoji) || "⭕",
})}\n\`\`\`\n${Args.a1.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.a2.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.a3.emoji
.replace(oEmoji, "⭕")
.replace(xEmoji, "❌")}\n${Args.b1.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.b2.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.b3.emoji
.replace(oEmoji, "⭕")
.replace(xEmoji, "❌")}\n${Args.c1.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.c2.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.c3.emoji
.replace(oEmoji, "⭕")
.replace(xEmoji, "❌")}\n\`\`\``.replaceAll(dashmoji, ""),
),
],
components: [],
});
}
}
}
if (Args.a1.emoji == x_emoji && Args.b1.emoji == x_emoji && Args.c1.emoji == x_emoji) won["<:X_:863314044781723668>"] = true;
if (Args.a2.emoji == x_emoji && Args.b2.emoji == x_emoji && Args.c2.emoji == x_emoji) won["<:X_:863314044781723668>"] = true;
if (Args.a3.emoji == x_emoji && Args.b3.emoji == x_emoji && Args.c3.emoji == x_emoji) won["<:X_:863314044781723668>"] = true;
if (Args.a1.emoji == x_emoji && Args.b2.emoji == x_emoji && Args.c3.emoji == x_emoji) won["<:X_:863314044781723668>"] = true;
if (Args.a3.emoji == x_emoji && Args.b2.emoji == x_emoji && Args.c1.emoji == x_emoji) won["<:X_:863314044781723668>"] = true;
if (Args.a1.emoji == x_emoji && Args.a2.emoji == x_emoji && Args.a3.emoji == x_emoji) won["<:X_:863314044781723668>"] = true;
if (Args.b1.emoji == x_emoji && Args.b2.emoji == x_emoji && Args.b3.emoji == x_emoji) won["<:X_:863314044781723668>"] = true;
if (Args.c1.emoji == x_emoji && Args.c2.emoji == x_emoji && Args.c3.emoji == x_emoji) won["<:X_:863314044781723668>"] = true;
if (won["<:X_:863314044781723668>"] != false)
if (Args.user == 0) {
if (Args.a1.emoji === xEmoji && Args.b1.emoji === xEmoji && Args.c1.emoji === xEmoji) won["<:X_:863314044781723668>"] = true;
if (Args.a2.emoji === xEmoji && Args.b2.emoji === xEmoji && Args.c2.emoji === xEmoji) won["<:X_:863314044781723668>"] = true;
if (Args.a3.emoji === xEmoji && Args.b3.emoji === xEmoji && Args.c3.emoji === xEmoji) won["<:X_:863314044781723668>"] = true;
if (Args.a1.emoji === xEmoji && Args.b2.emoji === xEmoji && Args.c3.emoji === xEmoji) won["<:X_:863314044781723668>"] = true;
if (Args.a3.emoji === xEmoji && Args.b2.emoji === xEmoji && Args.c1.emoji === xEmoji) won["<:X_:863314044781723668>"] = true;
if (Args.a1.emoji === xEmoji && Args.a2.emoji === xEmoji && Args.a3.emoji === xEmoji) won["<:X_:863314044781723668>"] = true;
if (Args.b1.emoji === xEmoji && Args.b2.emoji === xEmoji && Args.b3.emoji === xEmoji) won["<:X_:863314044781723668>"] = true;
if (Args.c1.emoji === xEmoji && Args.c2.emoji === xEmoji && Args.c3.emoji === xEmoji) won["<:X_:863314044781723668>"] = true;
if (won["<:X_:863314044781723668>"] !== false) {
if (Args.user === 0) {
const won = await client.users.fetch(fighters[1]).catch(console.error);
resolve(won);
if (options.resultBtn === true)
return m
.edit({
content: interaction.translate("fun/tictactoe:WON", {
winner: fighters[1],
emoji: client.emojis.cache.get(o_emoji) || "⭕",
}),
components: buttons,
embeds: [
epm.setDescription(
interaction.translate("fun/tictactoe:WON", {
winner: fighters[1],
emoji: client.emojis.cache.get(o_emoji) || "⭕",
}),
),
],
});
else if (!options.resultBtn || options.resultBtn === false)
return m
.edit({
content: interaction.translate("fun/tictactoe:WON", {
winner: fighters[1],
emoji: client.emojis.cache.get(o_emoji) || "⭕",
}),
embeds: [
epm.setDescription(
`${interaction.translate("fun/tictactoe:WON", {
winner: fighters[1],
emoji: client.emojis.cache.get(o_emoji) || "⭕",
})}\n\`\`\`\n${Args.a1.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.a2.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.a3.emoji
.replace(o_emoji, "⭕")
.replace(x_emoji, "❌")}\n${Args.b1.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.b2.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.b3.emoji
.replace(o_emoji, "⭕")
.replace(x_emoji, "❌")}\n${Args.c1.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.c2.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.c3.emoji
.replace(o_emoji, "⭕")
.replace(x_emoji, "❌")}\n\`\`\``.replaceAll(dashmoji, ""),
),
],
components: [],
});
} else if (Args.user == 1) {
if (options.resultBtn === true) {
return m.edit({
content: interaction.translate("fun/tictactoe:WON", {
winner: fighters[1],
emoji: client.emojis.cache.get(oEmoji) || "⭕",
}),
components: buttons,
embeds: [
epm.setDescription(
interaction.translate("fun/tictactoe:WON", {
winner: fighters[1],
emoji: client.emojis.cache.get(oEmoji) || "⭕",
}),
),
],
});
} else if (!options.resultBtn || options.resultBtn === false) {
return m.edit({
content: interaction.translate("fun/tictactoe:WON", {
winner: fighters[1],
emoji: client.emojis.cache.get(oEmoji) || "⭕",
}),
embeds: [
epm.setDescription(
`${interaction.translate("fun/tictactoe:WON", {
winner: fighters[1],
emoji: client.emojis.cache.get(oEmoji) || "⭕",
})}\n\`\`\`\n${Args.a1.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.a2.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.a3.emoji
.replace(oEmoji, "⭕")
.replace(xEmoji, "❌")}\n${Args.b1.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.b2.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.b3.emoji
.replace(oEmoji, "⭕")
.replace(xEmoji, "❌")}\n${Args.c1.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.c2.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.c3.emoji
.replace(oEmoji, "⭕")
.replace(xEmoji, "❌")}\n\`\`\``.replaceAll(dashmoji, ""),
),
],
components: [],
});
}
} else if (Args.user === 1) {
const won = await client.users.fetch(fighters[0]).catch(console.error);
resolve(won);
if (options.resultBtn === true)
return m
.edit({
content: interaction.translate("fun/tictactoe:WON", {
winner: fighters[0],
emoji: client.emojis.cache.get(o_emoji) || "⭕",
}),
components: buttons,
embeds: [
epm.setDescription(
interaction.translate("fun/tictactoe:WON", {
winner: fighters[0],
emoji: client.emojis.cache.get(o_emoji) || "⭕",
}),
),
],
});
else
return m
.edit({
content: interaction.translate("fun/tictactoe:WON", {
winner: fighters[0],
emoji: client.emojis.cache.get(o_emoji) || "⭕",
}),
embeds: [
epm.setDescription(
`${interaction.translate("fun/tictactoe:WON", {
winner: fighters[0],
emoji: client.emojis.cache.get(o_emoji) || "⭕",
})}\n\`\`\`\n${Args.a1.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.a2.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.a3.emoji
.replace(o_emoji, "⭕")
.replace(x_emoji, "❌")}\n${Args.b1.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.b2.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.b3.emoji
.replace(o_emoji, "⭕")
.replace(x_emoji, "❌")}\n${Args.c1.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.c2.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.c3.emoji
.replace(o_emoji, "⭕")
.replace(x_emoji, "❌")}\n\`\`\``.replaceAll(dashmoji, ""),
),
],
components: [],
});
if (options.resultBtn === true) {
return m.edit({
content: interaction.translate("fun/tictactoe:WON", {
winner: fighters[0],
emoji: client.emojis.cache.get(oEmoji) || "⭕",
}),
components: buttons,
embeds: [
epm.setDescription(
interaction.translate("fun/tictactoe:WON", {
winner: fighters[0],
emoji: client.emojis.cache.get(oEmoji) || "⭕",
}),
),
],
});
} else {
return m.edit({
content: interaction.translate("fun/tictactoe:WON", {
winner: fighters[0],
emoji: client.emojis.cache.get(oEmoji) || "⭕",
}),
embeds: [
epm.setDescription(
`${interaction.translate("fun/tictactoe:WON", {
winner: fighters[0],
emoji: client.emojis.cache.get(oEmoji) || "⭕",
})}\n\`\`\`\n${Args.a1.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.a2.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.a3.emoji
.replace(oEmoji, "⭕")
.replace(xEmoji, "❌")}\n${Args.b1.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.b2.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.b3.emoji
.replace(oEmoji, "⭕")
.replace(xEmoji, "❌")}\n${Args.c1.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.c2.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.c3.emoji
.replace(oEmoji, "⭕")
.replace(xEmoji, "❌")}\n\`\`\``.replaceAll(dashmoji, ""),
),
],
components: [],
});
}
}
}
m.edit({
content: `<@${Args.userid}>`,
@ -437,7 +442,7 @@ async function tictactoe(interaction, options = {}) {
epm.setDescription(
interaction.translate("fun/tictactoe:WAITING", {
user: Args.userid,
emoji: Args.user == 0 ? `${client.emojis.cache.get(o_emoji) || "⭕"}` : `${client.emojis.cache.get(x_emoji) || "❌"}`,
emoji: Args.user === 0 ? `${client.emojis.cache.get(oEmoji) || "⭕"}` : `${client.emojis.cache.get(xEmoji) || "❌"}`,
}),
),
],
@ -458,18 +463,18 @@ async function tictactoe(interaction, options = {}) {
ttt(m);
} else {
if (Args.user == 0) {
if (Args.user === 0) {
Args.user = 1;
Args[b.customId] = {
style: ButtonStyle.Success,
emoji: o_emoji,
emoji: oEmoji,
disabled: true,
};
} else {
Args.user = 0;
Args[b.customId] = {
style: ButtonStyle.Danger,
emoji: x_emoji,
emoji: xEmoji,
disabled: true,
};
}
@ -487,49 +492,49 @@ async function tictactoe(interaction, options = {}) {
.filter(key => predicate(obj[key]))
.reduce((res, key) => ((res[key] = obj[key]), res), {});
const Brgs = objectFilter(
map(Args, (_, fruit) => fruit.emoji == dashmoji),
num => num == true,
map(Args, (_, fruit) => fruit.emoji === dashmoji),
num => num === true,
);
if (Object.keys(Brgs).length == 0) {
if (Args.a1.emoji == o_emoji && Args.b1.emoji == o_emoji && Args.c1.emoji == o_emoji) won["<:O_:863314110560993340>"] = true;
if (Args.a2.emoji == o_emoji && Args.b2.emoji == o_emoji && Args.c2.emoji == o_emoji) won["<:O_:863314110560993340>"] = true;
if (Args.a3.emoji == o_emoji && Args.b3.emoji == o_emoji && Args.c3.emoji == o_emoji) won["<:O_:863314110560993340>"] = true;
if (Args.a1.emoji == o_emoji && Args.b2.emoji == o_emoji && Args.c3.emoji == o_emoji) won["<:O_:863314110560993340>"] = true;
if (Args.a3.emoji == o_emoji && Args.b2.emoji == o_emoji && Args.c1.emoji == o_emoji) won["<:O_:863314110560993340>"] = true;
if (Args.a1.emoji == o_emoji && Args.a2.emoji == o_emoji && Args.a3.emoji == o_emoji) won["<:O_:863314110560993340>"] = true;
if (Args.b1.emoji == o_emoji && Args.b2.emoji == o_emoji && Args.b3.emoji == o_emoji) won["<:O_:863314110560993340>"] = true;
if (Args.c1.emoji == o_emoji && Args.c2.emoji == o_emoji && Args.c3.emoji == o_emoji) won["<:O_:863314110560993340>"] = true;
if (Object.keys(Brgs).length === 0) {
if (Args.a1.emoji === oEmoji && Args.b1.emoji === oEmoji && Args.c1.emoji === oEmoji) won["<:O_:863314110560993340>"] = true;
if (Args.a2.emoji === oEmoji && Args.b2.emoji === oEmoji && Args.c2.emoji === oEmoji) won["<:O_:863314110560993340>"] = true;
if (Args.a3.emoji === oEmoji && Args.b3.emoji === oEmoji && Args.c3.emoji === oEmoji) won["<:O_:863314110560993340>"] = true;
if (Args.a1.emoji === oEmoji && Args.b2.emoji === oEmoji && Args.c3.emoji === oEmoji) won["<:O_:863314110560993340>"] = true;
if (Args.a3.emoji === oEmoji && Args.b2.emoji === oEmoji && Args.c1.emoji === oEmoji) won["<:O_:863314110560993340>"] = true;
if (Args.a1.emoji === oEmoji && Args.a2.emoji === oEmoji && Args.a3.emoji === oEmoji) won["<:O_:863314110560993340>"] = true;
if (Args.b1.emoji === oEmoji && Args.b2.emoji === oEmoji && Args.b3.emoji === oEmoji) won["<:O_:863314110560993340>"] = true;
if (Args.c1.emoji === oEmoji && Args.c2.emoji === oEmoji && Args.c3.emoji === oEmoji) won["<:O_:863314110560993340>"] = true;
if (won["<:O_:863314110560993340>"] == true) return ttt(m);
else if (won["<:X_:863314044781723668>"] == true) return;
if (won["<:O_:863314110560993340>"] === true) return ttt(m);
else if (won["<:X_:863314044781723668>"] === true) return;
else {
ttt(m);
if (options.resultBtn === true)
return m
.edit({
content: interaction.translate("fun/tictactoe:TIE"),
embeds: [epm.setDescription(interaction.translate("fun/tictactoe:TIE_DESC"))],
});
else
if (options.resultBtn === true) {
return m.edit({
content: interaction.translate("fun/tictactoe:TIE"),
embeds: [epm.setDescription(interaction.translate("fun/tictactoe:TIE_DESC"))],
});
} else {
return m
.edit({
content: interaction.translate("fun/tictactoe:TIE"),
embeds: [
epm.setDescription(
`${interaction.translate("fun/tictactoe:TIE_DESC")}!\n\`\`\`\n${Args.a1.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.a2.emoji
.replace(o_emoji, "⭕")
.replace(x_emoji, "❌")} | ${Args.a3.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")}\n${Args.b1.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.b2.emoji
.replace(o_emoji, "⭕")
.replace(x_emoji, "❌")} | ${Args.b3.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")}\n${Args.c1.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")} | ${Args.c2.emoji
.replace(o_emoji, "⭕")
.replace(x_emoji, "❌")} | ${Args.c3.emoji.replace(o_emoji, "⭕").replace(x_emoji, "❌")}\n\`\`\``.replaceAll(dashmoji, ""),
`${interaction.translate("fun/tictactoe:TIE_DESC")}!\n\`\`\`\n${Args.a1.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.a2.emoji
.replace(oEmoji, "⭕")
.replace(xEmoji, "❌")} | ${Args.a3.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")}\n${Args.b1.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.b2.emoji
.replace(oEmoji, "⭕")
.replace(xEmoji, "❌")} | ${Args.b3.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")}\n${Args.c1.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")} | ${Args.c2.emoji
.replace(oEmoji, "⭕")
.replace(xEmoji, "❌")} | ${Args.c3.emoji.replace(oEmoji, "⭕").replace(xEmoji, "❌")}\n\`\`\``.replaceAll(dashmoji, ""),
),
],
components: [],
})
.catch(() => {});
}
}
}
@ -537,20 +542,21 @@ async function tictactoe(interaction, options = {}) {
}
});
collector.on("end", (collected, reason) => {
if (collected.size === 0 && reason == "time")
if (collected.size === 0 && reason === "time") {
m.edit({
content: interaction.translate("fun/tictactoe:NO_ANSWER", {
user: Args.userid,
}),
components: [],
});
}
});
}
}
});
collector.on("end", (_, reason) => {
if (reason == "time") {
if (reason === "time") {
const embed = client.embed({
author: {
name: user.getUsername(),
@ -570,7 +576,7 @@ async function tictactoe(interaction, options = {}) {
components: [],
});
}
if (reason == "decline") {
if (reason === "decline") {
const embed = client.embed({
author: {
name: user.getUsername(),
@ -594,6 +600,4 @@ async function tictactoe(interaction, options = {}) {
console.log("TicTacToe errored:", e);
}
});
}
module.exports = tictactoe;
};

View file

@ -1,9 +1,13 @@
import "./helpers/extenders.js";
// import "./helpers/extenders.js";
// import { GatewayIntentBits } from "discord.js";
// import JaBaClient from "./base/Client.js";
// import languages from "./helpers/languages.js";
import { GatewayIntentBits } from "discord.js";
import Client from "./base/Client.js";
import { ExtendedClient } from "./base/newClient.js";
const client = new Client({
export const client = new ExtendedClient({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMembers,
@ -24,20 +28,43 @@ const client = new Client({
allowedMentions: { parse: ["everyone", "roles", "users"] },
});
(async () => {
console.time("botReady");
client.init();
client.translations = await require("./helpers/languages")();
// const client = new JaBaClient({
// intents: [
// GatewayIntentBits.Guilds,
// GatewayIntentBits.GuildMembers,
// GatewayIntentBits.GuildModeration,
// GatewayIntentBits.GuildEmojisAndStickers,
// GatewayIntentBits.GuildIntegrations,
// GatewayIntentBits.GuildInvites,
// GatewayIntentBits.GuildVoiceStates,
// GatewayIntentBits.GuildPresences,
// GatewayIntentBits.GuildMessages,
// GatewayIntentBits.GuildMessageReactions,
// GatewayIntentBits.GuildMessageTyping,
// GatewayIntentBits.MessageContent,
// GatewayIntentBits.DirectMessageTyping,
// GatewayIntentBits.DirectMessages,
// GatewayIntentBits.DirectMessageReactions,
// ],
// allowedMentions: { parse: ["everyone", "roles", "users"] },
// });
await client.loadEvents("../events");
await client.loadCommands("../commands");
await client.init();
})();
// (async () => {
// console.time("botReady");
client
.on("disconnect", () => client.logger.warn("Bot disconnected."))
.on("reconnecting", () => client.logger.warn("Bot reconnecting..."))
.on("warn", console.log)
.on("error", console.log);
// client.translations = await languages();
process.on("unhandledRejection", e => console.log(e)).on("uncaughtException", e => console.log(e));
// await client.loadEvents("../events");
// await client.loadCommands("../commands");
// await client.init();
// })();
// client
// .on("disconnect", () => client.logger.warn("Bot disconnected."))
// .on("reconnecting", () => client.logger.warn("Bot reconnecting..."))
// .on("warn", console.log)
// .on("error", console.log);
// process.on("unhandledRejection", e => console.log(e)).on("uncaughtException", e => console.log(e));

View file

@ -23,8 +23,6 @@
"AUTO_SANCTIONS": "Automatic Sanctions",
"BAN_CONTENT": "Ban: After **{{count}}** warnings",
"BAN_NOT_DEFINED": "Ban: Not set",
"DASHBOARD_TITLE": "Modify Settings",
"DASHBOARD_CONTENT": "Click here to go to the dashboard",
"GOODBYE_TITLE": "Farewell",
"GOODBYE_CONTENT": "Channel: {{channel}}\nCard: {{withImage}}",
"KICK_CONTENT": "Kick: After **{{count}}** warnings",

View file

@ -1,102 +0,0 @@
{
"name": "English",
"index": {
"feeds": [ "Current User", "Playing music in this much servers", "Users Count", "Servers Count" ],
"card": {
"category": "JaBa Bot",
"title": "Simple bot made by <a href=\"https://github.com/JonnyBro\">Jonny_Bro</a>",
"description": "Upper Text",
"image": "",
"footer": "Bottom Text"
},
"feedsTitle": "Feeds",
"graphTitle": "Graphs"
},
"manage": {
"settings": {
"memberCount": "Members",
"info": {
"info": "Info",
"server": "Server Information"
}
}
},
"privacyPolicy": {
"title": "Privacy Policy",
"description": "Privacy Policy and Terms of Service",
"pp": "Complete Privacy Policy"
},
"partials": {
"sidebar": {
"dash": "Dashboard",
"manage": "Manage Guilds",
"commands": "Commands",
"pp": "Privacy Policy",
"admin": "Admin",
"account": "Account Pages",
"login": "Sign In",
"logout": "Sign Out"
},
"navbar": {
"home": "Home",
"pages": {
"manage": "Manage Guilds",
"settings": "Manage Guilds",
"commands": "Commands",
"pp": "Privacy Policy",
"admin": "Admin Panel",
"error": "Error",
"credits": "Credits",
"debug": "Debug",
"leaderboard": "Leaderboard",
"profile": "Profile",
"maintenance": "Under Maintenance"
}
},
"title": {
"pages": {
"manage": "Manage Guilds",
"settings": "Manage Guilds",
"commands": "Commands",
"pp": "Privacy Policy",
"admin": "Admin Panel",
"error": "Error",
"credits": "Credits",
"debug": "Debug",
"leaderboard": "Leaderboard",
"profile": "Profile",
"maintenance": "Under Maintenance"
}
},
"notify": {
"errors": {
"settingsSave": "Failed to save setttings"
},
"success": {
"settingsSave": "Successfully saved setttings.",
"login": "Successfully logged in.",
"logout": "Successfully logged out."
}
},
"preloader": {
"text": "Page is loading..."
},
"premium": {
"title": "Want more from JaBa?",
"description": "Check out premium features below!",
"buttonText": "Become Premium"
},
"settings": {
"title": "Site Configuration",
"description": "Configurable Viewing Options",
"theme": {
"title": "Site Theme",
"description": "Make the site more appealing for your eyes!"
},
"language": {
"title": "Site Language",
"description": "Select your preffered language!"
}
}
}
}

View file

@ -15,7 +15,7 @@
"OPTION_NAN_ALL": "Please specify an integer greater than 0 or `all`.",
"OWNER_ONLY": "Only the bot owner can use this command.",
"SELECT_CANCELED": "Selection canceled.",
"STATS_FOOTER": "● [Dashboard]({{dashboardLink}})\n● [Support Server]({{supportLink}})\n● [Invite JaBa to Your Server]({{inviteLink}})",
"STATS_FOOTER": "● [Support Server]({{supportLink}})\n● [Invite JaBa to Your Server]({{inviteLink}})",
"TIMED_OUT": "Time out.",
"JUMP_TO_PAGE": "Specify the page you want to jump to (maximum **{{length}}**):",
"QUOTE_TITLE": "Message from {{user}}",

View file

@ -0,0 +1,23 @@
export default [
{
name: "en-US",
nativeName: "English",
moment: "en",
defaultMomentFormat: "HH:mm:ss, MMMM Do YYYY",
default: true,
},
{
name: "ru-RU",
nativeName: "Русский",
moment: "ru",
defaultMomentFormat: "HH:mm:ss, Do MMMM YYYY",
default: false,
},
{
name: "uk-UA",
nativeName: "Українська",
moment: "uk",
defaultMomentFormat: "HH:mm:ss, Do MMMM YYYY",
default: false,
},
];

View file

@ -1,23 +0,0 @@
[
{
"name": "en-US",
"nativeName": "English",
"moment": "en",
"defaultMomentFormat": "HH:mm:ss, MMMM Do YYYY",
"default": true
},
{
"name": "ru-RU",
"nativeName": "Русский",
"moment": "ru",
"defaultMomentFormat": "HH:mm:ss, Do MMMM YYYY",
"default": false
},
{
"name": "uk-UA",
"nativeName": "Українська",
"moment": "uk",
"defaultMomentFormat": "HH:mm:ss, Do MMMM YYYY",
"default": false
}
]

View file

@ -23,8 +23,6 @@
"AUTO_SANCTIONS": "Автоматические наказания",
"BAN_CONTENT": "Бан: После **{{count}}** предупреждений",
"BAN_NOT_DEFINED": "Бан: Не назначено",
"DASHBOARD_TITLE": "Изменить настройки",
"DASHBOARD_CONTENT": "Нажмите сюда, чтобы перейти в панель управления",
"GOODBYE_TITLE": "Прощание",
"GOODBYE_CONTENT": "Канал: {{channel}}\nКарточка: {{withImage}}",
"KICK_CONTENT": "Кик: После **{{count}}** предупреждений",

View file

@ -1,102 +0,0 @@
{
"name": "Русский",
"index": {
"feeds": [ "Текущий пользователь", "Играю музыку в стольких серверах", "Кол-во пользователей", "Кол-во серверов" ],
"card": {
"category": "JaBa Bot",
"title": "Простой бот, созданный <a href=\"https://github.com/JonnyBro\">Jonny_Bro</a>",
"description": "Верхний текст",
"image": "",
"footer": "Нижний текст"
},
"feedsTitle": "Новости",
"graphTitle": "Графики"
},
"manage": {
"settings": {
"memberCount": "Участники",
"info": {
"info": "Информация",
"server": "Информация о сервере"
}
}
},
"privacyPolicy": {
"title": "Политика конф.",
"description": "Политика конфиденциальности и Условия использования",
"pp": "Полная политика конфиденциальности"
},
"partials": {
"sidebar": {
"dash": "Панель управления",
"manage": "Сервера",
"commands": "Команды",
"pp": "Политика конф.",
"admin": "Админ панель",
"account": "Аккаунт",
"login": "Войти",
"logout": "Выйти"
},
"navbar": {
"home": "Главная",
"pages": {
"manage": "Настройки серверов",
"settings": "Настройки",
"commands": "Команды",
"pp": "Политика конфиденциальности",
"admin": "Админ панель",
"error": "Ошибка",
"credits": "Разработчики панели",
"debug": "Отладка",
"leaderboard": "Таблица лидеров",
"profile": "Профиль",
"maintenance": "Техобслуживание"
}
},
"title": {
"pages": {
"manage": "Настройки серверов",
"settings": "Настройки",
"commands": "Команды",
"pp": "Политика конфиденциальности",
"admin": "Админ панель",
"error": "Ошибка",
"credits": "Разработчики панели",
"debug": "Отладка",
"leaderboard": "Таблица лидеров",
"profile": "Профиль",
"maintenance": "Техобслуживание"
}
},
"notify": {
"errors": {
"settingsSave": "Произошла ошибка при сохранении настроек."
},
"success": {
"settingsSave": "Настройки успешно сохранены.",
"login": "Вход успешно выполнен.",
"logout": "Выход успешно выполнен."
}
},
"preloader": {
"text": "Загрузка..."
},
"premium": {
"title": "Хотите большего JaBa?",
"description": "Проверьте Премиум функции!",
"buttonText": "Стать Премиум"
},
"settings": {
"title": "Настройки сайта",
"description": "Настройте параметры панели управления",
"theme": {
"title": "Тема",
"description": "У нас есть тёмная и светлая!"
},
"language": {
"title": "Язык",
"description": "Выберите предпочитаемый язык!"
}
}
}
}

View file

@ -15,7 +15,7 @@
"OPTION_NAN_ALL": "Укажите целое число больше 0 или `all`",
"OWNER_ONLY": "Данную команду может использовать только владелец бота",
"SELECT_CANCELED": "Выбор отменён",
"STATS_FOOTER": "● [Панель управления]({{dashboardLink}})\n● [Сервер поддержки]({{supportLink}})\n● [Пригласить JaBa на свой сервер]({{inviteLink}})",
"STATS_FOOTER": "● [Сервер поддержки]({{supportLink}})\n● [Пригласить JaBa на свой сервер]({{inviteLink}})",
"TIMED_OUT": "Время вышло",
"JUMP_TO_PAGE": "Укажите страницу к которой хотите перейти (максимум **{{length}}**):",
"QUOTE_TITLE": "Сообщение от {{user}}",

View file

@ -23,8 +23,6 @@
"AUTO_SANCTIONS": "Автоматичні покарання",
"BAN_CONTENT": "Бан: Після **{{count}}** попереджень",
"BAN_NOT_DEFINED": "Бан: Не призначено",
"DASHBOARD_TITLE": "Змінити налаштування",
"DASHBOARD_CONTENT": "Натисніть сюди, щоб перейти до панелі керування",
"GOODBYE_TITLE": "Прощання",
"GOODBYE_CONTENT": "Канал: {{channel}}\nКартка: {{withImage}}",
"KICK_CONTENT": "Кік: Після **{{count}}** попереджень",

View file

@ -1,102 +0,0 @@
{
"name": "Українська",
"index": {
"feeds": [ "Поточний Користувач", "Играю музыку в стольких серверах", "Кількість користувачів", "Кількість серверів" ],
"card": {
"category": "JaBa Бот",
"title": "Простий бот, створений <a href=\"https://github.com/JonnyBro\">Jonny_Bro</a>",
"description": "Верхній Текст",
"image": "",
"footer": "Нижній Текст"
},
"feedsTitle": "Канали",
"graphTitle": "Графіки"
},
"manage": {
"settings": {
"memberCount": "Учасники",
"info": {
"info": "Інформація",
"server": "Інформація про Сервер"
}
}
},
"privacyPolicy": {
"title": "Політика Конфіденційності",
"description": "Політика Конфіденційності та Умови Сервісу",
"pp": "Повна Політика Конфіденційності"
},
"partials": {
"sidebar": {
"dash": "Панель Керування",
"manage": "Налаштування серверів",
"commands": "Команди",
"pp": "Політика Конфіденційності",
"admin": "Адмін",
"account": "Сторінки Аккаунта",
"login": "Увійти",
"logout": "Вийти"
},
"navbar": {
"home": "Головна",
"pages": {
"manage": "Налаштування серверів",
"settings": "Керувати",
"commands": "Команди",
"pp": "Політика Конфіденційності",
"admin": "Панель Адміністратора",
"error": "Помилка",
"credits": "Автори",
"debug": "Налагодження",
"leaderboard": "Таблиця Лідерів",
"profile": "Профіль",
"maintenance": "Технічне Обслуговування"
}
},
"title": {
"pages": {
"manage": "Керувати Гілдіями",
"settings": "Керувати",
"commands": "Команди",
"pp": "Політика Конфіденційності",
"admin": "Панель Адміністратора",
"error": "Помилка",
"credits": "Автори",
"debug": "Налагодження",
"leaderboard": "Таблиця Лідерів",
"profile": "Профіль",
"maintenance": "Технічне Обслуговування"
}
},
"notify": {
"errors": {
"settingsSave": "Сталася помилка при збереженні налаштувань."
},
"success": {
"settingsSave": "Налаштування успішно збережені.",
"login": "Успішний вхід.",
"logout": "Успішний вихід."
}
},
"preloader": {
"text": "Завантаження..."
},
"premium": {
"title": "Бажаєте більше від JaBa?",
"description": "Ознайомтесь з преміум-функціями нижче!",
"buttonText": "Стати Преміум"
},
"settings": {
"title": "Налаштування Сайту",
"description": "Налаштовувані параметри перегляду",
"theme": {
"title": "Тема",
"description": "Зробіть сайт більш привабливим для своїх очей!"
},
"language": {
"title": "Мова",
"description": "Виберіть бажану мову!"
}
}
}
}

View file

@ -15,7 +15,7 @@
"OPTION_NAN_ALL": "Вкажіть ціле число більше 0 або `all`",
"OWNER_ONLY": "Цю команду може використовувати тільки власник бота",
"SELECT_CANCELED": "Вибір скасовано",
"STATS_FOOTER": "● [Панель керування]({{dashboardLink}})\n● [Сервер підтримки]({{supportLink}})\n● [Запросити JaBa на свій сервер]({{inviteLink}})",
"STATS_FOOTER": "● [Сервер підтримки]({{supportLink}})\n● [Запросити JaBa на свій сервер]({{inviteLink}})",
"TIMED_OUT": "Час вийшов",
"JUMP_TO_PAGE": "Вкажіть сторінку, до якої хочете перейти (максимум **{{length}}**):",
"QUOTE_TITLE": "Повідомлення від {{user}}",

10
newCommands/Fun/8ball.js Normal file
View file

@ -0,0 +1,10 @@
import { SlashCommandBuilder } from "discord.js";
import Command from "../../base/newCommand.js";
export default new Command({
data: new SlashCommandBuilder().setName("8ball").setDescription("8ball"),
execute(interaction) {
console.log("8ball");
interaction.reply("8ball");
},
});

View file

@ -22,6 +22,7 @@
"discord-player-youtubei": "1.3.5",
"discord.js": "^14.16.3",
"gamedig": "^5.1.4",
"glob": "^11.0.0",
"i18next": "^24.0.0",
"i18next-fs-backend": "^2.6.0",
"md5": "^2.3.0",

View file

@ -47,6 +47,9 @@ importers:
gamedig:
specifier: ^5.1.4
version: 5.1.4
glob:
specifier: ^11.0.0
version: 11.0.0
i18next:
specifier: ^24.0.0
version: 24.0.0(typescript@5.7.2)
@ -227,6 +230,10 @@ packages:
resolution: {integrity: sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==}
engines: {node: '>=18.18'}
'@isaacs/cliui@8.0.2':
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
'@jest/schemas@29.6.3':
resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@ -441,6 +448,10 @@ packages:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
ansi-regex@6.1.0:
resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==}
engines: {node: '>=12'}
ansi-styles@2.2.1:
resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==}
engines: {node: '>=0.10.0'}
@ -453,6 +464,10 @@ packages:
resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
engines: {node: '>=10'}
ansi-styles@6.2.1:
resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
engines: {node: '>=12'}
any-promise@1.3.0:
resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
@ -667,9 +682,15 @@ packages:
domutils@3.1.0:
resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==}
eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
entities@4.5.0:
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
engines: {node: '>=0.12'}
@ -793,6 +814,10 @@ packages:
flatted@3.3.1:
resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==}
foreground-child@3.3.0:
resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==}
engines: {node: '>=14'}
form-data-encoder@2.1.4:
resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==}
engines: {node: '>= 14.17'}
@ -837,6 +862,11 @@ packages:
resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
engines: {node: '>=10.13.0'}
glob@11.0.0:
resolution: {integrity: sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==}
engines: {node: 20 || >=22}
hasBin: true
glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
deprecated: Glob versions prior to v9 are no longer supported
@ -976,6 +1006,10 @@ packages:
isomorphic-unfetch@4.0.2:
resolution: {integrity: sha512-1Yd+CF/7al18/N2BDbsLBcp6RO3tucSW+jcLq24dqdX5MNbCNTw1z4BsGsp4zNmjr/Izm2cs/cEqZPp4kvWSCA==}
jackspeak@4.0.2:
resolution: {integrity: sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==}
engines: {node: 20 || >=22}
jintr@3.0.2:
resolution: {integrity: sha512-5g2EBudeJFOopjAX4exAv5OCCW1DgUISfoioCsm1h9Q9HJ41LmnZ6J52PCsqBlQihsmp0VDuxreAVzM7yk5nFA==}
@ -1039,6 +1073,10 @@ packages:
resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
lru-cache@11.0.2:
resolution: {integrity: sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==}
engines: {node: 20 || >=22}
luxon@3.5.0:
resolution: {integrity: sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==}
engines: {node: '>=12'}
@ -1072,6 +1110,10 @@ packages:
resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
minimatch@10.0.1:
resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==}
engines: {node: 20 || >=22}
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
@ -1090,6 +1132,10 @@ packages:
resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==}
engines: {node: '>=8'}
minipass@7.1.2:
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
engines: {node: '>=16 || 14 >=14.17'}
minizlib@2.1.2:
resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==}
engines: {node: '>= 8'}
@ -1212,6 +1258,9 @@ packages:
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
engines: {node: '>=10'}
package-json-from-dist@1.0.1:
resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
@ -1234,6 +1283,10 @@ packages:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
path-scurry@2.0.0:
resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==}
engines: {node: 20 || >=22}
path-type@4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
@ -1399,6 +1452,10 @@ packages:
signal-exit@3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
signal-exit@4.1.0:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
slash@3.0.0:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'}
@ -1435,6 +1492,10 @@ packages:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
string-width@5.1.2:
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
engines: {node: '>=12'}
string_decoder@0.10.31:
resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==}
@ -1452,6 +1513,10 @@ packages:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
strip-ansi@7.1.0:
resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
engines: {node: '>=12'}
strip-json-comments@3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
@ -1581,6 +1646,14 @@ packages:
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
engines: {node: '>=0.10.0'}
wrap-ansi@7.0.0:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
engines: {node: '>=10'}
wrap-ansi@8.1.0:
resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
engines: {node: '>=12'}
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
@ -1820,6 +1893,15 @@ snapshots:
'@humanwhocodes/retry@0.4.1': {}
'@isaacs/cliui@8.0.2':
dependencies:
string-width: 5.1.2
string-width-cjs: string-width@4.2.3
strip-ansi: 7.1.0
strip-ansi-cjs: strip-ansi@6.0.1
wrap-ansi: 8.1.0
wrap-ansi-cjs: wrap-ansi@7.0.0
'@jest/schemas@29.6.3':
dependencies:
'@sinclair/typebox': 0.27.8
@ -2003,6 +2085,8 @@ snapshots:
ansi-regex@5.0.1: {}
ansi-regex@6.1.0: {}
ansi-styles@2.2.1: {}
ansi-styles@4.3.0:
@ -2011,6 +2095,8 @@ snapshots:
ansi-styles@5.2.0: {}
ansi-styles@6.2.1: {}
any-promise@1.3.0: {}
aproba@2.0.0: {}
@ -2258,8 +2344,12 @@ snapshots:
domelementtype: 2.3.0
domhandler: 5.0.3
eastasianwidth@0.2.0: {}
emoji-regex@8.0.0: {}
emoji-regex@9.2.2: {}
entities@4.5.0: {}
escape-string-regexp@1.0.5: {}
@ -2447,6 +2537,11 @@ snapshots:
flatted@3.3.1: {}
foreground-child@3.3.0:
dependencies:
cross-spawn: 7.0.6
signal-exit: 4.1.0
form-data-encoder@2.1.4: {}
formdata-polyfill@4.0.10:
@ -2505,6 +2600,15 @@ snapshots:
dependencies:
is-glob: 4.0.3
glob@11.0.0:
dependencies:
foreground-child: 3.3.0
jackspeak: 4.0.2
minimatch: 10.0.1
minipass: 7.1.2
package-json-from-dist: 1.0.1
path-scurry: 2.0.0
glob@7.2.3:
dependencies:
fs.realpath: 1.0.0
@ -2643,6 +2747,10 @@ snapshots:
node-fetch: 3.3.2
unfetch: 5.0.0
jackspeak@4.0.2:
dependencies:
'@isaacs/cliui': 8.0.2
jintr@3.0.2:
dependencies:
acorn: 8.12.1
@ -2698,6 +2806,8 @@ snapshots:
lowercase-keys@3.0.0: {}
lru-cache@11.0.2: {}
luxon@3.5.0: {}
magic-bytes.js@1.10.0: {}
@ -2725,6 +2835,10 @@ snapshots:
mimic-response@4.0.0: {}
minimatch@10.0.1:
dependencies:
brace-expansion: 2.0.1
minimatch@3.1.2:
dependencies:
brace-expansion: 1.1.11
@ -2741,6 +2855,8 @@ snapshots:
minipass@5.0.0: {}
minipass@7.1.2: {}
minizlib@2.1.2:
dependencies:
minipass: 3.3.6
@ -2855,6 +2971,8 @@ snapshots:
dependencies:
p-limit: 3.1.0
package-json-from-dist@1.0.1: {}
parent-module@1.0.1:
dependencies:
callsites: 3.1.0
@ -2874,6 +2992,11 @@ snapshots:
path-key@3.1.1: {}
path-scurry@2.0.0:
dependencies:
lru-cache: 11.0.2
minipass: 7.1.2
path-type@4.0.0: {}
peek-readable@4.1.0: {}
@ -3012,6 +3135,8 @@ snapshots:
signal-exit@3.0.7: {}
signal-exit@4.1.0: {}
slash@3.0.0: {}
smart-buffer@4.2.0:
@ -3052,6 +3177,12 @@ snapshots:
is-fullwidth-code-point: 3.0.0
strip-ansi: 6.0.1
string-width@5.1.2:
dependencies:
eastasianwidth: 0.2.0
emoji-regex: 9.2.2
strip-ansi: 7.1.0
string_decoder@0.10.31: {}
string_decoder@1.1.1:
@ -3070,6 +3201,10 @@ snapshots:
dependencies:
ansi-regex: 5.0.1
strip-ansi@7.1.0:
dependencies:
ansi-regex: 6.1.0
strip-json-comments@3.1.1: {}
strtok3@6.3.0:
@ -3186,6 +3321,18 @@ snapshots:
word-wrap@1.2.5: {}
wrap-ansi@7.0.0:
dependencies:
ansi-styles: 4.3.0
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi@8.1.0:
dependencies:
ansi-styles: 6.2.1
string-width: 5.1.2
strip-ansi: 7.1.0
wrappy@1.0.2: {}
ws@8.18.0: {}