From cb8139b8a00daa38e0b124929011f3300a3adbb1 Mon Sep 17 00:00:00 2001 From: DJj123dj <80536295+DJj123dj@users.noreply.github.com> Date: Mon, 16 Feb 2026 22:12:25 +0100 Subject: [PATCH] (v4.2) Open Discord Framework Update (Part 1) --- index.js | 162 +- package.json | 1 + plugins/example-plugin/index.ts | 2 +- src/core/api/api.ts | 42 +- src/core/api/defaults/action.ts | 22 +- src/core/api/defaults/base.ts | 26 +- src/core/api/defaults/builder.ts | 181 +- src/core/api/defaults/checker.ts | 55 +- src/core/api/defaults/client.ts | 167 +- src/core/api/defaults/code.ts | 49 +- src/core/api/defaults/config.ts | 34 +- src/core/api/defaults/console.ts | 19 +- src/core/api/defaults/cooldown.ts | 17 +- src/core/api/defaults/database.ts | 147 +- src/core/api/defaults/event.ts | 428 +++-- src/core/api/defaults/flag.ts | 49 +- src/core/api/defaults/fuse.ts | 27 + src/core/api/defaults/helpmenu.ts | 173 +- src/core/api/defaults/language.ts | 99 +- src/core/api/defaults/permission.ts | 7 +- src/core/api/defaults/plugin.ts | 31 +- src/core/api/defaults/post.ts | 21 +- src/core/api/defaults/progressbar.ts | 60 +- src/core/api/defaults/responder.ts | 113 +- src/core/api/defaults/session.ts | 17 +- src/core/api/defaults/startscreen.ts | 31 +- src/core/api/defaults/stat.ts | 327 ++-- src/core/api/defaults/verifybar.ts | 24 +- src/core/api/defaults/worker.ts | 22 +- src/core/api/main.ts | 274 ++- src/core/api/modules/action.ts | 58 - src/core/api/modules/base.ts | 763 -------- src/core/api/modules/builder.ts | 1554 ---------------- src/core/api/modules/checker.ts | 1549 ---------------- src/core/api/modules/client.ts | 2247 ----------------------- src/core/api/modules/code.ts | 58 - src/core/api/modules/config.ts | 159 -- src/core/api/modules/console.ts | 665 ------- src/core/api/modules/cooldown.ts | 348 ---- src/core/api/modules/database.ts | 278 --- src/core/api/modules/defaults.ts | 366 ---- src/core/api/modules/event.ts | 99 - src/core/api/modules/flag.ts | 73 - src/core/api/modules/helpmenu.ts | 216 --- src/core/api/modules/language.ts | 201 -- src/core/api/modules/permission.ts | 340 ---- src/core/api/modules/plugin.ts | 242 --- src/core/api/modules/post.ts | 90 - src/core/api/modules/progressbar.ts | 232 --- src/core/api/modules/responder.ts | 1418 -------------- src/core/api/modules/session.ts | 155 -- src/core/api/modules/startscreen.ts | 320 ---- src/core/api/modules/stat.ts | 313 ---- src/core/api/modules/verifybar.ts | 61 - src/core/api/modules/worker.ts | 93 - src/core/api/openticket/blacklist.ts | 11 +- src/core/api/openticket/option.ts | 98 +- src/core/api/openticket/panel.ts | 37 +- src/core/api/openticket/priority.ts | 25 +- src/core/api/openticket/question.ts | 53 +- src/core/api/openticket/role.ts | 37 +- src/core/api/openticket/ticket.ts | 37 +- src/core/api/openticket/transcript.ts | 49 +- src/core/cli/editConfig.ts | 2 +- src/core/cli/quickSetup.ts | 4 +- src/core/startup/dump.ts | 49 - src/core/startup/init.ts | 281 --- src/core/startup/manageMigration.ts | 10 +- src/core/startup/migration.ts | 26 +- src/core/startup/pluginLauncher.ts | 260 --- src/data/framework/checkerLoader.ts | 4 +- src/data/framework/codeLoader.ts | 8 +- src/data/framework/liveStatusLoader.ts | 2 +- src/data/openticket/transcriptLoader.ts | 4 +- src/index.ts | 224 ++- 75 files changed, 1494 insertions(+), 14252 deletions(-) create mode 100644 src/core/api/defaults/fuse.ts delete mode 100644 src/core/api/modules/action.ts delete mode 100644 src/core/api/modules/base.ts delete mode 100644 src/core/api/modules/builder.ts delete mode 100644 src/core/api/modules/checker.ts delete mode 100644 src/core/api/modules/client.ts delete mode 100644 src/core/api/modules/code.ts delete mode 100644 src/core/api/modules/config.ts delete mode 100644 src/core/api/modules/console.ts delete mode 100644 src/core/api/modules/cooldown.ts delete mode 100644 src/core/api/modules/database.ts delete mode 100644 src/core/api/modules/defaults.ts delete mode 100644 src/core/api/modules/event.ts delete mode 100644 src/core/api/modules/flag.ts delete mode 100644 src/core/api/modules/helpmenu.ts delete mode 100644 src/core/api/modules/language.ts delete mode 100644 src/core/api/modules/permission.ts delete mode 100644 src/core/api/modules/plugin.ts delete mode 100644 src/core/api/modules/post.ts delete mode 100644 src/core/api/modules/progressbar.ts delete mode 100644 src/core/api/modules/responder.ts delete mode 100644 src/core/api/modules/session.ts delete mode 100644 src/core/api/modules/startscreen.ts delete mode 100644 src/core/api/modules/stat.ts delete mode 100644 src/core/api/modules/verifybar.ts delete mode 100644 src/core/api/modules/worker.ts delete mode 100644 src/core/startup/dump.ts delete mode 100644 src/core/startup/init.ts delete mode 100644 src/core/startup/pluginLauncher.ts diff --git a/index.js b/index.js index 6cead33..e456948 100644 --- a/index.js +++ b/index.js @@ -4,7 +4,6 @@ const flags = [ //PTERODACTYL PANEL //add startup flags here (e.g. "--no-compile") when running via the panel ] -process.argv.push(...flags) /////////////// STARTUP FLAGS /////////////// /* @@ -21,163 +20,12 @@ process.argv.push(...flags) Support Us: https://github.com/sponsors/DJj123dj/ */ + /////////////////////////////////////////// ////////// COMPILATION + STARTUP ////////// /////////////////////////////////////////// -const fs = require("fs") -const ts = require("typescript") -const {createHash,Hash} = require("crypto") -const nodepath = require('path') -const ansis = require("ansis") -/** ## What is this? - * This is a function which compares `./src/` with a hash stored in `./dist/hash.txt`. - * The hash is based on the modified date & file metadata of all files in `./src/`. - * - * If the hash is different, the bot will automatically re-compile. - * This will help you save CPU resources because the bot shouldn't re-compile when nothing has been changed :) - * - * @param {string} dir - * @param {Hash|null} upperHash - */ -function computeSourceHash(dir,upperHash){ - const hash = upperHash ? upperHash : createHash("sha256") - const info = fs.readdirSync(dir,{withFileTypes:true}) - - for (const file of info) { - const fullPath = nodepath.join(dir,file.name) - if (file.isFile() && [".js",".ts",".jsx",".tsx"].some((ext) => file.name.endsWith(ext))){ - const statInfo = fs.statSync(fullPath) - //compute hash using file metadata - const fileInfo = `${fullPath}:${statInfo.size}:${statInfo.mtimeMs}` - hash.update(fileInfo) - - }else if (file.isDirectory()){ - //recursively compute all folders - computeSourceHash(fullPath,hash) - } - } - //return when not being called recursively - if (!upperHash) { - return hash.digest("hex") - } -} -function requiresCompilation(){ - //check hashes when not using "--compile-only" flag - if (process.argv.includes("--compile-only")) return true - - console.log("OT: Comparing prebuilds with source...") - const sourceHash = computeSourceHash("./src/") - const pluginHash = computeSourceHash("./plugins/") - const hash = sourceHash+":"+pluginHash - - if (fs.existsSync("./dist/hash.txt")){ - const distHash = fs.readFileSync("./dist/hash.txt").toString() - if (distHash === hash) return false - else return true - }else return true -} -function saveNewCompilationHash(){ - const sourceHash = computeSourceHash("./src/") - const pluginHash = computeSourceHash("./plugins/") - const hash = sourceHash+":"+pluginHash - fs.writeFileSync("./dist/hash.txt",hash) -} - -if (!process.argv.includes("--no-compile")){ - const requiredDependencies = new Set() - if (fs.existsSync("./plugins")){ - console.log("OT: Reading plugin.json files...") - for (const pluginDir of fs.readdirSync("./plugins")){ - if (pluginDir === ".DS_Store") continue - const pluginPath = nodepath.join("./plugins", pluginDir) - if (!fs.statSync(pluginPath).isDirectory()) continue - - const pluginJsonPath = nodepath.join(pluginPath, "plugin.json") - if (fs.existsSync(pluginJsonPath)){ - try{ - const pluginData = JSON.parse(fs.readFileSync(pluginJsonPath).toString()) - if (pluginData.npmDependencies && Array.isArray(pluginData.npmDependencies)){ - pluginData.npmDependencies.forEach((dep) => { - if (typeof dep === "string" && dep.trim()){ - requiredDependencies.add(dep.trim()) - } - }) - } - }catch(err){ - // skip invalid plugin.json files, will be caught later - } - } - } - - if (requiredDependencies.size > 0){ - console.log("OT: Checking plugin npm dependencies...") - /**@type {string[]} */ - const missingDeps = [] - for (const dep of requiredDependencies){ - try{ - require.resolve(dep) - }catch(err){ - missingDeps.push(dep) - } - } - - if (missingDeps.length > 0){ - console.log(ansis.red("OT: ❌ Fatal Error --> Missing npm dependencies required by plugins:\n\n")+ansis.cyan(missingDeps.map((dep) => " - "+dep).join("\n")+"\n")) - console.log("OT: Please install missing dependencies using the following command:\n> "+ansis.bold.green("npm install " + missingDeps.join(" "))+"\n") - process.exit(1) - } - } - } - - if (requiresCompilation()){ - console.log("OT: Compilation Required...") - - //REMOVE EXISTING BUILDS - console.log("OT: Removing Prebuilds...") - fs.rmSync("./dist",{recursive:true,force:true}) - - //COMPILE TYPESCRIPT - console.log("OT: Compiling Typescript...") - const configPath = nodepath.resolve('./tsconfig.json') - const configFile = ts.readConfigFile(configPath,ts.sys.readFile) - - //check for tsconfig errors - if (configFile.error){ - const message = ts.formatDiagnosticsWithColorAndContext([configFile.error],ts.createCompilerHost({})) - console.error(message) - process.exit(1) - } - - //parse tsconfig file - const parsedConfig = ts.parseJsonConfigFileContent(configFile.config,ts.sys,nodepath.dirname(configPath)) - - //create program/compiler - const program = ts.createProgram({ - rootNames:parsedConfig.fileNames, - options:parsedConfig.options - }) - - //emit all compiled files - const emitResult = program.emit() - - //print emit errors/warnings (type errors) - const allDiagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics) - const formattedDiagnostics = ts.formatDiagnosticsWithColorAndContext(allDiagnostics, ts.createCompilerHost(parsedConfig.options)) - console.log(formattedDiagnostics) - - if (emitResult.emitSkipped || allDiagnostics.find((d) => d.category == ts.DiagnosticCategory.Error || d.category == ts.DiagnosticCategory.Warning)){ - console.log("OT: Compilation Failed!") - process.exit(1) - } - }else console.log("OT: No Compilation Required...") - - //save new compilation hash - saveNewCompilationHash() -} - -//START BOT -console.log("OT: Compilation Succeeded!") -if (process.argv.includes("--compile-only")) process.exit(0) //exit when only compile is required! -console.log("OT: Starting Bot!") -require("./dist/src/index.js") \ No newline at end of file +const framework = require("@open-discord-bots/framework") +framework.frameworkStartup(flags,"openticket",() => { + require("./dist/src/index.js") +}) \ No newline at end of file diff --git a/package.json b/package.json index 087e7b3..5768e21 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "license": "GPL-3.0-only", "dependencies": { "@discordjs/rest": "^2.6.0", + "@open-discord-bots/framework": "^0.1.2", "@types/node": "^22.5.0", "@types/terminal-kit": "^2.5.7", "ansis": "^4.2.0", diff --git a/plugins/example-plugin/index.ts b/plugins/example-plugin/index.ts index 5441b05..97b70ba 100644 --- a/plugins/example-plugin/index.ts +++ b/plugins/example-plugin/index.ts @@ -6,7 +6,7 @@ import * as discord from "discord.js" //// Enable it in the plugin.json file! //// ///////////////////////////////////////////// -if (utilities.project != "openticket") throw new api.ODPluginError("This plugin only works in Open Ticket!") +if (opendiscord.project != "openticket") throw new api.ODPluginError("This plugin only works in Open Ticket!") //Add Typescript autocomplete support for plugin data. (!!!OPTIONAL!!!) declare module "#opendiscord-types" { diff --git a/src/core/api/api.ts b/src/core/api/api.ts index 7286d8f..5ec6201 100644 --- a/src/core/api/api.ts +++ b/src/core/api/api.ts @@ -1,34 +1,7 @@ -//MAIN MODULE -export * from "./main" +//EXPORT FRAMEWORK +export * from "@open-discord-bots/framework/api" -//BASE MODULES -export * from "./modules/base" -export * from "./modules/event" -export * from "./modules/config" -export * from "./modules/database" -export * from "./modules/language" -export * from "./modules/flag" -export * from "./modules/console" -export * from "./modules/defaults" -export * from "./modules/plugin" -export * from "./modules/checker" -export * from "./modules/client" -export * from "./modules/worker" -export * from "./modules/builder" -export * from "./modules/responder" -export * from "./modules/action" -export * from "./modules/permission" -export * from "./modules/helpmenu" -export * from "./modules/session" -export * from "./modules/stat" -export * from "./modules/code" -export * from "./modules/cooldown" -export * from "./modules/post" -export * from "./modules/verifybar" -export * from "./modules/progressbar" -export * from "./modules/startscreen" - -//OPENTICKET DEFAULT MODULES +//EXPORT DEFAULT MODULES export * from "./defaults/base" export * from "./defaults/event" export * from "./defaults/config" @@ -52,8 +25,10 @@ export * from "./defaults/post" export * from "./defaults/progressbar" export * from "./defaults/startscreen" export * from "./defaults/console" +export * from "./defaults/verifybar" +export * from "./defaults/fuse" -//OPENTICKET MODULES +//EXPORT OPENTICKET MODULES export * from "./openticket/question" export * from "./openticket/option" export * from "./openticket/panel" @@ -61,4 +36,7 @@ export * from "./openticket/ticket" export * from "./openticket/blacklist" export * from "./openticket/transcript" export * from "./openticket/role" -export * from "./openticket/priority" \ No newline at end of file +export * from "./openticket/priority" + +//EXPORT MAIN MODULE +export { ODOpenTicketMain } from "./main" \ No newline at end of file diff --git a/src/core/api/defaults/action.ts b/src/core/api/defaults/action.ts index c86269b..607b584 100644 --- a/src/core/api/defaults/action.ts +++ b/src/core/api/defaults/action.ts @@ -1,14 +1,12 @@ /////////////////////////////////////// //DEFAULT ACTION MODULE /////////////////////////////////////// -import { ODValidId } from "../modules/base" -import { ODAction, ODActionManager } from "../modules/action" +import * as api from "@open-discord-bots/framework/api" import { ODWorkerManager_Default } from "./worker" import * as discord from "discord.js" import { ODRoleOption, ODTicketOption } from "../openticket/option" import { ODTicket, ODTicketClearFilter } from "../openticket/ticket" import { ODTranscriptCompiler, ODTranscriptCompilerCompileResult } from "../openticket/transcript" -import { ODMessageBuildSentResult } from "../modules/builder" import { ODRole, ODRoleUpdateMode, ODRoleUpdateResult } from "../openticket/role" import { ODPriorityLevel } from "../openticket/priority" @@ -26,7 +24,7 @@ export interface ODActionManagerIds_Default { "opendiscord:create-transcript":{ source:"slash"|"text"|"ticket-message"|"reopen-message"|"close-message"|"autoclose-message"|"autodelete"|"clear"|"other", params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket}, - result:{compiler:ODTranscriptCompiler, success:boolean, result:ODTranscriptCompilerCompileResult, errorReason:string|null, pendingMessage:ODMessageBuildSentResult|null, initData:object|null, participants:{user:discord.User,role:"creator"|"participant"|"admin"}[]}, + result:{compiler:ODTranscriptCompiler, success:boolean, result:ODTranscriptCompilerCompileResult, errorReason:string|null, pendingMessage:api.ODMessageBuildSentResult|null, initData:object|null, participants:{user:discord.User,role:"creator"|"participant"|"admin"}[]}, workers:"opendiscord:select-compiler"|"opendiscord:init-transcript"|"opendiscord:compile-transcript"|"opendiscord:ready-transcript"|"opendiscord:logs" }, "opendiscord:create-ticket":{ @@ -139,25 +137,25 @@ export interface ODActionManagerIds_Default { * * This default class is made for the global variable `opendiscord.actions`! */ -export class ODActionManager_Default extends ODActionManager { +export class ODActionManager_Default extends api.ODActionManager { get(id:ActionId): ODAction_Default - get(id:ODValidId): ODAction|null + get(id:api.ODValidId): api.ODAction|null - get(id:ODValidId): ODAction|null { + get(id:api.ODValidId): api.ODAction|null { return super.get(id) } remove(id:ActionId): ODAction_Default - remove(id:ODValidId): ODAction|null + remove(id:api.ODValidId): api.ODAction|null - remove(id:ODValidId): ODAction|null { + remove(id:api.ODValidId): api.ODAction|null { return super.remove(id) } exists(id:keyof ODActionManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -168,6 +166,6 @@ export class ODActionManager_Default extends ODActionManager { * * This default class is made for the default `ODAction`'s! */ -export class ODAction_Default extends ODAction { +export class ODAction_Default extends api.ODAction { declare workers: ODWorkerManager_Default } \ No newline at end of file diff --git a/src/core/api/defaults/base.ts b/src/core/api/defaults/base.ts index 2cfa279..cca2608 100644 --- a/src/core/api/defaults/base.ts +++ b/src/core/api/defaults/base.ts @@ -1,18 +1,18 @@ /////////////////////////////////////// //BASE MODULE /////////////////////////////////////// -import { ODVersion, ODVersionManager, ODValidId } from "../modules/base" +import * as api from "@open-discord-bots/framework/api" /**## ODVersionManagerIds_Default `interface` * This interface is a list of ids available in the `ODVersionManager` class. * It's used to generate typescript declarations for this class. */ export interface ODVersionManagerIds_Default { - "opendiscord:version":ODVersion, - "opendiscord:last-version":ODVersion, - "opendiscord:api":ODVersion, - "opendiscord:transcripts":ODVersion, - "opendiscord:livestatus":ODVersion + "opendiscord:version":api.ODVersion, + "opendiscord:last-version":api.ODVersion, + "opendiscord:api":api.ODVersion, + "opendiscord:transcripts":api.ODVersion, + "opendiscord:livestatus":api.ODVersion } /**## ODFlagManager_Default `default_class` @@ -21,25 +21,25 @@ export interface ODVersionManagerIds_Default { * * This default class is made for the global variable `opendiscord.flags`! */ -export class ODVersionManager_Default extends ODVersionManager { +export class ODVersionManager_Default extends api.ODVersionManager { get(id:VersionId): ODVersionManagerIds_Default[VersionId] - get(id:ODValidId): ODVersion|null + get(id:api.ODValidId): api.ODVersion|null - get(id:ODValidId): ODVersion|null { + get(id:api.ODValidId): api.ODVersion|null { return super.get(id) } remove(id:VersionId): ODVersionManagerIds_Default[VersionId] - remove(id:ODValidId): ODVersion|null + remove(id:api.ODValidId): api.ODVersion|null - remove(id:ODValidId): ODVersion|null { + remove(id:api.ODValidId): api.ODVersion|null { return super.remove(id) } exists(id:keyof ODVersionManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } \ No newline at end of file diff --git a/src/core/api/defaults/builder.ts b/src/core/api/defaults/builder.ts index 96c652b..edb0728 100644 --- a/src/core/api/defaults/builder.ts +++ b/src/core/api/defaults/builder.ts @@ -1,19 +1,16 @@ /////////////////////////////////////// //DEFAULT BUILDER MODULE /////////////////////////////////////// -import { ODValidButtonColor, ODValidId } from "../modules/base" -import { ODBuilderManager, ODButton, ODButtonInstance, ODButtonManager, ODDropdown, ODDropdownInstance, ODDropdownManager, ODEmbed, ODEmbedInstance, ODEmbedManager, ODFile, ODFileInstance, ODFileManager, ODMessage, ODMessageInstance, ODMessageManager, ODModal, ODModalInstance, ODModalManager } from "../modules/builder" +import * as api from "@open-discord-bots/framework/api" import { ODWorkerManager_Default } from "./worker" -import { ODTicket, ODTicketClearFilter } from "../openticket/ticket" -import { ODPermissionEmbedType } from "../defaults/permission" -import { ODTextCommandErrorInvalidOption, ODTextCommandErrorMissingOption, ODTextCommandErrorUnknownCommand } from "../modules/client" -import { ODPanel } from "../openticket/panel" -import { ODRoleOption, ODTicketOption, ODWebsiteOption } from "../openticket/option" -import { ODVerifyBar } from "../modules/verifybar" -import * as discord from "discord.js" +import { ODPermissionEmbedType } from "./permission" import { ODTranscriptCompiler, ODTranscriptCompilerCompileResult } from "../openticket/transcript" +import { ODRoleOption, ODTicketOption, ODWebsiteOption } from "../openticket/option" +import { ODTicket, ODTicketClearFilter } from "../openticket/ticket" import { ODRole, ODRoleUpdateResult } from "../openticket/role" import { ODPriorityLevel } from "../openticket/priority" +import { ODPanel } from "../openticket/panel" +import * as discord from "discord.js" /**## ODBuilderManager_Default `default_class` * This is a special class that adds type definitions & typescript to the ODBuilderManager class. @@ -21,7 +18,7 @@ import { ODPriorityLevel } from "../openticket/priority" * * This default class is made for the global variable `opendiscord.builders`! */ -export class ODBuilderManager_Default extends ODBuilderManager { +export class ODBuilderManager_Default extends api.ODBuilderManager { declare buttons: ODButtonManager_Default declare dropdowns: ODDropdownManager_Default declare files: ODFileManager_Default @@ -35,8 +32,8 @@ export class ODBuilderManager_Default extends ODBuilderManager { * It's used to generate typescript declarations for this class. */ export interface ODButtonManagerIds_Default { - "opendiscord:verifybar-success":{source:"verifybar"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:ODVerifyBar,customData?:string,customColor?:ODValidButtonColor,customLabel?:string,customEmoji?:string},workers:"opendiscord:verifybar-success"}, - "opendiscord:verifybar-failure":{source:"verifybar"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:ODVerifyBar,customData?:string,customColor?:ODValidButtonColor,customLabel?:string,customEmoji?:string},workers:"opendiscord:verifybar-failure"}, + "opendiscord:verifybar-success":{source:"verifybar"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar,customData?:string,customColor?:api.ODValidButtonColor,customLabel?:string,customEmoji?:string},workers:"opendiscord:verifybar-success"}, + "opendiscord:verifybar-failure":{source:"verifybar"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar,customData?:string,customColor?:api.ODValidButtonColor,customLabel?:string,customEmoji?:string},workers:"opendiscord:verifybar-failure"}, "opendiscord:error-ticket-deprecated-transcript":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{},workers:"opendiscord:error-ticket-deprecated-transcript"}, @@ -72,32 +69,32 @@ export interface ODButtonManagerIds_Default { * * This default class is made for the global variable `opendiscord.builders.buttons`! */ -export class ODButtonManager_Default extends ODButtonManager { +export class ODButtonManager_Default extends api.ODButtonManager { get(id:ButtonId): ODButton_Default - get(id:ODValidId): ODButton|null + get(id:api.ODValidId): api.ODButton|null - get(id:ODValidId): ODButton|null { + get(id:api.ODValidId): api.ODButton|null { return super.get(id) } remove(id:ButtonId): ODButton_Default - remove(id:ODValidId): ODButton|null + remove(id:api.ODValidId): api.ODButton|null - remove(id:ODValidId): ODButton|null { + remove(id:api.ODValidId): api.ODButton|null { return super.remove(id) } exists(id:keyof ODButtonManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } getSafe(id:ButtonId): ODButton_Default - getSafe(id:ODValidId): ODButton + getSafe(id:api.ODValidId): api.ODButton - getSafe(id:ODValidId): ODButton { + getSafe(id:api.ODValidId): api.ODButton { return super.getSafe(id) } } @@ -108,8 +105,8 @@ export class ODButtonManager_Default extends ODButtonManager { * * This default class is made for the default `ODButton`'s! */ -export class ODButton_Default extends ODButton { - declare workers: ODWorkerManager_Default +export class ODButton_Default extends api.ODButton { + declare workers: ODWorkerManager_Default } /**## ODDropdownManagerIds_Default `interface` @@ -126,32 +123,32 @@ export interface ODDropdownManagerIds_Default { * * This default class is made for the global variable `opendiscord.builders.dropdowns`! */ -export class ODDropdownManager_Default extends ODDropdownManager { +export class ODDropdownManager_Default extends api.ODDropdownManager { get(id:DropdownId): ODDropdown_Default - get(id:ODValidId): ODDropdown|null + get(id:api.ODValidId): api.ODDropdown|null - get(id:ODValidId): ODDropdown|null { + get(id:api.ODValidId): api.ODDropdown|null { return super.get(id) } remove(id:DropdownId): ODDropdown_Default - remove(id:ODValidId): ODDropdown|null + remove(id:api.ODValidId): api.ODDropdown|null - remove(id:ODValidId): ODDropdown|null { + remove(id:api.ODValidId): api.ODDropdown|null { return super.remove(id) } exists(id:keyof ODDropdownManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } getSafe(id:DropdownId): ODDropdown_Default - getSafe(id:ODValidId): ODDropdown + getSafe(id:api.ODValidId): api.ODDropdown - getSafe(id:ODValidId): ODDropdown { + getSafe(id:api.ODValidId): api.ODDropdown { return super.getSafe(id) } } @@ -162,8 +159,8 @@ export class ODDropdownManager_Default extends ODDropdownManager { * * This default class is made for the default `ODDropdown`'s! */ -export class ODDropdown_Default extends ODDropdown { - declare workers: ODWorkerManager_Default +export class ODDropdown_Default extends api.ODDropdown { + declare workers: ODWorkerManager_Default } /**## ODFileManagerIds_Default `interface` @@ -180,32 +177,32 @@ export interface ODFileManagerIds_Default { * * This default class is made for the global variable `opendiscord.builders.files`! */ -export class ODFileManager_Default extends ODFileManager { +export class ODFileManager_Default extends api.ODFileManager { get(id:FileId): ODFile_Default - get(id:ODValidId): ODFile|null + get(id:api.ODValidId): api.ODFile|null - get(id:ODValidId): ODFile|null { + get(id:api.ODValidId): api.ODFile|null { return super.get(id) } remove(id:FileId): ODFile_Default - remove(id:ODValidId): ODFile|null + remove(id:api.ODValidId): api.ODFile|null - remove(id:ODValidId): ODFile|null { + remove(id:api.ODValidId): api.ODFile|null { return super.remove(id) } exists(id:keyof ODFileManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } getSafe(id:FileId): ODFile_Default - getSafe(id:ODValidId): ODFile + getSafe(id:api.ODValidId): api.ODFile - getSafe(id:ODValidId): ODFile { + getSafe(id:api.ODValidId): api.ODFile { return super.getSafe(id) } } @@ -216,8 +213,8 @@ export class ODFileManager_Default extends ODFileManager { * * This default class is made for the default `ODFile`'s! */ -export class ODFile_Default extends ODFile { - declare workers: ODWorkerManager_Default +export class ODFile_Default extends api.ODFile { + declare workers: ODWorkerManager_Default } /**## ODEmbedManagerIds_Default `interface` @@ -226,9 +223,9 @@ export class ODFile_Default(id:EmbedId): ODEmbed_Default - get(id:ODValidId): ODEmbed|null + get(id:api.ODValidId): api.ODEmbed|null - get(id:ODValidId): ODEmbed|null { + get(id:api.ODValidId): api.ODEmbed|null { return super.get(id) } remove(id:EmbedId): ODEmbed_Default - remove(id:ODValidId): ODEmbed|null + remove(id:api.ODValidId): api.ODEmbed|null - remove(id:ODValidId): ODEmbed|null { + remove(id:api.ODValidId): api.ODEmbed|null { return super.remove(id) } exists(id:keyof ODEmbedManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } getSafe(id:EmbedId): ODEmbed_Default - getSafe(id:ODValidId): ODEmbed + getSafe(id:api.ODValidId): api.ODEmbed - getSafe(id:ODValidId): ODEmbed { + getSafe(id:api.ODValidId): api.ODEmbed { return super.getSafe(id) } } @@ -344,8 +341,8 @@ export class ODEmbedManager_Default extends ODEmbedManager { * * This default class is made for the default `ODEmbed`'s! */ -export class ODEmbed_Default extends ODEmbed { - declare workers: ODWorkerManager_Default +export class ODEmbed_Default extends api.ODEmbed { + declare workers: ODWorkerManager_Default } /**## ODMessageManagerIds_Default `interface` @@ -353,19 +350,19 @@ export class ODEmbed_Default},workers:"opendiscord:verifybar-ticket-message"}, - "opendiscord:verifybar-close-message":{source:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-close-message"}, - "opendiscord:verifybar-reopen-message":{source:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-reopen-message"}, - "opendiscord:verifybar-claim-message":{source:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-claim-message"}, - "opendiscord:verifybar-unclaim-message":{source:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-unclaim-message"}, - "opendiscord:verifybar-pin-message":{source:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-pin-message"}, - "opendiscord:verifybar-unpin-message":{source:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-unpin-message"} - "opendiscord:verifybar-autoclose-message":{source:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-autoclose-message"} + "opendiscord:verifybar-ticket-message":{source:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-ticket-message"}, + "opendiscord:verifybar-close-message":{source:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-close-message"}, + "opendiscord:verifybar-reopen-message":{source:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-reopen-message"}, + "opendiscord:verifybar-claim-message":{source:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-claim-message"}, + "opendiscord:verifybar-unclaim-message":{source:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-unclaim-message"}, + "opendiscord:verifybar-pin-message":{source:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-pin-message"}, + "opendiscord:verifybar-unpin-message":{source:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-unpin-message"} + "opendiscord:verifybar-autoclose-message":{source:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-autoclose-message"} "opendiscord:error":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,error:string,layout:"simple"|"advanced",customTitle?:string},workers:"opendiscord:error"}, - "opendiscord:error-option-missing":{source:"slash"|"text"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,error:ODTextCommandErrorMissingOption},workers:"opendiscord:error-option-missing"}, - "opendiscord:error-option-invalid":{source:"slash"|"text"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,error:ODTextCommandErrorInvalidOption},workers:"opendiscord:error-option-invalid"}, - "opendiscord:error-unknown-command":{source:"slash"|"text"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,error:ODTextCommandErrorUnknownCommand},workers:"opendiscord:error-unknown-command"}, + "opendiscord:error-option-missing":{source:"slash"|"text"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,error:api.ODTextCommandErrorMissingOption},workers:"opendiscord:error-option-missing"}, + "opendiscord:error-option-invalid":{source:"slash"|"text"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,error:api.ODTextCommandErrorInvalidOption},workers:"opendiscord:error-option-invalid"}, + "opendiscord:error-unknown-command":{source:"slash"|"text"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,error:api.ODTextCommandErrorUnknownCommand},workers:"opendiscord:error-unknown-command"}, "opendiscord:error-no-permissions":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,permissions:ODPermissionEmbedType[]},workers:"opendiscord:error-no-permissions"}, "opendiscord:error-no-permissions-cooldown":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,until?:Date},workers:"opendiscord:error-no-permissions-cooldown"}, "opendiscord:error-no-permissions-blacklisted":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User},workers:"opendiscord:error-no-permissions-blacklisted"}, @@ -447,32 +444,32 @@ export interface ODMessageManagerIds_Default { * * This default class is made for the global variable `opendiscord.builders.messages`! */ -export class ODMessageManager_Default extends ODMessageManager { +export class ODMessageManager_Default extends api.ODMessageManager { get(id:MessageId): ODMessage_Default - get(id:ODValidId): ODMessage|null + get(id:api.ODValidId): api.ODMessage|null - get(id:ODValidId): ODMessage|null { + get(id:api.ODValidId): api.ODMessage|null { return super.get(id) } remove(id:MessageId): ODMessage_Default - remove(id:ODValidId): ODMessage|null + remove(id:api.ODValidId): api.ODMessage|null - remove(id:ODValidId): ODMessage|null { + remove(id:api.ODValidId): api.ODMessage|null { return super.remove(id) } exists(id:keyof ODMessageManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } getSafe(id:MessageId): ODMessage_Default - getSafe(id:ODValidId): ODMessage + getSafe(id:api.ODValidId): api.ODMessage - getSafe(id:ODValidId): ODMessage { + getSafe(id:api.ODValidId): api.ODMessage { return super.getSafe(id) } } @@ -483,8 +480,8 @@ export class ODMessageManager_Default extends ODMessageManager { * * This default class is made for the default `ODMessage`'s! */ -export class ODMessage_Default extends ODMessage { - declare workers: ODWorkerManager_Default +export class ODMessage_Default extends api.ODMessage { + declare workers: ODWorkerManager_Default } /**## ODModalManagerIds_Default `interface` @@ -508,32 +505,32 @@ export interface ODModalManagerIds_Default { * * This default class is made for the global variable `opendiscord.builders.modals`! */ -export class ODModalManager_Default extends ODModalManager { +export class ODModalManager_Default extends api.ODModalManager { get(id:ModalId): ODModal_Default - get(id:ODValidId): ODModal|null + get(id:api.ODValidId): api.ODModal|null - get(id:ODValidId): ODModal|null { + get(id:api.ODValidId): api.ODModal|null { return super.get(id) } remove(id:ModalId): ODModal_Default - remove(id:ODValidId): ODModal|null + remove(id:api.ODValidId): api.ODModal|null - remove(id:ODValidId): ODModal|null { + remove(id:api.ODValidId): api.ODModal|null { return super.remove(id) } exists(id:keyof ODModalManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } getSafe(id:ModalId): ODModal_Default - getSafe(id:ODValidId): ODModal + getSafe(id:api.ODValidId): api.ODModal - getSafe(id:ODValidId): ODModal { + getSafe(id:api.ODValidId): api.ODModal { return super.getSafe(id) } } @@ -544,6 +541,6 @@ export class ODModalManager_Default extends ODModalManager { * * This default class is made for the default `ODModal`'s! */ -export class ODModal_Default extends ODModal { - declare workers: ODWorkerManager_Default +export class ODModal_Default extends api.ODModal { + declare workers: ODWorkerManager_Default } \ No newline at end of file diff --git a/src/core/api/defaults/checker.ts b/src/core/api/defaults/checker.ts index 9cc654c..1ca332b 100644 --- a/src/core/api/defaults/checker.ts +++ b/src/core/api/defaults/checker.ts @@ -1,9 +1,8 @@ /////////////////////////////////////// //DEFAULT CONFIG CHECKER MODULE /////////////////////////////////////// -import { ODLanguageManager_Default } from "../api" -import { ODValidId } from "../modules/base" -import { ODCheckerManager, ODChecker, ODCheckerTranslationRegister, ODCheckerRenderer, ODCheckerFunctionManager, ODCheckerResult, ODCheckerFunction } from "../modules/checker" +import * as api from "@open-discord-bots/framework/api" +import { ODLanguageManager_Default } from "./language" import ansis from "ansis" /**## ODCheckerManagerIds_Default `interface` @@ -11,11 +10,11 @@ import ansis from "ansis" * It's used to generate typescript declarations for this class. */ export interface ODCheckerManagerIds_Default { - "opendiscord:general":ODChecker, - "opendiscord:questions":ODChecker, - "opendiscord:options":ODChecker, - "opendiscord:panels":ODChecker, - "opendiscord:transcripts":ODChecker + "opendiscord:general":api.ODChecker, + "opendiscord:questions":api.ODChecker, + "opendiscord:options":api.ODChecker, + "opendiscord:panels":api.ODChecker, + "opendiscord:transcripts":api.ODChecker } /**## ODCheckerManager_Default `default_class` @@ -24,29 +23,29 @@ export interface ODCheckerManagerIds_Default { * * This default class is made for the global variable `opendiscord.checkers`! */ -export class ODCheckerManager_Default extends ODCheckerManager { +export class ODCheckerManager_Default extends api.ODCheckerManager { declare translation: ODCheckerTranslationRegister_Default declare renderer: ODCheckerRenderer_Default declare functions: ODCheckerFunctionManager_Default get(id:CheckerId): ODCheckerManagerIds_Default[CheckerId] - get(id:ODValidId): ODChecker|null + get(id:api.ODValidId): api.ODChecker|null - get(id:ODValidId): ODChecker|null { + get(id:api.ODValidId): api.ODChecker|null { return super.get(id) } remove(id:CheckerId): ODCheckerManagerIds_Default[CheckerId] - remove(id:ODValidId): ODChecker|null + remove(id:api.ODValidId): api.ODChecker|null - remove(id:ODValidId): ODChecker|null { + remove(id:api.ODValidId): api.ODChecker|null { return super.remove(id) } exists(id:keyof ODCheckerManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -57,7 +56,7 @@ export class ODCheckerManager_Default extends ODCheckerManager { * * This default class is made for the global variable `opendiscord.checkers.renderer`! */ -export class ODCheckerRenderer_Default extends ODCheckerRenderer { +export class ODCheckerRenderer_Default extends api.ODCheckerRenderer { extraHeaderText: string[] = [] extraFooterText: string[] = [] extraTopText: string[] = [] @@ -72,7 +71,7 @@ export class ODCheckerRenderer_Default extends ODCheckerRenderer { disableHeader: boolean = false disableFooter: boolean = false - getComponents(compact:boolean, renderEmpty:boolean, translation:ODCheckerTranslationRegister_Default, data:ODCheckerResult): string[] { + getComponents(compact:boolean, renderEmpty:boolean, translation:ODCheckerTranslationRegister_Default, data:api.ODCheckerResult): string[] { const tm = translation const t = { headerOpenticket:tm.get("other","opendiscord:header-openticket") ?? "OPEN TICKET", @@ -312,7 +311,7 @@ export type ODCheckerTranslationRegisterMessageIds_Default = ( * * This default class is made for the global variable `opendiscord.checkers.translation`! */ -export class ODCheckerTranslationRegister_Default extends ODCheckerTranslationRegister { +export class ODCheckerTranslationRegister_Default extends api.ODCheckerTranslationRegister { get(type:"other", id:ODCheckerTranslationRegisterOtherIds_Default): string get(type:"message", id:ODCheckerTranslationRegisterMessageIds_Default): string get(type:"message"|"other", id:string): string|null @@ -350,9 +349,9 @@ export class ODCheckerTranslationRegister_Default extends ODCheckerTranslationRe * It's used to generate typescript declarations for this class. */ export interface ODCheckerFunctionManagerIds_Default { - "opendiscord:unused-options":ODCheckerFunction, - "opendiscord:unused-questions":ODCheckerFunction, - "opendiscord:dropdown-options":ODCheckerFunction + "opendiscord:unused-options":api.ODCheckerFunction, + "opendiscord:unused-questions":api.ODCheckerFunction, + "opendiscord:dropdown-options":api.ODCheckerFunction } /**## ODCheckerFunctionManager_Default `default_class` @@ -361,25 +360,25 @@ export interface ODCheckerFunctionManagerIds_Default { * * This default class is made for the global variable `opendiscord.checkers.functions`! */ -export class ODCheckerFunctionManager_Default extends ODCheckerFunctionManager { +export class ODCheckerFunctionManager_Default extends api.ODCheckerFunctionManager { get(id:CheckerFunctionId): ODCheckerFunctionManagerIds_Default[CheckerFunctionId] - get(id:ODValidId): ODCheckerFunction|null + get(id:api.ODValidId): api.ODCheckerFunction|null - get(id:ODValidId): ODCheckerFunction|null { + get(id:api.ODValidId): api.ODCheckerFunction|null { return super.get(id) } remove(id:CheckerFunctionId): ODCheckerFunctionManagerIds_Default[CheckerFunctionId] - remove(id:ODValidId): ODCheckerFunction|null + remove(id:api.ODValidId): api.ODCheckerFunction|null - remove(id:ODValidId): ODCheckerFunction|null { + remove(id:api.ODValidId): api.ODCheckerFunction|null { return super.remove(id) } exists(id:keyof ODCheckerFunctionManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } \ No newline at end of file diff --git a/src/core/api/defaults/client.ts b/src/core/api/defaults/client.ts index 7b5a540..8cfcaab 100644 --- a/src/core/api/defaults/client.ts +++ b/src/core/api/defaults/client.ts @@ -1,8 +1,7 @@ /////////////////////////////////////// //DEFAULT CLIENT MODULE /////////////////////////////////////// -import { ODValidId } from "../modules/base" -import { ODClientManager, ODSlashCommand, ODTextCommand, ODSlashCommandManager, ODTextCommandManager, ODSlashCommandInteractionCallback, ODTextCommandInteractionCallback, ODContextMenu, ODContextMenuManager, ODContextMenuInteractionCallback } from "../modules/client" +import * as api from "@open-discord-bots/framework/api" /** (CONTRIBUTOR GUIDE) HOW TO ADD NEW COMMANDS? * - Register the command in loadAllSlashCommands() & loadAllTextCommands() in (./src/data/framework/commandLoader.ts) @@ -20,7 +19,7 @@ import { ODClientManager, ODSlashCommand, ODTextCommand, ODSlashCommandManager, * * This default class is made for the global variable `opendiscord.client`! */ -export class ODClientManager_Default extends ODClientManager { +export class ODClientManager_Default extends api.ODClientManager { declare slashCommands: ODSlashCommandManager_Default declare textCommands: ODTextCommandManager_Default declare contextMenus: ODContextMenuManager_Default @@ -31,28 +30,28 @@ export class ODClientManager_Default extends ODClientManager { * It's used to generate typescript declarations for this class. */ export interface ODSlashCommandManagerIds_Default { - "opendiscord:help":ODSlashCommand, - "opendiscord:panel":ODSlashCommand, - "opendiscord:ticket":ODSlashCommand, - "opendiscord:close":ODSlashCommand, - "opendiscord:delete":ODSlashCommand, - "opendiscord:reopen":ODSlashCommand, - "opendiscord:claim":ODSlashCommand, - "opendiscord:unclaim":ODSlashCommand, - "opendiscord:pin":ODSlashCommand, - "opendiscord:unpin":ODSlashCommand, - "opendiscord:move":ODSlashCommand, - "opendiscord:rename":ODSlashCommand, - "opendiscord:add":ODSlashCommand, - "opendiscord:remove":ODSlashCommand, - "opendiscord:blacklist":ODSlashCommand, - "opendiscord:stats":ODSlashCommand, - "opendiscord:clear":ODSlashCommand, - "opendiscord:autoclose":ODSlashCommand, - "opendiscord:autodelete":ODSlashCommand, - "opendiscord:topic":ODSlashCommand, - "opendiscord:priority":ODSlashCommand, - "opendiscord:transfer":ODSlashCommand, + "opendiscord:help":api.ODSlashCommand, + "opendiscord:panel":api.ODSlashCommand, + "opendiscord:ticket":api.ODSlashCommand, + "opendiscord:close":api.ODSlashCommand, + "opendiscord:delete":api.ODSlashCommand, + "opendiscord:reopen":api.ODSlashCommand, + "opendiscord:claim":api.ODSlashCommand, + "opendiscord:unclaim":api.ODSlashCommand, + "opendiscord:pin":api.ODSlashCommand, + "opendiscord:unpin":api.ODSlashCommand, + "opendiscord:move":api.ODSlashCommand, + "opendiscord:rename":api.ODSlashCommand, + "opendiscord:add":api.ODSlashCommand, + "opendiscord:remove":api.ODSlashCommand, + "opendiscord:blacklist":api.ODSlashCommand, + "opendiscord:stats":api.ODSlashCommand, + "opendiscord:clear":api.ODSlashCommand, + "opendiscord:autoclose":api.ODSlashCommand, + "opendiscord:autodelete":api.ODSlashCommand, + "opendiscord:topic":api.ODSlashCommand, + "opendiscord:priority":api.ODSlashCommand, + "opendiscord:transfer":api.ODSlashCommand, } /**## ODSlashCommandManager_Default `default_class` @@ -61,32 +60,32 @@ export interface ODSlashCommandManagerIds_Default { * * This default class is made for the global variable `opendiscord.client.slashCommands`! */ -export class ODSlashCommandManager_Default extends ODSlashCommandManager { +export class ODSlashCommandManager_Default extends api.ODSlashCommandManager { get(id:SlashCommandId): ODSlashCommandManagerIds_Default[SlashCommandId] - get(id:ODValidId): ODSlashCommand|null + get(id:api.ODValidId): api.ODSlashCommand|null - get(id:ODValidId): ODSlashCommand|null { + get(id:api.ODValidId): api.ODSlashCommand|null { return super.get(id) } remove(id:SlashCommandId): ODSlashCommandManagerIds_Default[SlashCommandId] - remove(id:ODValidId): ODSlashCommand|null + remove(id:api.ODValidId): api.ODSlashCommand|null - remove(id:ODValidId): ODSlashCommand|null { + remove(id:api.ODValidId): api.ODSlashCommand|null { return super.remove(id) } exists(id:keyof ODSlashCommandManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } - onInteraction(commandName:keyof ODSlashCommandManagerIds_Default, callback:ODSlashCommandInteractionCallback): void - onInteraction(commandName:string|RegExp, callback:ODSlashCommandInteractionCallback): void + onInteraction(commandName:keyof ODSlashCommandManagerIds_Default, callback:api.ODSlashCommandInteractionCallback): void + onInteraction(commandName:string|RegExp, callback:api.ODSlashCommandInteractionCallback): void - onInteraction(commandName:string|RegExp, callback:ODSlashCommandInteractionCallback): void { + onInteraction(commandName:string|RegExp, callback:api.ODSlashCommandInteractionCallback): void { return super.onInteraction(commandName,callback) } } @@ -96,37 +95,37 @@ export class ODSlashCommandManager_Default extends ODSlashCommandManager { * It's used to generate typescript declarations for this class. */ export interface ODTextCommandManagerIds_Default { - "opendiscord:dump":ODTextCommand, - "opendiscord:help":ODTextCommand, - "opendiscord:panel":ODTextCommand, - "opendiscord:close":ODTextCommand, - "opendiscord:delete":ODTextCommand, - "opendiscord:reopen":ODTextCommand, - "opendiscord:claim":ODTextCommand, - "opendiscord:unclaim":ODTextCommand, - "opendiscord:pin":ODTextCommand, - "opendiscord:unpin":ODTextCommand, - "opendiscord:move":ODTextCommand, - "opendiscord:rename":ODTextCommand, - "opendiscord:add":ODTextCommand, - "opendiscord:remove":ODTextCommand, - "opendiscord:blacklist-view":ODTextCommand, - "opendiscord:blacklist-add":ODTextCommand, - "opendiscord:blacklist-remove":ODTextCommand, - "opendiscord:blacklist-get":ODTextCommand, - "opendiscord:stats-global":ODTextCommand, - "opendiscord:stats-reset":ODTextCommand, - "opendiscord:stats-ticket":ODTextCommand, - "opendiscord:stats-user":ODTextCommand, - "opendiscord:clear":ODTextCommand, - "opendiscord:autoclose-disable":ODTextCommand, - "opendiscord:autoclose-enable":ODTextCommand, - "opendiscord:autodelete-disable":ODTextCommand, - "opendiscord:autodelete-enable":ODTextCommand, - "opendiscord:topic-set":ODTextCommand, - "opendiscord:priority-set":ODTextCommand, - "opendiscord:priority-get":ODTextCommand, - "opendiscord:transfer":ODTextCommand, + "opendiscord:dump":api.ODTextCommand, + "opendiscord:help":api.ODTextCommand, + "opendiscord:panel":api.ODTextCommand, + "opendiscord:close":api.ODTextCommand, + "opendiscord:delete":api.ODTextCommand, + "opendiscord:reopen":api.ODTextCommand, + "opendiscord:claim":api.ODTextCommand, + "opendiscord:unclaim":api.ODTextCommand, + "opendiscord:pin":api.ODTextCommand, + "opendiscord:unpin":api.ODTextCommand, + "opendiscord:move":api.ODTextCommand, + "opendiscord:rename":api.ODTextCommand, + "opendiscord:add":api.ODTextCommand, + "opendiscord:remove":api.ODTextCommand, + "opendiscord:blacklist-view":api.ODTextCommand, + "opendiscord:blacklist-add":api.ODTextCommand, + "opendiscord:blacklist-remove":api.ODTextCommand, + "opendiscord:blacklist-get":api.ODTextCommand, + "opendiscord:stats-global":api.ODTextCommand, + "opendiscord:stats-reset":api.ODTextCommand, + "opendiscord:stats-ticket":api.ODTextCommand, + "opendiscord:stats-user":api.ODTextCommand, + "opendiscord:clear":api.ODTextCommand, + "opendiscord:autoclose-disable":api.ODTextCommand, + "opendiscord:autoclose-enable":api.ODTextCommand, + "opendiscord:autodelete-disable":api.ODTextCommand, + "opendiscord:autodelete-enable":api.ODTextCommand, + "opendiscord:topic-set":api.ODTextCommand, + "opendiscord:priority-set":api.ODTextCommand, + "opendiscord:priority-get":api.ODTextCommand, + "opendiscord:transfer":api.ODTextCommand, } /**## ODTextCommandManager_Default `default_class` @@ -135,29 +134,29 @@ export interface ODTextCommandManagerIds_Default { * * This default class is made for the global variable `opendiscord.client.textCommands`! */ -export class ODTextCommandManager_Default extends ODTextCommandManager { +export class ODTextCommandManager_Default extends api.ODTextCommandManager { get(id:TextCommandId): ODTextCommandManagerIds_Default[TextCommandId] - get(id:ODValidId): ODTextCommand|null + get(id:api.ODValidId): api.ODTextCommand|null - get(id:ODValidId): ODTextCommand|null { + get(id:api.ODValidId): api.ODTextCommand|null { return super.get(id) } remove(id:TextCommandId): ODTextCommandManagerIds_Default[TextCommandId] - remove(id:ODValidId): ODTextCommand|null + remove(id:api.ODValidId): api.ODTextCommand|null - remove(id:ODValidId): ODTextCommand|null { + remove(id:api.ODValidId): api.ODTextCommand|null { return super.remove(id) } exists(id:keyof ODTextCommandManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } - onInteraction(commandPrefix:string, commandName:string|RegExp, callback:ODTextCommandInteractionCallback): void { + onInteraction(commandPrefix:string, commandName:string|RegExp, callback:api.ODTextCommandInteractionCallback): void { return super.onInteraction(commandPrefix,commandName,callback) } } @@ -176,32 +175,32 @@ export interface ODContextMenuManagerIds_Default { * * This default class is made for the global variable `opendiscord.client.contextMenus`! */ -export class ODContextMenuManager_Default extends ODContextMenuManager { +export class ODContextMenuManager_Default extends api.ODContextMenuManager { get(id:ContextMenuId): ODContextMenuManagerIds_Default[ContextMenuId] - get(id:ODValidId): ODContextMenu|null + get(id:api.ODValidId): api.ODContextMenu|null - get(id:ODValidId): ODContextMenu|null { + get(id:api.ODValidId): api.ODContextMenu|null { return super.get(id) } remove(id:ContextMenuId): ODContextMenuManagerIds_Default[ContextMenuId] - remove(id:ODValidId): ODContextMenu|null + remove(id:api.ODValidId): api.ODContextMenu|null - remove(id:ODValidId): ODContextMenu|null { + remove(id:api.ODValidId): api.ODContextMenu|null { return super.remove(id) } exists(id:keyof ODContextMenuManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } - onInteraction(menuName:keyof ODContextMenuManagerIds_Default, callback:ODContextMenuInteractionCallback): void - onInteraction(menuName:string|RegExp, callback:ODContextMenuInteractionCallback): void + onInteraction(menuName:keyof ODContextMenuManagerIds_Default, callback:api.ODContextMenuInteractionCallback): void + onInteraction(menuName:string|RegExp, callback:api.ODContextMenuInteractionCallback): void - onInteraction(menuName:string|RegExp, callback:ODContextMenuInteractionCallback): void { + onInteraction(menuName:string|RegExp, callback:api.ODContextMenuInteractionCallback): void { return super.onInteraction(menuName,callback) } } \ No newline at end of file diff --git a/src/core/api/defaults/code.ts b/src/core/api/defaults/code.ts index 7ef19a8..edb0db9 100644 --- a/src/core/api/defaults/code.ts +++ b/src/core/api/defaults/code.ts @@ -1,30 +1,29 @@ /////////////////////////////////////// //DEFAULT CODE MODULE /////////////////////////////////////// -import { ODValidId } from "../modules/base" -import { ODCode, ODCodeManager } from "../modules/code" +import * as api from "@open-discord-bots/framework/api" /**## ODCodeManagerIds_Default `interface` * This interface is a list of ids available in the `ODCodeManager_Default` class. * It's used to generate typescript declarations for this class. */ export interface ODCodeManagerIds_Default { - "opendiscord:command-error-handling":ODCode, - "opendiscord:start-listening-interactions":ODCode, - "opendiscord:panel-database-cleaner":ODCode, - "opendiscord:suffix-database-cleaner":ODCode, - "opendiscord:option-database-cleaner":ODCode, - "opendiscord:user-database-cleaner":ODCode, - "opendiscord:ticket-database-cleaner":ODCode, - "opendiscord:panel-auto-update":ODCode, - "opendiscord:ticket-saver":ODCode, - "opendiscord:blacklist-saver":ODCode, - "opendiscord:auto-role-on-join":ODCode, - "opendiscord:autoclose-timeout":ODCode, - "opendiscord:autoclose-leave":ODCode, - "opendiscord:autodelete-timeout":ODCode, - "opendiscord:autodelete-leave":ODCode, - "opendiscord:ticket-anti-busy":ODCode, + "opendiscord:command-error-handling":api.ODCode, + "opendiscord:start-listening-interactions":api.ODCode, + "opendiscord:panel-database-cleaner":api.ODCode, + "opendiscord:suffix-database-cleaner":api.ODCode, + "opendiscord:option-database-cleaner":api.ODCode, + "opendiscord:user-database-cleaner":api.ODCode, + "opendiscord:ticket-database-cleaner":api.ODCode, + "opendiscord:panel-auto-update":api.ODCode, + "opendiscord:ticket-saver":api.ODCode, + "opendiscord:blacklist-saver":api.ODCode, + "opendiscord:auto-role-on-join":api.ODCode, + "opendiscord:autoclose-timeout":api.ODCode, + "opendiscord:autoclose-leave":api.ODCode, + "opendiscord:autodelete-timeout":api.ODCode, + "opendiscord:autodelete-leave":api.ODCode, + "opendiscord:ticket-anti-busy":api.ODCode, } /**## ODCodeManager_Default `default_class` @@ -33,25 +32,25 @@ export interface ODCodeManagerIds_Default { * * This default class is made for the global variable `opendiscord.code`! */ -export class ODCodeManager_Default extends ODCodeManager { +export class ODCodeManager_Default extends api.ODCodeManager { get(id:CodeId): ODCodeManagerIds_Default[CodeId] - get(id:ODValidId): ODCode|null + get(id:api.ODValidId): api.ODCode|null - get(id:ODValidId): ODCode|null { + get(id:api.ODValidId): api.ODCode|null { return super.get(id) } remove(id:CodeId): ODCodeManagerIds_Default[CodeId] - remove(id:ODValidId): ODCode|null + remove(id:api.ODValidId): api.ODCode|null - remove(id:ODValidId): ODCode|null { + remove(id:api.ODValidId): api.ODCode|null { return super.remove(id) } exists(id:keyof ODCodeManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } \ No newline at end of file diff --git a/src/core/api/defaults/config.ts b/src/core/api/defaults/config.ts index 69a1850..ad85394 100644 --- a/src/core/api/defaults/config.ts +++ b/src/core/api/defaults/config.ts @@ -1,10 +1,8 @@ /////////////////////////////////////// //DEFAULT CONFIG MODULE /////////////////////////////////////// -import { ODValidButtonColor, ODValidId } from "../modules/base" +import * as api from "@open-discord-bots/framework/api" import * as discord from "discord.js" -import { ODConfigManager, ODConfig, ODJsonConfig } from "../modules/config" -import { ODClientActivityMode, ODClientActivityType } from "../modules/client" import { ODRoleUpdateMode } from "../openticket/role" /** (CONTRIBUTOR GUIDE) HOW TO ADD NEW CONFIG VARIABLES? @@ -45,25 +43,25 @@ export interface ODConfigManagerIds_Default { * * This default class is made for the global variable `opendiscord.configs`! */ -export class ODConfigManager_Default extends ODConfigManager { +export class ODConfigManager_Default extends api.ODConfigManager { get(id:ConfigId): ODConfigManagerIds_Default[ConfigId] - get(id:ODValidId): ODConfig|null + get(id:api.ODValidId): api.ODConfig|null - get(id:ODValidId): ODConfig|null { + get(id:api.ODValidId): api.ODConfig|null { return super.get(id) } remove(id:ConfigId): ODConfigManagerIds_Default[ConfigId] - remove(id:ODValidId): ODConfig|null + remove(id:api.ODValidId): api.ODConfig|null - remove(id:ODValidId): ODConfig|null { + remove(id:api.ODValidId): api.ODConfig|null { return super.remove(id) } exists(id:keyof ODConfigManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -75,9 +73,9 @@ export interface ODJsonConfig_DefaultStatusType { /**Is the status enabled? */ enabled:boolean, /**The type of status (e.g. playing, listening, custom, ...) */ - type:Exclude, + type:Exclude, /**The mode/status of the bot (e.g. online, invisible, idle, do not disturb) */ - mode:ODClientActivityMode + mode:api.ODClientActivityMode /**The text for the status. */ text:string, /**Additional text for the status. (visible below 'text') */ @@ -324,7 +322,7 @@ export interface ODJsonConfig_DefaultGeneralData { * * This default class is made for the `general.json` config! */ -export class ODJsonConfig_DefaultGeneral extends ODJsonConfig { +export class ODJsonConfig_DefaultGeneral extends api.ODJsonConfig { declare data: ODJsonConfig_DefaultGeneralData } @@ -358,7 +356,7 @@ export interface ODJsonConfig_DefaultOptionButtonSettingsType { /**The label of the button (can also be empty) */ label:string, /**The color of the button (not available in options with the 'website' type!) */ - color:ODValidButtonColor + color:api.ODValidButtonColor } /**## ODJsonConfig_DefaultOptionEmbedSettingsType `interface` @@ -546,7 +544,7 @@ export type ODJsonConfig_DefaultOptionsData = (ODJsonConfig_DefaultOptionTicketT * * This default class is made for the `options.json` config! */ -export class ODJsonConfig_DefaultOptions extends ODJsonConfig { +export class ODJsonConfig_DefaultOptions extends api.ODJsonConfig { declare data: ODJsonConfig_DefaultOptionsData } @@ -641,7 +639,7 @@ export type ODJsonConfig_DefaultPanelsData = ODJsonConfig_DefaultPanelType[] * * This default class is made for the `panels.json` config! */ -export class ODJsonConfig_DefaultPanels extends ODJsonConfig { +export class ODJsonConfig_DefaultPanels extends api.ODJsonConfig { declare data: ODJsonConfig_DefaultPanelsData } @@ -706,7 +704,7 @@ export type ODJsonConfig_DefaultQuestionsData = (ODJsonConfig_DefaultShortQuesti * * This default class is made for the `questions.json` config! */ -export class ODJsonConfig_DefaultQuestions extends ODJsonConfig { +export class ODJsonConfig_DefaultQuestions extends api.ODJsonConfig { declare data: ODJsonConfig_DefaultQuestionsData } @@ -828,6 +826,6 @@ export interface ODJsonConfig_DefaultTranscriptsData { * * This default class is made for the `transcripts.json` config! */ -export class ODJsonConfig_DefaultTranscripts extends ODJsonConfig { +export class ODJsonConfig_DefaultTranscripts extends api.ODJsonConfig { declare data: ODJsonConfig_DefaultTranscriptsData } \ No newline at end of file diff --git a/src/core/api/defaults/console.ts b/src/core/api/defaults/console.ts index 6b4d0da..22e7089 100644 --- a/src/core/api/defaults/console.ts +++ b/src/core/api/defaults/console.ts @@ -1,15 +1,14 @@ /////////////////////////////////////// //DEFAULT CONSOLE MODULE /////////////////////////////////////// -import { ODValidId } from "../modules/base" -import { ODLiveStatusUrlSource, ODLiveStatusManager, ODLiveStatusSource } from "../modules/console" +import * as api from "@open-discord-bots/framework/api" /**## ODLiveStatusManagerIds_Default `interface` * This interface is a list of ids available in the `ODLiveStatusManager_Default` class. * It's used to generate typescript declarations for this class. */ export interface ODLiveStatusManagerIds_Default { - "opendiscord:default-djdj-dev":ODLiveStatusUrlSource + "opendiscord:default-djdj-dev":api.ODLiveStatusUrlSource } /**## ODLiveStatusManager_Default `default_class` @@ -18,25 +17,25 @@ export interface ODLiveStatusManagerIds_Default { * * This default class is made for the global variable `opendiscord.livestatus`! */ -export class ODLiveStatusManager_Default extends ODLiveStatusManager { +export class ODLiveStatusManager_Default extends api.ODLiveStatusManager { get(id:LiveStatusId): ODLiveStatusManagerIds_Default[LiveStatusId] - get(id:ODValidId): ODLiveStatusSource|null + get(id:api.ODValidId): api.ODLiveStatusSource|null - get(id:ODValidId): ODLiveStatusSource|null { + get(id:api.ODValidId): api.ODLiveStatusSource|null { return super.get(id) } remove(id:LiveStatusId): ODLiveStatusManagerIds_Default[LiveStatusId] - remove(id:ODValidId): ODLiveStatusSource|null + remove(id:api.ODValidId): api.ODLiveStatusSource|null - remove(id:ODValidId): ODLiveStatusSource|null { + remove(id:api.ODValidId): api.ODLiveStatusSource|null { return super.remove(id) } exists(id:keyof ODLiveStatusManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } \ No newline at end of file diff --git a/src/core/api/defaults/cooldown.ts b/src/core/api/defaults/cooldown.ts index 75a53e7..29a4ab9 100644 --- a/src/core/api/defaults/cooldown.ts +++ b/src/core/api/defaults/cooldown.ts @@ -1,8 +1,7 @@ /////////////////////////////////////// //DEFAULT COOLDOWN MODULE /////////////////////////////////////// -import { ODValidId } from "../modules/base" -import { ODCooldown, ODCooldownManager } from "../modules/cooldown" +import * as api from "@open-discord-bots/framework/api" /**## ODCooldownManagerIds_Default `interface` * This interface is a list of ids available in the `ODCooldownManager_Default` class. @@ -18,25 +17,25 @@ export interface ODCooldownManagerIds_Default { * * This default class is made for the global variable `opendiscord.cooldowns`! */ -export class ODCooldownManager_Default extends ODCooldownManager { +export class ODCooldownManager_Default extends api.ODCooldownManager { get(id:CooldownId): ODCooldownManagerIds_Default[CooldownId] - get(id:ODValidId): ODCooldown|null + get(id:api.ODValidId): api.ODCooldown|null - get(id:ODValidId): ODCooldown|null { + get(id:api.ODValidId): api.ODCooldown|null { return super.get(id) } remove(id:CooldownId): ODCooldownManagerIds_Default[CooldownId] - remove(id:ODValidId): ODCooldown|null + remove(id:api.ODValidId): api.ODCooldown|null - remove(id:ODValidId): ODCooldown|null { + remove(id:api.ODValidId): api.ODCooldown|null { return super.remove(id) } exists(id:keyof ODCooldownManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } \ No newline at end of file diff --git a/src/core/api/defaults/database.ts b/src/core/api/defaults/database.ts index 8e73a10..a4183c4 100644 --- a/src/core/api/defaults/database.ts +++ b/src/core/api/defaults/database.ts @@ -1,8 +1,7 @@ /////////////////////////////////////// //DEFAULT DATABASE MODULE /////////////////////////////////////// -import { ODOptionalPromise, ODValidId, ODValidJsonType } from "../modules/base" -import { ODDatabaseManager, ODDatabase, ODFormattedJsonDatabase } from "../modules/database" +import * as api from "@open-discord-bots/framework/api" import { ODTicketJson } from "../openticket/ticket" import { ODOptionJson } from "../openticket/option" @@ -12,7 +11,7 @@ import { ODOptionJson } from "../openticket/option" */ export interface ODDatabaseManagerIds_Default { "opendiscord:global":ODFormattedJsonDatabase_DefaultGlobal, - "opendiscord:stats":ODFormattedJsonDatabase, + "opendiscord:stats":api.ODFormattedJsonDatabase, "opendiscord:tickets":ODFormattedJsonDatabase_DefaultTickets, "opendiscord:users":ODFormattedJsonDatabase_DefaultUsers, "opendiscord:options":ODFormattedJsonDatabase_DefaultOptions, @@ -24,25 +23,25 @@ export interface ODDatabaseManagerIds_Default { * * This default class is made for the global variable `opendiscord.databases`! */ -export class ODDatabaseManager_Default extends ODDatabaseManager { +export class ODDatabaseManager_Default extends api.ODDatabaseManager { get(id:DatabaseId): ODDatabaseManagerIds_Default[DatabaseId] - get(id:ODValidId): ODDatabase|null + get(id:api.ODValidId): api.ODDatabase|null - get(id:ODValidId): ODDatabase|null { + get(id:api.ODValidId): api.ODDatabase|null { return super.get(id) } remove(id:DatabaseId): ODDatabaseManagerIds_Default[DatabaseId] - remove(id:ODValidId): ODDatabase|null + remove(id:api.ODValidId): api.ODDatabase|null - remove(id:ODValidId): ODDatabase|null { + remove(id:api.ODValidId): api.ODDatabase|null { return super.remove(id) } exists(id:keyof ODDatabaseManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -65,39 +64,39 @@ export interface ODFormattedJsonDatabaseIds_DefaultGlobal { * * This default class is made for the `global.json` database! */ -export class ODFormattedJsonDatabase_DefaultGlobal extends ODFormattedJsonDatabase { - set(category:CategoryId, key:string, value:ODFormattedJsonDatabaseIds_DefaultGlobal[CategoryId]): ODOptionalPromise - set(category:string, key:string, value:ODValidJsonType): ODOptionalPromise +export class ODFormattedJsonDatabase_DefaultGlobal extends api.ODFormattedJsonDatabase { + set(category:CategoryId, key:string, value:ODFormattedJsonDatabaseIds_DefaultGlobal[CategoryId]): api.ODOptionalPromise + set(category:string, key:string, value:api.ODValidJsonType): api.ODOptionalPromise - set(category:string, key:string, value:ODValidJsonType): ODOptionalPromise { + set(category:string, key:string, value:api.ODValidJsonType): api.ODOptionalPromise { return super.set(category,key,value) } - get(category:CategoryId, key:string): ODOptionalPromise - get(category:string, key:string): ODOptionalPromise + get(category:CategoryId, key:string): api.ODOptionalPromise + get(category:string, key:string): api.ODOptionalPromise - get(category:string, key:string): ODOptionalPromise { + get(category:string, key:string): api.ODOptionalPromise { return super.get(category,key) } - delete(category:CategoryId, key:string): ODOptionalPromise - delete(category:string, key:string): ODOptionalPromise + delete(category:CategoryId, key:string): api.ODOptionalPromise + delete(category:string, key:string): api.ODOptionalPromise - delete(category:string, key:string): ODOptionalPromise { + delete(category:string, key:string): api.ODOptionalPromise { return super.delete(category,key) } - exists(category:keyof ODFormattedJsonDatabaseIds_DefaultGlobal, key:string): ODOptionalPromise - exists(category:string, key:string): ODOptionalPromise + exists(category:keyof ODFormattedJsonDatabaseIds_DefaultGlobal, key:string): api.ODOptionalPromise + exists(category:string, key:string): api.ODOptionalPromise - exists(category:string, key:string): ODOptionalPromise { + exists(category:string, key:string): api.ODOptionalPromise { return super.exists(category,key) } - getCategory(category:CategoryId): ODOptionalPromise<{key:string, value:ODFormattedJsonDatabaseIds_DefaultGlobal[CategoryId]}[]|undefined> - getCategory(category:string): ODOptionalPromise<{key:string, value:ODValidJsonType}[]|undefined> + getCategory(category:CategoryId): api.ODOptionalPromise<{key:string, value:ODFormattedJsonDatabaseIds_DefaultGlobal[CategoryId]}[]|undefined> + getCategory(category:string): api.ODOptionalPromise<{key:string, value:api.ODValidJsonType}[]|undefined> - getCategory(category:string): ODOptionalPromise<{key:string, value:ODValidJsonType}[]|undefined> { + getCategory(category:string): api.ODOptionalPromise<{key:string, value:api.ODValidJsonType}[]|undefined> { return super.getCategory(category) } } @@ -116,39 +115,39 @@ export interface ODFormattedJsonDatabaseIds_DefaultTickets { * * This default class is made for the `tickets.json` database! */ -export class ODFormattedJsonDatabase_DefaultTickets extends ODFormattedJsonDatabase { - set(category:CategoryId, key:string, value:ODFormattedJsonDatabaseIds_DefaultTickets[CategoryId]): ODOptionalPromise - set(category:string, key:string, value:ODValidJsonType): ODOptionalPromise +export class ODFormattedJsonDatabase_DefaultTickets extends api.ODFormattedJsonDatabase { + set(category:CategoryId, key:string, value:ODFormattedJsonDatabaseIds_DefaultTickets[CategoryId]): api.ODOptionalPromise + set(category:string, key:string, value:api.ODValidJsonType): api.ODOptionalPromise - set(category:string, key:string, value:ODValidJsonType): ODOptionalPromise { + set(category:string, key:string, value:api.ODValidJsonType): api.ODOptionalPromise { return super.set(category,key,value) } - get(category:CategoryId, key:string): ODOptionalPromise - get(category:string, key:string): ODOptionalPromise + get(category:CategoryId, key:string): api.ODOptionalPromise + get(category:string, key:string): api.ODOptionalPromise - get(category:string, key:string): ODOptionalPromise { + get(category:string, key:string): api.ODOptionalPromise { return super.get(category,key) } - delete(category:CategoryId, key:string): ODOptionalPromise - delete(category:string, key:string): ODOptionalPromise + delete(category:CategoryId, key:string): api.ODOptionalPromise + delete(category:string, key:string): api.ODOptionalPromise - delete(category:string, key:string): ODOptionalPromise { + delete(category:string, key:string): api.ODOptionalPromise { return super.delete(category,key) } - exists(category:keyof ODFormattedJsonDatabaseIds_DefaultTickets, key:string): ODOptionalPromise - exists(category:string, key:string): ODOptionalPromise + exists(category:keyof ODFormattedJsonDatabaseIds_DefaultTickets, key:string): api.ODOptionalPromise + exists(category:string, key:string): api.ODOptionalPromise - exists(category:string, key:string): ODOptionalPromise { + exists(category:string, key:string): api.ODOptionalPromise { return super.exists(category,key) } - getCategory(category:CategoryId): ODOptionalPromise<{key:string, value:ODFormattedJsonDatabaseIds_DefaultTickets[CategoryId]}[]|undefined> - getCategory(category:string): ODOptionalPromise<{key:string, value:ODValidJsonType}[]|undefined> + getCategory(category:CategoryId): api.ODOptionalPromise<{key:string, value:ODFormattedJsonDatabaseIds_DefaultTickets[CategoryId]}[]|undefined> + getCategory(category:string): api.ODOptionalPromise<{key:string, value:api.ODValidJsonType}[]|undefined> - getCategory(category:string): ODOptionalPromise<{key:string, value:ODValidJsonType}[]|undefined> { + getCategory(category:string): api.ODOptionalPromise<{key:string, value:api.ODValidJsonType}[]|undefined> { return super.getCategory(category) } } @@ -167,39 +166,39 @@ export interface ODFormattedJsonDatabaseIds_DefaultUsers { * * This default class is made for the `users.json` database! */ -export class ODFormattedJsonDatabase_DefaultUsers extends ODFormattedJsonDatabase { - set(category:CategoryId, key:string, value:ODFormattedJsonDatabaseIds_DefaultUsers[CategoryId]): ODOptionalPromise - set(category:string, key:string, value:ODValidJsonType): ODOptionalPromise +export class ODFormattedJsonDatabase_DefaultUsers extends api.ODFormattedJsonDatabase { + set(category:CategoryId, key:string, value:ODFormattedJsonDatabaseIds_DefaultUsers[CategoryId]): api.ODOptionalPromise + set(category:string, key:string, value:api.ODValidJsonType): api.ODOptionalPromise - set(category:string, key:string, value:ODValidJsonType): ODOptionalPromise { + set(category:string, key:string, value:api.ODValidJsonType): api.ODOptionalPromise { return super.set(category,key,value) } - get(category:CategoryId, key:string): ODOptionalPromise - get(category:string, key:string): ODOptionalPromise + get(category:CategoryId, key:string): api.ODOptionalPromise + get(category:string, key:string): api.ODOptionalPromise - get(category:string, key:string): ODOptionalPromise { + get(category:string, key:string): api.ODOptionalPromise { return super.get(category,key) } - delete(category:CategoryId, key:string): ODOptionalPromise - delete(category:string, key:string): ODOptionalPromise + delete(category:CategoryId, key:string): api.ODOptionalPromise + delete(category:string, key:string): api.ODOptionalPromise - delete(category:string, key:string): ODOptionalPromise { + delete(category:string, key:string): api.ODOptionalPromise { return super.delete(category,key) } - exists(category:keyof ODFormattedJsonDatabaseIds_DefaultUsers, key:string): ODOptionalPromise - exists(category:string, key:string): ODOptionalPromise + exists(category:keyof ODFormattedJsonDatabaseIds_DefaultUsers, key:string): api.ODOptionalPromise + exists(category:string, key:string): api.ODOptionalPromise - exists(category:string, key:string): ODOptionalPromise { + exists(category:string, key:string): api.ODOptionalPromise { return super.exists(category,key) } - getCategory(category:CategoryId): ODOptionalPromise<{key:string, value:ODFormattedJsonDatabaseIds_DefaultUsers[CategoryId]}[]|undefined> - getCategory(category:string): ODOptionalPromise<{key:string, value:ODValidJsonType}[]|undefined> + getCategory(category:CategoryId): api.ODOptionalPromise<{key:string, value:ODFormattedJsonDatabaseIds_DefaultUsers[CategoryId]}[]|undefined> + getCategory(category:string): api.ODOptionalPromise<{key:string, value:api.ODValidJsonType}[]|undefined> - getCategory(category:string): ODOptionalPromise<{key:string, value:ODValidJsonType}[]|undefined> { + getCategory(category:string): api.ODOptionalPromise<{key:string, value:api.ODValidJsonType}[]|undefined> { return super.getCategory(category) } } @@ -219,39 +218,39 @@ export interface ODFormattedJsonDatabaseIds_DefaultOptions { * * This default class is made for the `options.json` database! */ -export class ODFormattedJsonDatabase_DefaultOptions extends ODFormattedJsonDatabase { - set(category:CategoryId, key:string, value:ODFormattedJsonDatabaseIds_DefaultOptions[CategoryId]): ODOptionalPromise - set(category:string, key:string, value:ODValidJsonType): ODOptionalPromise +export class ODFormattedJsonDatabase_DefaultOptions extends api.ODFormattedJsonDatabase { + set(category:CategoryId, key:string, value:ODFormattedJsonDatabaseIds_DefaultOptions[CategoryId]): api.ODOptionalPromise + set(category:string, key:string, value:api.ODValidJsonType): api.ODOptionalPromise - set(category:string, key:string, value:ODValidJsonType): ODOptionalPromise { + set(category:string, key:string, value:api.ODValidJsonType): api.ODOptionalPromise { return super.set(category,key,value) } - get(category:CategoryId, key:string): ODOptionalPromise - get(category:string, key:string): ODOptionalPromise + get(category:CategoryId, key:string): api.ODOptionalPromise + get(category:string, key:string): api.ODOptionalPromise - get(category:string, key:string): ODOptionalPromise { + get(category:string, key:string): api.ODOptionalPromise { return super.get(category,key) } - delete(category:CategoryId, key:string): ODOptionalPromise - delete(category:string, key:string): ODOptionalPromise + delete(category:CategoryId, key:string): api.ODOptionalPromise + delete(category:string, key:string): api.ODOptionalPromise - delete(category:string, key:string): ODOptionalPromise { + delete(category:string, key:string): api.ODOptionalPromise { return super.delete(category,key) } - exists(category:keyof ODFormattedJsonDatabaseIds_DefaultOptions, key:string): ODOptionalPromise - exists(category:string, key:string): ODOptionalPromise + exists(category:keyof ODFormattedJsonDatabaseIds_DefaultOptions, key:string): api.ODOptionalPromise + exists(category:string, key:string): api.ODOptionalPromise - exists(category:string, key:string): ODOptionalPromise { + exists(category:string, key:string): api.ODOptionalPromise { return super.exists(category,key) } - getCategory(category:CategoryId): ODOptionalPromise<{key:string, value:ODFormattedJsonDatabaseIds_DefaultOptions[CategoryId]}[]|undefined> - getCategory(category:string): ODOptionalPromise<{key:string, value:ODValidJsonType}[]|undefined> + getCategory(category:CategoryId): api.ODOptionalPromise<{key:string, value:ODFormattedJsonDatabaseIds_DefaultOptions[CategoryId]}[]|undefined> + getCategory(category:string): api.ODOptionalPromise<{key:string, value:api.ODValidJsonType}[]|undefined> - getCategory(category:string): ODOptionalPromise<{key:string, value:ODValidJsonType}[]|undefined> { + getCategory(category:string): api.ODOptionalPromise<{key:string, value:api.ODValidJsonType}[]|undefined> { return super.getCategory(category) } } \ No newline at end of file diff --git a/src/core/api/defaults/event.ts b/src/core/api/defaults/event.ts index 86496fc..2dbc9fc 100644 --- a/src/core/api/defaults/event.ts +++ b/src/core/api/defaults/event.ts @@ -2,13 +2,7 @@ //DEFAULT EVENT MODULE /////////////////////////////////////// //BASE MODULES -import { ODPromiseVoid, ODValidId } from "../modules/base" -import { ODConsoleManager, ODError } from "../modules/console" -import { ODCheckerResult, ODCheckerStorage } from "../modules/checker" -import { ODDefaultsManager } from "../modules/defaults" -import { ODLanguage } from "../modules/language" -import { ODClientActivityManager } from "../modules/client" -import { ODEvent, ODEventManager } from "../modules/event" +import * as api from "@open-discord-bots/framework/api" import * as discord from "discord.js" //DEFAULT MODULES @@ -50,292 +44,292 @@ import { ODPriorityLevel, ODPriorityManager_Default } from "../openticket/priori */ export interface ODEventIds_Default { //error handling - "onErrorHandling": ODEvent_Default<(error:Error, origin:NodeJS.UncaughtExceptionOrigin) => ODPromiseVoid> - "afterErrorHandling": ODEvent_Default<(error:Error, origin:NodeJS.UncaughtExceptionOrigin, message:ODError) => ODPromiseVoid> + "onErrorHandling": ODEvent_Default<(error:Error, origin:NodeJS.UncaughtExceptionOrigin) => api.ODPromiseVoid> + "afterErrorHandling": ODEvent_Default<(error:Error, origin:NodeJS.UncaughtExceptionOrigin, message:api.ODError) => api.ODPromiseVoid> //plugins - "afterPluginsLoaded": ODEvent_Default<(plugins:ODPluginManager_Default) => ODPromiseVoid> - "onPluginClassLoad": ODEvent_Default<(classes:ODPluginClassManager_Default, plugins:ODPluginManager_Default) => ODPromiseVoid> - "afterPluginClassesLoaded": ODEvent_Default<(classes:ODPluginClassManager_Default, plugins:ODPluginManager_Default) => ODPromiseVoid> + "afterPluginsLoaded": ODEvent_Default<(plugins:ODPluginManager_Default) => api.ODPromiseVoid> + "onPluginClassLoad": ODEvent_Default<(classes:ODPluginClassManager_Default, plugins:ODPluginManager_Default) => api.ODPromiseVoid> + "afterPluginClassesLoaded": ODEvent_Default<(classes:ODPluginClassManager_Default, plugins:ODPluginManager_Default) => api.ODPromiseVoid> //flags - "onFlagLoad": ODEvent_Default<(flags:ODFlagManager_Default) => ODPromiseVoid> - "afterFlagsLoaded": ODEvent_Default<(flags:ODFlagManager_Default) => ODPromiseVoid> - "onFlagInit": ODEvent_Default<(flags:ODFlagManager_Default) => ODPromiseVoid> - "afterFlagsInitiated": ODEvent_Default<(flags:ODFlagManager_Default) => ODPromiseVoid> + "onFlagLoad": ODEvent_Default<(flags:ODFlagManager_Default) => api.ODPromiseVoid> + "afterFlagsLoaded": ODEvent_Default<(flags:ODFlagManager_Default) => api.ODPromiseVoid> + "onFlagInit": ODEvent_Default<(flags:ODFlagManager_Default) => api.ODPromiseVoid> + "afterFlagsInitiated": ODEvent_Default<(flags:ODFlagManager_Default) => api.ODPromiseVoid> //progress bars - "onProgressBarRendererLoad": ODEvent_Default<(renderers:ODProgressBarRendererManager_Default) => ODPromiseVoid> - "afterProgressBarRenderersLoaded": ODEvent_Default<(renderers:ODProgressBarRendererManager_Default) => ODPromiseVoid> - "onProgressBarLoad": ODEvent_Default<(progressbars:ODProgressBarManager_Default) => ODPromiseVoid> - "afterProgressBarsLoaded": ODEvent_Default<(progressbars:ODProgressBarManager_Default) => ODPromiseVoid> + "onProgressBarRendererLoad": ODEvent_Default<(renderers:ODProgressBarRendererManager_Default) => api.ODPromiseVoid> + "afterProgressBarRenderersLoaded": ODEvent_Default<(renderers:ODProgressBarRendererManager_Default) => api.ODPromiseVoid> + "onProgressBarLoad": ODEvent_Default<(progressbars:ODProgressBarManager_Default) => api.ODPromiseVoid> + "afterProgressBarsLoaded": ODEvent_Default<(progressbars:ODProgressBarManager_Default) => api.ODPromiseVoid> //configs - "onConfigLoad": ODEvent_Default<(configs:ODConfigManager_Default) => ODPromiseVoid> - "afterConfigsLoaded": ODEvent_Default<(configs:ODConfigManager_Default) => ODPromiseVoid> - "onConfigInit": ODEvent_Default<(configs:ODConfigManager_Default) => ODPromiseVoid> - "afterConfigsInitiated": ODEvent_Default<(configs:ODConfigManager_Default) => ODPromiseVoid> + "onConfigLoad": ODEvent_Default<(configs:ODConfigManager_Default) => api.ODPromiseVoid> + "afterConfigsLoaded": ODEvent_Default<(configs:ODConfigManager_Default) => api.ODPromiseVoid> + "onConfigInit": ODEvent_Default<(configs:ODConfigManager_Default) => api.ODPromiseVoid> + "afterConfigsInitiated": ODEvent_Default<(configs:ODConfigManager_Default) => api.ODPromiseVoid> //databases - "onDatabaseLoad": ODEvent_Default<(databases:ODDatabaseManager_Default) => ODPromiseVoid> - "afterDatabasesLoaded": ODEvent_Default<(databases:ODDatabaseManager_Default) => ODPromiseVoid> - "onDatabaseInit": ODEvent_Default<(databases:ODDatabaseManager_Default) => ODPromiseVoid> - "afterDatabasesInitiated": ODEvent_Default<(databases:ODDatabaseManager_Default) => ODPromiseVoid> + "onDatabaseLoad": ODEvent_Default<(databases:ODDatabaseManager_Default) => api.ODPromiseVoid> + "afterDatabasesLoaded": ODEvent_Default<(databases:ODDatabaseManager_Default) => api.ODPromiseVoid> + "onDatabaseInit": ODEvent_Default<(databases:ODDatabaseManager_Default) => api.ODPromiseVoid> + "afterDatabasesInitiated": ODEvent_Default<(databases:ODDatabaseManager_Default) => api.ODPromiseVoid> //languages - "onLanguageLoad": ODEvent_Default<(languages:ODLanguageManager_Default) => ODPromiseVoid> - "afterLanguagesLoaded": ODEvent_Default<(languages:ODLanguageManager_Default) => ODPromiseVoid> - "onLanguageInit": ODEvent_Default<(languages:ODLanguageManager_Default) => ODPromiseVoid> - "afterLanguagesInitiated": ODEvent_Default<(languages:ODLanguageManager_Default) => ODPromiseVoid> - "onLanguageSelect": ODEvent_Default<(languages:ODLanguageManager_Default) => ODPromiseVoid> - "afterLanguagesSelected": ODEvent_Default<(main:ODLanguage|null, backup:ODLanguage|null, languages:ODLanguageManager_Default) => ODPromiseVoid> + "onLanguageLoad": ODEvent_Default<(languages:ODLanguageManager_Default) => api.ODPromiseVoid> + "afterLanguagesLoaded": ODEvent_Default<(languages:ODLanguageManager_Default) => api.ODPromiseVoid> + "onLanguageInit": ODEvent_Default<(languages:ODLanguageManager_Default) => api.ODPromiseVoid> + "afterLanguagesInitiated": ODEvent_Default<(languages:ODLanguageManager_Default) => api.ODPromiseVoid> + "onLanguageSelect": ODEvent_Default<(languages:ODLanguageManager_Default) => api.ODPromiseVoid> + "afterLanguagesSelected": ODEvent_Default<(main:api.ODLanguage|null, backup:api.ODLanguage|null, languages:ODLanguageManager_Default) => api.ODPromiseVoid> //sessions - "onSessionLoad": ODEvent_Default<(languages:ODSessionManager_Default) => ODPromiseVoid> - "afterSessionsLoaded": ODEvent_Default<(languages:ODSessionManager_Default) => ODPromiseVoid> + "onSessionLoad": ODEvent_Default<(languages:ODSessionManager_Default) => api.ODPromiseVoid> + "afterSessionsLoaded": ODEvent_Default<(languages:ODSessionManager_Default) => api.ODPromiseVoid> //config checkers - "onCheckerLoad": ODEvent_Default<(checkers:ODCheckerManager_Default) => ODPromiseVoid> - "afterCheckersLoaded": ODEvent_Default<(checkers:ODCheckerManager_Default) => ODPromiseVoid> - "onCheckerFunctionLoad": ODEvent_Default<(functions:ODCheckerFunctionManager_Default, checkers:ODCheckerManager_Default) => ODPromiseVoid> - "afterCheckerFunctionsLoaded": ODEvent_Default<(functions:ODCheckerFunctionManager_Default, checkers:ODCheckerManager_Default) => ODPromiseVoid> - "onCheckerExecute": ODEvent_Default<(checkers:ODCheckerManager_Default) => ODPromiseVoid> - "afterCheckersExecuted": ODEvent_Default<(result:ODCheckerResult, checkers:ODCheckerManager_Default) => ODPromiseVoid> - "onCheckerTranslationLoad": ODEvent_Default<(translations:ODCheckerTranslationRegister_Default, enabled:boolean, checkers:ODCheckerManager_Default) => ODPromiseVoid> - "afterCheckerTranslationsLoaded": ODEvent_Default<(translations:ODCheckerTranslationRegister_Default, checkers:ODCheckerManager_Default) => ODPromiseVoid> - "onCheckerRender": ODEvent_Default<(renderer:ODCheckerRenderer_Default, checkers:ODCheckerManager_Default) => ODPromiseVoid> - "afterCheckersRendered": ODEvent_Default<(renderer:ODCheckerRenderer_Default, checkers:ODCheckerManager_Default) => ODPromiseVoid> - "onCheckerQuit": ODEvent_Default<(checkers:ODCheckerManager_Default) => ODPromiseVoid> + "onCheckerLoad": ODEvent_Default<(checkers:ODCheckerManager_Default) => api.ODPromiseVoid> + "afterCheckersLoaded": ODEvent_Default<(checkers:ODCheckerManager_Default) => api.ODPromiseVoid> + "onCheckerFunctionLoad": ODEvent_Default<(functions:ODCheckerFunctionManager_Default, checkers:ODCheckerManager_Default) => api.ODPromiseVoid> + "afterCheckerFunctionsLoaded": ODEvent_Default<(functions:ODCheckerFunctionManager_Default, checkers:ODCheckerManager_Default) => api.ODPromiseVoid> + "onCheckerExecute": ODEvent_Default<(checkers:ODCheckerManager_Default) => api.ODPromiseVoid> + "afterCheckersExecuted": ODEvent_Default<(result:api.ODCheckerResult, checkers:ODCheckerManager_Default) => api.ODPromiseVoid> + "onCheckerTranslationLoad": ODEvent_Default<(translations:ODCheckerTranslationRegister_Default, enabled:boolean, checkers:ODCheckerManager_Default) => api.ODPromiseVoid> + "afterCheckerTranslationsLoaded": ODEvent_Default<(translations:ODCheckerTranslationRegister_Default, checkers:ODCheckerManager_Default) => api.ODPromiseVoid> + "onCheckerRender": ODEvent_Default<(renderer:ODCheckerRenderer_Default, checkers:ODCheckerManager_Default) => api.ODPromiseVoid> + "afterCheckersRendered": ODEvent_Default<(renderer:ODCheckerRenderer_Default, checkers:ODCheckerManager_Default) => api.ODPromiseVoid> + "onCheckerQuit": ODEvent_Default<(checkers:ODCheckerManager_Default) => api.ODPromiseVoid> //plugin loading before client - "onPluginBeforeClientLoad": ODEvent_Default<() => ODPromiseVoid>, - "afterPluginBeforeClientLoaded": ODEvent_Default<() => ODPromiseVoid>, + "onPluginBeforeClientLoad": ODEvent_Default<() => api.ODPromiseVoid>, + "afterPluginBeforeClientLoaded": ODEvent_Default<() => api.ODPromiseVoid>, //client configuration - "onClientLoad": ODEvent_Default<(client:ODClientManager_Default) => ODPromiseVoid> - "afterClientLoaded": ODEvent_Default<(client:ODClientManager_Default) => ODPromiseVoid> - "onClientInit": ODEvent_Default<(client:ODClientManager_Default) => ODPromiseVoid> - "afterClientInitiated": ODEvent_Default<(client:ODClientManager_Default) => ODPromiseVoid> - "onClientReady": ODEvent_Default<(client:ODClientManager_Default) => ODPromiseVoid> - "afterClientReady": ODEvent_Default<(client:ODClientManager_Default) => ODPromiseVoid> - "onClientActivityLoad": ODEvent_Default<(activity:ODClientActivityManager, client:ODClientManager_Default) => ODPromiseVoid> - "afterClientActivityLoaded": ODEvent_Default<(activity:ODClientActivityManager, client:ODClientManager_Default) => ODPromiseVoid> - "onClientActivityInit": ODEvent_Default<(activity:ODClientActivityManager, client:ODClientManager_Default) => ODPromiseVoid> - "afterClientActivityInitiated": ODEvent_Default<(activity:ODClientActivityManager, client:ODClientManager_Default) => ODPromiseVoid> + "onClientLoad": ODEvent_Default<(client:ODClientManager_Default) => api.ODPromiseVoid> + "afterClientLoaded": ODEvent_Default<(client:ODClientManager_Default) => api.ODPromiseVoid> + "onClientInit": ODEvent_Default<(client:ODClientManager_Default) => api.ODPromiseVoid> + "afterClientInitiated": ODEvent_Default<(client:ODClientManager_Default) => api.ODPromiseVoid> + "onClientReady": ODEvent_Default<(client:ODClientManager_Default) => api.ODPromiseVoid> + "afterClientReady": ODEvent_Default<(client:ODClientManager_Default) => api.ODPromiseVoid> + "onClientActivityLoad": ODEvent_Default<(activity:api.ODClientActivityManager, client:ODClientManager_Default) => api.ODPromiseVoid> + "afterClientActivityLoaded": ODEvent_Default<(activity:api.ODClientActivityManager, client:ODClientManager_Default) => api.ODPromiseVoid> + "onClientActivityInit": ODEvent_Default<(activity:api.ODClientActivityManager, client:ODClientManager_Default) => api.ODPromiseVoid> + "afterClientActivityInitiated": ODEvent_Default<(activity:api.ODClientActivityManager, client:ODClientManager_Default) => api.ODPromiseVoid> //priority levels - "onPriorityLoad": ODEvent_Default<(priorities:ODPriorityManager_Default) => ODPromiseVoid> - "afterPrioritiesLoaded": ODEvent_Default<(priorities:ODPriorityManager_Default) => ODPromiseVoid> + "onPriorityLoad": ODEvent_Default<(priorities:ODPriorityManager_Default) => api.ODPromiseVoid> + "afterPrioritiesLoaded": ODEvent_Default<(priorities:ODPriorityManager_Default) => api.ODPromiseVoid> //client slash commands - "onSlashCommandLoad": ODEvent_Default<(slash:ODSlashCommandManager_Default, client:ODClientManager_Default) => ODPromiseVoid> - "afterSlashCommandsLoaded": ODEvent_Default<(slash:ODSlashCommandManager_Default, client:ODClientManager_Default) => ODPromiseVoid> - "onSlashCommandRegister": ODEvent_Default<(slash:ODSlashCommandManager_Default, client:ODClientManager_Default) => ODPromiseVoid> - "afterSlashCommandsRegistered": ODEvent_Default<(slash:ODSlashCommandManager_Default, client:ODClientManager_Default) => ODPromiseVoid> + "onSlashCommandLoad": ODEvent_Default<(slash:ODSlashCommandManager_Default, client:ODClientManager_Default) => api.ODPromiseVoid> + "afterSlashCommandsLoaded": ODEvent_Default<(slash:ODSlashCommandManager_Default, client:ODClientManager_Default) => api.ODPromiseVoid> + "onSlashCommandRegister": ODEvent_Default<(slash:ODSlashCommandManager_Default, client:ODClientManager_Default) => api.ODPromiseVoid> + "afterSlashCommandsRegistered": ODEvent_Default<(slash:ODSlashCommandManager_Default, client:ODClientManager_Default) => api.ODPromiseVoid> //client context menus - "onContextMenuLoad": ODEvent_Default<(menu:ODContextMenuManager_Default, client:ODClientManager_Default) => ODPromiseVoid> - "afterContextMenusLoaded": ODEvent_Default<(menu:ODContextMenuManager_Default, client:ODClientManager_Default) => ODPromiseVoid> - "onContextMenuRegister": ODEvent_Default<(menu:ODContextMenuManager_Default, client:ODClientManager_Default) => ODPromiseVoid> - "afterContextMenusRegistered": ODEvent_Default<(menu:ODContextMenuManager_Default, client:ODClientManager_Default) => ODPromiseVoid> + "onContextMenuLoad": ODEvent_Default<(menu:ODContextMenuManager_Default, client:ODClientManager_Default) => api.ODPromiseVoid> + "afterContextMenusLoaded": ODEvent_Default<(menu:ODContextMenuManager_Default, client:ODClientManager_Default) => api.ODPromiseVoid> + "onContextMenuRegister": ODEvent_Default<(menu:ODContextMenuManager_Default, client:ODClientManager_Default) => api.ODPromiseVoid> + "afterContextMenusRegistered": ODEvent_Default<(menu:ODContextMenuManager_Default, client:ODClientManager_Default) => api.ODPromiseVoid> //client text commands - "onTextCommandLoad": ODEvent_Default<(text:ODTextCommandManager_Default, client:ODClientManager_Default,) => ODPromiseVoid> - "afterTextCommandsLoaded": ODEvent_Default<(text:ODTextCommandManager_Default, client:ODClientManager_Default) => ODPromiseVoid> + "onTextCommandLoad": ODEvent_Default<(text:ODTextCommandManager_Default, client:ODClientManager_Default,) => api.ODPromiseVoid> + "afterTextCommandsLoaded": ODEvent_Default<(text:ODTextCommandManager_Default, client:ODClientManager_Default) => api.ODPromiseVoid> //plugin loading before managers - "onPluginBeforeManagerLoad": ODEvent_Default<() => ODPromiseVoid>, - "afterPluginBeforeManagerLoaded": ODEvent_Default<() => ODPromiseVoid>, + "onPluginBeforeManagerLoad": ODEvent_Default<() => api.ODPromiseVoid>, + "afterPluginBeforeManagerLoaded": ODEvent_Default<() => api.ODPromiseVoid>, //questions - "onQuestionLoad": ODEvent_Default<(questions:ODQuestionManager) => ODPromiseVoid> - "afterQuestionsLoaded": ODEvent_Default<(questions:ODQuestionManager) => ODPromiseVoid> + "onQuestionLoad": ODEvent_Default<(questions:ODQuestionManager) => api.ODPromiseVoid> + "afterQuestionsLoaded": ODEvent_Default<(questions:ODQuestionManager) => api.ODPromiseVoid> //options - "onOptionLoad": ODEvent_Default<(options:ODOptionManager) => ODPromiseVoid> - "afterOptionsLoaded": ODEvent_Default<(options:ODOptionManager) => ODPromiseVoid> + "onOptionLoad": ODEvent_Default<(options:ODOptionManager) => api.ODPromiseVoid> + "afterOptionsLoaded": ODEvent_Default<(options:ODOptionManager) => api.ODPromiseVoid> //panels - "onPanelLoad": ODEvent_Default<(panels:ODPanelManager) => ODPromiseVoid> - "afterPanelsLoaded": ODEvent_Default<(panels:ODPanelManager) => ODPromiseVoid> - "onPanelSpawn": ODEvent_Default<(panel:ODPanel) => ODPromiseVoid> - "afterPanelSpawned": ODEvent_Default<(panel:ODPanel) => ODPromiseVoid> + "onPanelLoad": ODEvent_Default<(panels:ODPanelManager) => api.ODPromiseVoid> + "afterPanelsLoaded": ODEvent_Default<(panels:ODPanelManager) => api.ODPromiseVoid> + "onPanelSpawn": ODEvent_Default<(panel:ODPanel) => api.ODPromiseVoid> + "afterPanelSpawned": ODEvent_Default<(panel:ODPanel) => api.ODPromiseVoid> //tickets - "onTicketLoad": ODEvent_Default<(tickets:ODTicketManager) => ODPromiseVoid> - "afterTicketsLoaded": ODEvent_Default<(tickets:ODTicketManager) => ODPromiseVoid> + "onTicketLoad": ODEvent_Default<(tickets:ODTicketManager) => api.ODPromiseVoid> + "afterTicketsLoaded": ODEvent_Default<(tickets:ODTicketManager) => api.ODPromiseVoid> //ticket creation - "onTicketChannelCreation": ODEvent_Default<(option:ODTicketOption, user:discord.User) => ODPromiseVoid> - "afterTicketChannelCreated": ODEvent_Default<(option:ODTicketOption, channel:discord.GuildTextBasedChannel, user:discord.User) => ODPromiseVoid> - "onTicketChannelDeletion": ODEvent_Default<(ticket:ODTicket, channel:discord.GuildTextBasedChannel, user:discord.User) => ODPromiseVoid> - "afterTicketChannelDeleted": ODEvent_Default<(ticket:ODTicket, user:discord.User) => ODPromiseVoid> - "onTicketPermissionsCreated": ODEvent_Default<(option:ODTicketOption, permissions:ODPermissionManager_Default, channel:discord.GuildTextBasedChannel, user:discord.User) => ODPromiseVoid> - "afterTicketPermissionsCreated": ODEvent_Default<(option:ODTicketOption, permissions:ODPermissionManager_Default, channel:discord.GuildTextBasedChannel, user:discord.User) => ODPromiseVoid> - "onTicketMainMessageCreated": ODEvent_Default<(ticket:ODTicket, channel:discord.GuildTextBasedChannel, user:discord.User) => ODPromiseVoid> - "afterTicketMainMessageCreated": ODEvent_Default<(ticket:ODTicket, message:discord.Message, channel:discord.GuildTextBasedChannel, user:discord.User) => ODPromiseVoid> + "onTicketChannelCreation": ODEvent_Default<(option:ODTicketOption, user:discord.User) => api.ODPromiseVoid> + "afterTicketChannelCreated": ODEvent_Default<(option:ODTicketOption, channel:discord.GuildTextBasedChannel, user:discord.User) => api.ODPromiseVoid> + "onTicketChannelDeletion": ODEvent_Default<(ticket:ODTicket, channel:discord.GuildTextBasedChannel, user:discord.User) => api.ODPromiseVoid> + "afterTicketChannelDeleted": ODEvent_Default<(ticket:ODTicket, user:discord.User) => api.ODPromiseVoid> + "onTicketPermissionsCreated": ODEvent_Default<(option:ODTicketOption, permissions:ODPermissionManager_Default, channel:discord.GuildTextBasedChannel, user:discord.User) => api.ODPromiseVoid> + "afterTicketPermissionsCreated": ODEvent_Default<(option:ODTicketOption, permissions:ODPermissionManager_Default, channel:discord.GuildTextBasedChannel, user:discord.User) => api.ODPromiseVoid> + "onTicketMainMessageCreated": ODEvent_Default<(ticket:ODTicket, channel:discord.GuildTextBasedChannel, user:discord.User) => api.ODPromiseVoid> + "afterTicketMainMessageCreated": ODEvent_Default<(ticket:ODTicket, message:discord.Message, channel:discord.GuildTextBasedChannel, user:discord.User) => api.ODPromiseVoid> //ticket actions - "onTicketCreate": ODEvent_Default<(creator:discord.User) => ODPromiseVoid> - "afterTicketCreated": ODEvent_Default<(ticket:ODTicket, creator:discord.User, channel:discord.GuildTextBasedChannel) => ODPromiseVoid> - "onTicketClose": ODEvent_Default<(ticket:ODTicket, closer:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid> - "afterTicketClosed": ODEvent_Default<(ticket:ODTicket, closer:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid> - "onTicketReopen": ODEvent_Default<(ticket:ODTicket, reopener:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid> - "afterTicketReopened": ODEvent_Default<(ticket:ODTicket, reopener:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid> - "onTicketDelete": ODEvent_Default<(ticket:ODTicket, deleter:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid> - "afterTicketDeleted": ODEvent_Default<(ticket:ODTicket, deleter:discord.User, reason:string|null) => ODPromiseVoid> - "onTicketMove": ODEvent_Default<(ticket:ODTicket, mover:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid> - "afterTicketMoved": ODEvent_Default<(ticket:ODTicket, mover:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid> - "onTicketClaim": ODEvent_Default<(ticket:ODTicket, claimer:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid> - "afterTicketClaimed": ODEvent_Default<(ticket:ODTicket, claimer:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid> - "onTicketUnclaim": ODEvent_Default<(ticket:ODTicket, unclaimer:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid> - "afterTicketUnclaimed": ODEvent_Default<(ticket:ODTicket, unclaimer:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid> - "onTicketPin": ODEvent_Default<(ticket:ODTicket, pinner:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid> - "afterTicketPinned": ODEvent_Default<(ticket:ODTicket, pinner:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid> - "onTicketUnpin": ODEvent_Default<(ticket:ODTicket, unpinner:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid> - "afterTicketUnpinned": ODEvent_Default<(ticket:ODTicket, unpinner:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid> - "onTicketUserAdd": ODEvent_Default<(ticket:ODTicket, adder:discord.User, user:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid> - "afterTicketUserAdded": ODEvent_Default<(ticket:ODTicket, adder:discord.User, user:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid> - "onTicketUserRemove": ODEvent_Default<(ticket:ODTicket, remover:discord.User, user:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid> - "afterTicketUserRemoved": ODEvent_Default<(ticket:ODTicket, remover:discord.User, user:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid> - "onTicketRename": ODEvent_Default<(ticket:ODTicket, renamer:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid> - "afterTicketRenamed": ODEvent_Default<(ticket:ODTicket, renamer:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid> - "onTicketsClear": ODEvent_Default<(tickets:ODTicket[], clearer:discord.User, channel:discord.GuildTextBasedChannel, filter:ODTicketClearFilter) => ODPromiseVoid> - "afterTicketsCleared": ODEvent_Default<(tickets:ODTicket[], clearer:discord.User, channel:discord.GuildTextBasedChannel, filter:ODTicketClearFilter) => ODPromiseVoid> - "onTicketTopicChange": ODEvent_Default<(ticket:ODTicket, changer:discord.User, channel:discord.GuildTextBasedChannel, oldTopic:string, newTopic:string) => ODPromiseVoid> - "afterTicketTopicChanged": ODEvent_Default<(ticket:ODTicket, changer:discord.User, channel:discord.GuildTextBasedChannel, oldTopic:string, newTopic:string) => ODPromiseVoid> - "onTicketPriorityChange": ODEvent_Default<(ticket:ODTicket, changer:discord.User, channel:discord.GuildTextBasedChannel, oldPriority:ODPriorityLevel, newPriority:ODPriorityLevel, reason:string|null) => ODPromiseVoid> - "afterTicketPriorityChanged": ODEvent_Default<(ticket:ODTicket, changer:discord.User, channel:discord.GuildTextBasedChannel, oldPriority:ODPriorityLevel, newPriority:ODPriorityLevel, reason:string|null) => ODPromiseVoid> - "onTicketTransfer": ODEvent_Default<(ticket:ODTicket, changer:discord.User, channel:discord.GuildTextBasedChannel, oldCreator:discord.User, newCreator:discord.User, reason:string|null) => ODPromiseVoid> - "afterTicketTransferred": ODEvent_Default<(ticket:ODTicket, changer:discord.User, channel:discord.GuildTextBasedChannel, oldCreator:discord.User, newCreator:discord.User, reason:string|null) => ODPromiseVoid> + "onTicketCreate": ODEvent_Default<(creator:discord.User) => api.ODPromiseVoid> + "afterTicketCreated": ODEvent_Default<(ticket:ODTicket, creator:discord.User, channel:discord.GuildTextBasedChannel) => api.ODPromiseVoid> + "onTicketClose": ODEvent_Default<(ticket:ODTicket, closer:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => api.ODPromiseVoid> + "afterTicketClosed": ODEvent_Default<(ticket:ODTicket, closer:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => api.ODPromiseVoid> + "onTicketReopen": ODEvent_Default<(ticket:ODTicket, reopener:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => api.ODPromiseVoid> + "afterTicketReopened": ODEvent_Default<(ticket:ODTicket, reopener:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => api.ODPromiseVoid> + "onTicketDelete": ODEvent_Default<(ticket:ODTicket, deleter:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => api.ODPromiseVoid> + "afterTicketDeleted": ODEvent_Default<(ticket:ODTicket, deleter:discord.User, reason:string|null) => api.ODPromiseVoid> + "onTicketMove": ODEvent_Default<(ticket:ODTicket, mover:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => api.ODPromiseVoid> + "afterTicketMoved": ODEvent_Default<(ticket:ODTicket, mover:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => api.ODPromiseVoid> + "onTicketClaim": ODEvent_Default<(ticket:ODTicket, claimer:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => api.ODPromiseVoid> + "afterTicketClaimed": ODEvent_Default<(ticket:ODTicket, claimer:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => api.ODPromiseVoid> + "onTicketUnclaim": ODEvent_Default<(ticket:ODTicket, unclaimer:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => api.ODPromiseVoid> + "afterTicketUnclaimed": ODEvent_Default<(ticket:ODTicket, unclaimer:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => api.ODPromiseVoid> + "onTicketPin": ODEvent_Default<(ticket:ODTicket, pinner:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => api.ODPromiseVoid> + "afterTicketPinned": ODEvent_Default<(ticket:ODTicket, pinner:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => api.ODPromiseVoid> + "onTicketUnpin": ODEvent_Default<(ticket:ODTicket, unpinner:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => api.ODPromiseVoid> + "afterTicketUnpinned": ODEvent_Default<(ticket:ODTicket, unpinner:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => api.ODPromiseVoid> + "onTicketUserAdd": ODEvent_Default<(ticket:ODTicket, adder:discord.User, user:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => api.ODPromiseVoid> + "afterTicketUserAdded": ODEvent_Default<(ticket:ODTicket, adder:discord.User, user:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => api.ODPromiseVoid> + "onTicketUserRemove": ODEvent_Default<(ticket:ODTicket, remover:discord.User, user:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => api.ODPromiseVoid> + "afterTicketUserRemoved": ODEvent_Default<(ticket:ODTicket, remover:discord.User, user:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => api.ODPromiseVoid> + "onTicketRename": ODEvent_Default<(ticket:ODTicket, renamer:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => api.ODPromiseVoid> + "afterTicketRenamed": ODEvent_Default<(ticket:ODTicket, renamer:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => api.ODPromiseVoid> + "onTicketsClear": ODEvent_Default<(tickets:ODTicket[], clearer:discord.User, channel:discord.GuildTextBasedChannel, filter:ODTicketClearFilter) => api.ODPromiseVoid> + "afterTicketsCleared": ODEvent_Default<(tickets:ODTicket[], clearer:discord.User, channel:discord.GuildTextBasedChannel, filter:ODTicketClearFilter) => api.ODPromiseVoid> + "onTicketTopicChange": ODEvent_Default<(ticket:ODTicket, changer:discord.User, channel:discord.GuildTextBasedChannel, oldTopic:string, newTopic:string) => api.ODPromiseVoid> + "afterTicketTopicChanged": ODEvent_Default<(ticket:ODTicket, changer:discord.User, channel:discord.GuildTextBasedChannel, oldTopic:string, newTopic:string) => api.ODPromiseVoid> + "onTicketPriorityChange": ODEvent_Default<(ticket:ODTicket, changer:discord.User, channel:discord.GuildTextBasedChannel, oldPriority:ODPriorityLevel, newPriority:ODPriorityLevel, reason:string|null) => api.ODPromiseVoid> + "afterTicketPriorityChanged": ODEvent_Default<(ticket:ODTicket, changer:discord.User, channel:discord.GuildTextBasedChannel, oldPriority:ODPriorityLevel, newPriority:ODPriorityLevel, reason:string|null) => api.ODPromiseVoid> + "onTicketTransfer": ODEvent_Default<(ticket:ODTicket, changer:discord.User, channel:discord.GuildTextBasedChannel, oldCreator:discord.User, newCreator:discord.User, reason:string|null) => api.ODPromiseVoid> + "afterTicketTransferred": ODEvent_Default<(ticket:ODTicket, changer:discord.User, channel:discord.GuildTextBasedChannel, oldCreator:discord.User, newCreator:discord.User, reason:string|null) => api.ODPromiseVoid> //roles - "onRoleLoad": ODEvent_Default<(roles:ODRoleManager) => ODPromiseVoid> - "afterRolesLoaded": ODEvent_Default<(roles:ODRoleManager) => ODPromiseVoid> - "onRoleUpdate": ODEvent_Default<(user:discord.User,role:ODRole) => ODPromiseVoid> - "afterRolesUpdated": ODEvent_Default<(user:discord.User,role:ODRole) => ODPromiseVoid> + "onRoleLoad": ODEvent_Default<(roles:ODRoleManager) => api.ODPromiseVoid> + "afterRolesLoaded": ODEvent_Default<(roles:ODRoleManager) => api.ODPromiseVoid> + "onRoleUpdate": ODEvent_Default<(user:discord.User,role:ODRole) => api.ODPromiseVoid> + "afterRolesUpdated": ODEvent_Default<(user:discord.User,role:ODRole) => api.ODPromiseVoid> //blacklist - "onBlacklistLoad": ODEvent_Default<(blacklist:ODBlacklistManager) => ODPromiseVoid> - "afterBlacklistLoaded": ODEvent_Default<(blacklist:ODBlacklistManager) => ODPromiseVoid> + "onBlacklistLoad": ODEvent_Default<(blacklist:ODBlacklistManager) => api.ODPromiseVoid> + "afterBlacklistLoaded": ODEvent_Default<(blacklist:ODBlacklistManager) => api.ODPromiseVoid> //transcripts - "onTranscriptCompilerLoad": ODEvent_Default<(transcripts:ODTranscriptManager_Default) => ODPromiseVoid> - "afterTranscriptCompilersLoaded": ODEvent_Default<(transcripts:ODTranscriptManager_Default) => ODPromiseVoid> - "onTranscriptHistoryLoad": ODEvent_Default<(transcripts:ODTranscriptManager_Default) => ODPromiseVoid> - "afterTranscriptHistoryLoaded": ODEvent_Default<(transcripts:ODTranscriptManager_Default) => ODPromiseVoid> + "onTranscriptCompilerLoad": ODEvent_Default<(transcripts:ODTranscriptManager_Default) => api.ODPromiseVoid> + "afterTranscriptCompilersLoaded": ODEvent_Default<(transcripts:ODTranscriptManager_Default) => api.ODPromiseVoid> + "onTranscriptHistoryLoad": ODEvent_Default<(transcripts:ODTranscriptManager_Default) => api.ODPromiseVoid> + "afterTranscriptHistoryLoaded": ODEvent_Default<(transcripts:ODTranscriptManager_Default) => api.ODPromiseVoid> //transcript creation - "onTranscriptCreate": ODEvent_Default<(transcripts:ODTranscriptManager_Default,ticket:ODTicket,channel:discord.TextChannel,user:discord.User) => ODPromiseVoid> - "afterTranscriptCreated": ODEvent_Default<(transcripts:ODTranscriptManager_Default,ticket:ODTicket,channel:discord.TextChannel,user:discord.User) => ODPromiseVoid> - "onTranscriptInit": ODEvent_Default<(transcripts:ODTranscriptManager_Default,ticket:ODTicket,channel:discord.TextChannel,user:discord.User) => ODPromiseVoid> - "afterTranscriptInitiated": ODEvent_Default<(transcripts:ODTranscriptManager_Default,ticket:ODTicket,channel:discord.TextChannel,user:discord.User) => ODPromiseVoid> - "onTranscriptCompile": ODEvent_Default<(transcripts:ODTranscriptManager_Default,ticket:ODTicket,channel:discord.TextChannel,user:discord.User) => ODPromiseVoid> - "afterTranscriptCompiled": ODEvent_Default<(transcripts:ODTranscriptManager_Default,ticket:ODTicket,channel:discord.TextChannel,user:discord.User) => ODPromiseVoid> - "onTranscriptReady": ODEvent_Default<(transcripts:ODTranscriptManager_Default,ticket:ODTicket,channel:discord.TextChannel,user:discord.User) => ODPromiseVoid> - "afterTranscriptReady": ODEvent_Default<(transcripts:ODTranscriptManager_Default,ticket:ODTicket,channel:discord.TextChannel,user:discord.User) => ODPromiseVoid> + "onTranscriptCreate": ODEvent_Default<(transcripts:ODTranscriptManager_Default,ticket:ODTicket,channel:discord.TextChannel,user:discord.User) => api.ODPromiseVoid> + "afterTranscriptCreated": ODEvent_Default<(transcripts:ODTranscriptManager_Default,ticket:ODTicket,channel:discord.TextChannel,user:discord.User) => api.ODPromiseVoid> + "onTranscriptInit": ODEvent_Default<(transcripts:ODTranscriptManager_Default,ticket:ODTicket,channel:discord.TextChannel,user:discord.User) => api.ODPromiseVoid> + "afterTranscriptInitiated": ODEvent_Default<(transcripts:ODTranscriptManager_Default,ticket:ODTicket,channel:discord.TextChannel,user:discord.User) => api.ODPromiseVoid> + "onTranscriptCompile": ODEvent_Default<(transcripts:ODTranscriptManager_Default,ticket:ODTicket,channel:discord.TextChannel,user:discord.User) => api.ODPromiseVoid> + "afterTranscriptCompiled": ODEvent_Default<(transcripts:ODTranscriptManager_Default,ticket:ODTicket,channel:discord.TextChannel,user:discord.User) => api.ODPromiseVoid> + "onTranscriptReady": ODEvent_Default<(transcripts:ODTranscriptManager_Default,ticket:ODTicket,channel:discord.TextChannel,user:discord.User) => api.ODPromiseVoid> + "afterTranscriptReady": ODEvent_Default<(transcripts:ODTranscriptManager_Default,ticket:ODTicket,channel:discord.TextChannel,user:discord.User) => api.ODPromiseVoid> //plugin loading before builders - "onPluginBeforeBuilderLoad": ODEvent_Default<() => ODPromiseVoid>, - "afterPluginBeforeBuilderLoaded": ODEvent_Default<() => ODPromiseVoid>, + "onPluginBeforeBuilderLoad": ODEvent_Default<() => api.ODPromiseVoid>, + "afterPluginBeforeBuilderLoaded": ODEvent_Default<() => api.ODPromiseVoid>, //builders - "onButtonBuilderLoad": ODEvent_Default<(buttons:ODButtonManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> - "afterButtonBuildersLoaded": ODEvent_Default<(buttons:ODButtonManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> - "onDropdownBuilderLoad": ODEvent_Default<(dropdowns:ODDropdownManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> - "afterDropdownBuildersLoaded": ODEvent_Default<(dropdowns:ODDropdownManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> - "onFileBuilderLoad": ODEvent_Default<(files:ODFileManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> - "afterFileBuildersLoaded": ODEvent_Default<(files:ODFileManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> - "onEmbedBuilderLoad": ODEvent_Default<(embeds:ODEmbedManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> - "afterEmbedBuildersLoaded": ODEvent_Default<(embeds:ODEmbedManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> - "onMessageBuilderLoad": ODEvent_Default<(messages:ODMessageManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> - "afterMessageBuildersLoaded": ODEvent_Default<(messages:ODMessageManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> - "onModalBuilderLoad": ODEvent_Default<(modals:ODModalManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> - "afterModalBuildersLoaded": ODEvent_Default<(modals:ODModalManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> + "onButtonBuilderLoad": ODEvent_Default<(buttons:ODButtonManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => api.ODPromiseVoid> + "afterButtonBuildersLoaded": ODEvent_Default<(buttons:ODButtonManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => api.ODPromiseVoid> + "onDropdownBuilderLoad": ODEvent_Default<(dropdowns:ODDropdownManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => api.ODPromiseVoid> + "afterDropdownBuildersLoaded": ODEvent_Default<(dropdowns:ODDropdownManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => api.ODPromiseVoid> + "onFileBuilderLoad": ODEvent_Default<(files:ODFileManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => api.ODPromiseVoid> + "afterFileBuildersLoaded": ODEvent_Default<(files:ODFileManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => api.ODPromiseVoid> + "onEmbedBuilderLoad": ODEvent_Default<(embeds:ODEmbedManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => api.ODPromiseVoid> + "afterEmbedBuildersLoaded": ODEvent_Default<(embeds:ODEmbedManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => api.ODPromiseVoid> + "onMessageBuilderLoad": ODEvent_Default<(messages:ODMessageManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => api.ODPromiseVoid> + "afterMessageBuildersLoaded": ODEvent_Default<(messages:ODMessageManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => api.ODPromiseVoid> + "onModalBuilderLoad": ODEvent_Default<(modals:ODModalManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => api.ODPromiseVoid> + "afterModalBuildersLoaded": ODEvent_Default<(modals:ODModalManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => api.ODPromiseVoid> //plugin loading before responders - "onPluginBeforeResponderLoad": ODEvent_Default<() => ODPromiseVoid>, - "afterPluginBeforeResponderLoaded": ODEvent_Default<() => ODPromiseVoid>, + "onPluginBeforeResponderLoad": ODEvent_Default<() => api.ODPromiseVoid>, + "afterPluginBeforeResponderLoaded": ODEvent_Default<() => api.ODPromiseVoid>, //responders - "onCommandResponderLoad": ODEvent_Default<(commands:ODCommandResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> - "afterCommandRespondersLoaded": ODEvent_Default<(commands:ODCommandResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> - "onButtonResponderLoad": ODEvent_Default<(buttons:ODButtonResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> - "afterButtonRespondersLoaded": ODEvent_Default<(buttons:ODButtonResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> - "onDropdownResponderLoad": ODEvent_Default<(dropdowns:ODDropdownResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> - "afterDropdownRespondersLoaded": ODEvent_Default<(dropdowns:ODDropdownResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> - "onModalResponderLoad": ODEvent_Default<(modals:ODModalResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> - "afterModalRespondersLoaded": ODEvent_Default<(modals:ODModalResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> - "onContextMenuResponderLoad": ODEvent_Default<(menus:ODContextMenuResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> - "afterContextMenuRespondersLoaded": ODEvent_Default<(menus:ODContextMenuResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> - "onAutocompleteResponderLoad": ODEvent_Default<(autocomplete:ODAutocompleteResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> - "afterAutocompleteRespondersLoaded": ODEvent_Default<(autocomplete:ODAutocompleteResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid> + "onCommandResponderLoad": ODEvent_Default<(commands:ODCommandResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => api.ODPromiseVoid> + "afterCommandRespondersLoaded": ODEvent_Default<(commands:ODCommandResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => api.ODPromiseVoid> + "onButtonResponderLoad": ODEvent_Default<(buttons:ODButtonResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => api.ODPromiseVoid> + "afterButtonRespondersLoaded": ODEvent_Default<(buttons:ODButtonResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => api.ODPromiseVoid> + "onDropdownResponderLoad": ODEvent_Default<(dropdowns:ODDropdownResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => api.ODPromiseVoid> + "afterDropdownRespondersLoaded": ODEvent_Default<(dropdowns:ODDropdownResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => api.ODPromiseVoid> + "onModalResponderLoad": ODEvent_Default<(modals:ODModalResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => api.ODPromiseVoid> + "afterModalRespondersLoaded": ODEvent_Default<(modals:ODModalResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => api.ODPromiseVoid> + "onContextMenuResponderLoad": ODEvent_Default<(menus:ODContextMenuResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => api.ODPromiseVoid> + "afterContextMenuRespondersLoaded": ODEvent_Default<(menus:ODContextMenuResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => api.ODPromiseVoid> + "onAutocompleteResponderLoad": ODEvent_Default<(autocomplete:ODAutocompleteResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => api.ODPromiseVoid> + "afterAutocompleteRespondersLoaded": ODEvent_Default<(autocomplete:ODAutocompleteResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => api.ODPromiseVoid> //plugin loading before finalizations - "onPluginBeforeFinalizationLoad": ODEvent_Default<() => ODPromiseVoid>, - "afterPluginBeforeFinalizationLoaded": ODEvent_Default<() => ODPromiseVoid>, + "onPluginBeforeFinalizationLoad": ODEvent_Default<() => api.ODPromiseVoid>, + "afterPluginBeforeFinalizationLoaded": ODEvent_Default<() => api.ODPromiseVoid>, //actions - "onActionLoad": ODEvent_Default<(actions:ODActionManager_Default) => ODPromiseVoid> - "afterActionsLoaded": ODEvent_Default<(actions:ODActionManager_Default) => ODPromiseVoid> + "onActionLoad": ODEvent_Default<(actions:ODActionManager_Default) => api.ODPromiseVoid> + "afterActionsLoaded": ODEvent_Default<(actions:ODActionManager_Default) => api.ODPromiseVoid> //verifybars - "onVerifyBarLoad": ODEvent_Default<(verifybars:ODVerifyBarManager_Default) => ODPromiseVoid> - "afterVerifyBarsLoaded": ODEvent_Default<(verifybars:ODVerifyBarManager_Default) => ODPromiseVoid> + "onVerifyBarLoad": ODEvent_Default<(verifybars:ODVerifyBarManager_Default) => api.ODPromiseVoid> + "afterVerifyBarsLoaded": ODEvent_Default<(verifybars:ODVerifyBarManager_Default) => api.ODPromiseVoid> //permissions - "onPermissionLoad": ODEvent_Default<(permissions:ODPermissionManager_Default) => ODPromiseVoid> - "afterPermissionsLoaded": ODEvent_Default<(permissions:ODPermissionManager_Default) => ODPromiseVoid> + "onPermissionLoad": ODEvent_Default<(permissions:ODPermissionManager_Default) => api.ODPromiseVoid> + "afterPermissionsLoaded": ODEvent_Default<(permissions:ODPermissionManager_Default) => api.ODPromiseVoid> //posts - "onPostLoad": ODEvent_Default<(posts:ODPostManager_Default) => ODPromiseVoid> - "afterPostsLoaded": ODEvent_Default<(posts:ODPostManager_Default) => ODPromiseVoid> - "onPostInit": ODEvent_Default<(posts:ODPostManager_Default) => ODPromiseVoid> - "afterPostsInitiated": ODEvent_Default<(posts:ODPostManager_Default) => ODPromiseVoid> + "onPostLoad": ODEvent_Default<(posts:ODPostManager_Default) => api.ODPromiseVoid> + "afterPostsLoaded": ODEvent_Default<(posts:ODPostManager_Default) => api.ODPromiseVoid> + "onPostInit": ODEvent_Default<(posts:ODPostManager_Default) => api.ODPromiseVoid> + "afterPostsInitiated": ODEvent_Default<(posts:ODPostManager_Default) => api.ODPromiseVoid> //cooldowns - "onCooldownLoad": ODEvent_Default<(cooldowns:ODCooldownManager_Default) => ODPromiseVoid> - "afterCooldownsLoaded": ODEvent_Default<(cooldowns:ODCooldownManager_Default) => ODPromiseVoid> - "onCooldownInit": ODEvent_Default<(cooldowns:ODCooldownManager_Default) => ODPromiseVoid> - "afterCooldownsInitiated": ODEvent_Default<(cooldowns:ODCooldownManager_Default) => ODPromiseVoid> + "onCooldownLoad": ODEvent_Default<(cooldowns:ODCooldownManager_Default) => api.ODPromiseVoid> + "afterCooldownsLoaded": ODEvent_Default<(cooldowns:ODCooldownManager_Default) => api.ODPromiseVoid> + "onCooldownInit": ODEvent_Default<(cooldowns:ODCooldownManager_Default) => api.ODPromiseVoid> + "afterCooldownsInitiated": ODEvent_Default<(cooldowns:ODCooldownManager_Default) => api.ODPromiseVoid> //help menu - "onHelpMenuCategoryLoad": ODEvent_Default<(menu:ODHelpMenuManager_Default) => ODPromiseVoid> - "afterHelpMenuCategoriesLoaded": ODEvent_Default<(menu:ODHelpMenuManager_Default) => ODPromiseVoid> - "onHelpMenuComponentLoad": ODEvent_Default<(menu:ODHelpMenuManager_Default) => ODPromiseVoid> - "afterHelpMenuComponentsLoaded": ODEvent_Default<(menu:ODHelpMenuManager_Default) => ODPromiseVoid> + "onHelpMenuCategoryLoad": ODEvent_Default<(menu:ODHelpMenuManager_Default) => api.ODPromiseVoid> + "afterHelpMenuCategoriesLoaded": ODEvent_Default<(menu:ODHelpMenuManager_Default) => api.ODPromiseVoid> + "onHelpMenuComponentLoad": ODEvent_Default<(menu:ODHelpMenuManager_Default) => api.ODPromiseVoid> + "afterHelpMenuComponentsLoaded": ODEvent_Default<(menu:ODHelpMenuManager_Default) => api.ODPromiseVoid> //stats - "onStatScopeLoad": ODEvent_Default<(stats:ODStatsManager_Default) => ODPromiseVoid> - "afterStatScopesLoaded": ODEvent_Default<(stats:ODStatsManager_Default) => ODPromiseVoid> - "onStatLoad": ODEvent_Default<(stats:ODStatsManager_Default) => ODPromiseVoid> - "afterStatsLoaded": ODEvent_Default<(stats:ODStatsManager_Default) => ODPromiseVoid> - "onStatInit": ODEvent_Default<(stats:ODStatsManager_Default) => ODPromiseVoid> - "afterStatsInitiated": ODEvent_Default<(stats:ODStatsManager_Default) => ODPromiseVoid> + "onStatScopeLoad": ODEvent_Default<(stats:ODStatsManager_Default) => api.ODPromiseVoid> + "afterStatScopesLoaded": ODEvent_Default<(stats:ODStatsManager_Default) => api.ODPromiseVoid> + "onStatLoad": ODEvent_Default<(stats:ODStatsManager_Default) => api.ODPromiseVoid> + "afterStatsLoaded": ODEvent_Default<(stats:ODStatsManager_Default) => api.ODPromiseVoid> + "onStatInit": ODEvent_Default<(stats:ODStatsManager_Default) => api.ODPromiseVoid> + "afterStatsInitiated": ODEvent_Default<(stats:ODStatsManager_Default) => api.ODPromiseVoid> //plugin loading before code - "onPluginBeforeCodeLoad": ODEvent_Default<() => ODPromiseVoid>, - "afterPluginBeforeCodeLoaded": ODEvent_Default<() => ODPromiseVoid>, + "onPluginBeforeCodeLoad": ODEvent_Default<() => api.ODPromiseVoid>, + "afterPluginBeforeCodeLoaded": ODEvent_Default<() => api.ODPromiseVoid>, //code - "onCodeLoad": ODEvent_Default<(code:ODCodeManager_Default) => ODPromiseVoid> - "afterCodeLoaded": ODEvent_Default<(code:ODCodeManager_Default) => ODPromiseVoid> - "onCodeExecute": ODEvent_Default<(code:ODCodeManager_Default) => ODPromiseVoid> - "afterCodeExecuted": ODEvent_Default<(code:ODCodeManager_Default) => ODPromiseVoid> + "onCodeLoad": ODEvent_Default<(code:ODCodeManager_Default) => api.ODPromiseVoid> + "afterCodeLoaded": ODEvent_Default<(code:ODCodeManager_Default) => api.ODPromiseVoid> + "onCodeExecute": ODEvent_Default<(code:ODCodeManager_Default) => api.ODPromiseVoid> + "afterCodeExecuted": ODEvent_Default<(code:ODCodeManager_Default) => api.ODPromiseVoid> //livestatus - "onLiveStatusSourceLoad": ODEvent_Default<(livestatus:ODLiveStatusManager_Default) => ODPromiseVoid> - "afterLiveStatusSourcesLoaded": ODEvent_Default<(livestatus:ODLiveStatusManager_Default) => ODPromiseVoid> + "onLiveStatusSourceLoad": ODEvent_Default<(livestatus:ODLiveStatusManager_Default) => api.ODPromiseVoid> + "afterLiveStatusSourcesLoaded": ODEvent_Default<(livestatus:ODLiveStatusManager_Default) => api.ODPromiseVoid> //startscreen - "onStartScreenLoad": ODEvent_Default<(startscreen:ODStartScreenManager_Default) => ODPromiseVoid> - "afterStartScreensLoaded": ODEvent_Default<(startscreen:ODStartScreenManager_Default) => ODPromiseVoid> - "onStartScreenRender": ODEvent_Default<(startscreen:ODStartScreenManager_Default) => ODPromiseVoid> - "afterStartScreensRendered": ODEvent_Default<(startscreen:ODStartScreenManager_Default) => ODPromiseVoid> + "onStartScreenLoad": ODEvent_Default<(startscreen:ODStartScreenManager_Default) => api.ODPromiseVoid> + "afterStartScreensLoaded": ODEvent_Default<(startscreen:ODStartScreenManager_Default) => api.ODPromiseVoid> + "onStartScreenRender": ODEvent_Default<(startscreen:ODStartScreenManager_Default) => api.ODPromiseVoid> + "afterStartScreensRendered": ODEvent_Default<(startscreen:ODStartScreenManager_Default) => api.ODPromiseVoid> //ready - "beforeReadyForUsage": ODEvent_Default<() => ODPromiseVoid> - "onReadyForUsage": ODEvent_Default<() => ODPromiseVoid> + "beforeReadyForUsage": ODEvent_Default<() => api.ODPromiseVoid> + "onReadyForUsage": ODEvent_Default<() => api.ODPromiseVoid> } /**## ODEventManager_Default `default_class` @@ -344,25 +338,25 @@ export interface ODEventIds_Default { * * This default class is made for the global variable `opendiscord.events`! */ -export class ODEventManager_Default extends ODEventManager { +export class ODEventManager_Default extends api.ODEventManager { get(id:StartScreenId): ODEventIds_Default[StartScreenId] - get(id:ODValidId): ODEvent|null + get(id:api.ODValidId): api.ODEvent|null - get(id:ODValidId): ODEvent|null { + get(id:api.ODValidId): api.ODEvent|null { return super.get(id) } remove(id:StartScreenId): ODEventIds_Default[StartScreenId] - remove(id:ODValidId): ODEvent|null + remove(id:api.ODValidId): api.ODEvent|null - remove(id:ODValidId): ODEvent|null { + remove(id:api.ODValidId): api.ODEvent|null { return super.remove(id) } exists(id:keyof ODEventIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -373,7 +367,7 @@ export class ODEventManager_Default extends ODEventManager { * * This default class is made for the global variable `opendiscord.events`! */ -export class ODEvent_Default ODPromiseVoid)> extends ODEvent { +export class ODEvent_Default api.ODPromiseVoid)> extends api.ODEvent { listen(callback:Callback): void { return super.listen(callback) } diff --git a/src/core/api/defaults/flag.ts b/src/core/api/defaults/flag.ts index 8830cc2..5e68b13 100644 --- a/src/core/api/defaults/flag.ts +++ b/src/core/api/defaults/flag.ts @@ -1,30 +1,29 @@ /////////////////////////////////////// //DEFAULT PROCESS MODULE /////////////////////////////////////// -import { ODValidId } from "../modules/base" -import { ODFlagManager, ODFlag } from "../modules/flag" +import * as api from "@open-discord-bots/framework/api" /**## ODFlagManagerIds_Default `interface` * This interface is a list of ids available in the `ODFlagManager_Default` class. * It's used to generate typescript declarations for this class. */ export interface ODFlagManagerIds_Default { - "opendiscord:no-migration":ODFlag, - "opendiscord:dev-config":ODFlag, - "opendiscord:dev-database":ODFlag, - "opendiscord:debug":ODFlag, - "opendiscord:crash":ODFlag, - "opendiscord:no-transcripts":ODFlag, - "opendiscord:no-checker":ODFlag, - "opendiscord:checker":ODFlag, - "opendiscord:no-easter":ODFlag, - "opendiscord:no-plugins":ODFlag, - "opendiscord:soft-plugins":ODFlag, - "opendiscord:force-slash-update":ODFlag, - "opendiscord:no-compile":ODFlag, - "opendiscord:compile-only":ODFlag, - "opendiscord:silent":ODFlag, - "opendiscord:cli":ODFlag, + "opendiscord:no-migration":api.ODFlag, + "opendiscord:dev-config":api.ODFlag, + "opendiscord:dev-database":api.ODFlag, + "opendiscord:debug":api.ODFlag, + "opendiscord:crash":api.ODFlag, + "opendiscord:no-transcripts":api.ODFlag, + "opendiscord:no-checker":api.ODFlag, + "opendiscord:checker":api.ODFlag, + "opendiscord:no-easter":api.ODFlag, + "opendiscord:no-plugins":api.ODFlag, + "opendiscord:soft-plugins":api.ODFlag, + "opendiscord:force-slash-update":api.ODFlag, + "opendiscord:no-compile":api.ODFlag, + "opendiscord:compile-only":api.ODFlag, + "opendiscord:silent":api.ODFlag, + "opendiscord:cli":api.ODFlag, } /**## ODFlagManager_Default `default_class` @@ -33,25 +32,25 @@ export interface ODFlagManagerIds_Default { * * This default class is made for the global variable `opendiscord.flags`! */ -export class ODFlagManager_Default extends ODFlagManager { +export class ODFlagManager_Default extends api.ODFlagManager { get(id:FlagId): ODFlagManagerIds_Default[FlagId] - get(id:ODValidId): ODFlag|null + get(id:api.ODValidId): api.ODFlag|null - get(id:ODValidId): ODFlag|null { + get(id:api.ODValidId): api.ODFlag|null { return super.get(id) } remove(id:FlagId): ODFlagManagerIds_Default[FlagId] - remove(id:ODValidId): ODFlag|null + remove(id:api.ODValidId): api.ODFlag|null - remove(id:ODValidId): ODFlag|null { + remove(id:api.ODValidId): api.ODFlag|null { return super.remove(id) } exists(id:keyof ODFlagManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } \ No newline at end of file diff --git a/src/core/api/defaults/fuse.ts b/src/core/api/defaults/fuse.ts new file mode 100644 index 0000000..bf77248 --- /dev/null +++ b/src/core/api/defaults/fuse.ts @@ -0,0 +1,27 @@ +/////////////////////////////////////// +//DEFAULT FUSE MODULE +/////////////////////////////////////// +import * as api from "@open-discord-bots/framework/api" + +export interface ODOpenTicketFuseList { + /**Load the default Open Ticket questions (from `config/questions.json`) */ + questionLoading:boolean, + /**Load the default Open Ticket options (from `config/options.json`) */ + optionLoading:boolean, + /**Load the default Open Ticket panels (from `config/panels.json`) */ + panelLoading:boolean, + /**Load the default Open Ticket tickets (from `database/tickets.json`) */ + ticketLoading:boolean, + /**Load the default Open Ticket reaction roles (from `config/options.json`) */ + roleLoading:boolean, + /**Load the default Open Ticket blacklist (from `database/users.json`) */ + blacklistLoading:boolean, + /**Load the default Open Ticket transcript compilers. */ + transcriptCompilerLoading:boolean, + /**Load the default Open Ticket transcript history (from `database/transcripts.json`) */ + transcriptHistoryLoading:boolean, + /**The interval in milliseconds that are between autoclose timeout checkers. */ + autocloseCheckInterval:number, + /**The interval in milliseconds that are between autodelete timeout checkers. */ + autodeleteCheckInterval:number, +} \ No newline at end of file diff --git a/src/core/api/defaults/helpmenu.ts b/src/core/api/defaults/helpmenu.ts index 9864f18..673d2c9 100644 --- a/src/core/api/defaults/helpmenu.ts +++ b/src/core/api/defaults/helpmenu.ts @@ -1,8 +1,7 @@ /////////////////////////////////////// //DEFAULT HELP MODULE /////////////////////////////////////// -import { ODValidId } from "../modules/base" -import { ODHelpMenuCategory, ODHelpMenuCommandComponent, ODHelpMenuComponent, ODHelpMenuManager } from "../modules/helpmenu" +import * as api from "@open-discord-bots/framework/api" /** (CONTRIBUTOR GUIDE) HOW TO ADD NEW COMMANDS? * - Register the command in loadAllSlashCommands() & loadAllTextCommands() in (./src/data/framework/commandLoader.ts) @@ -34,25 +33,25 @@ export interface ODHelpMenuManagerIds_Default { * * This default class is made for the global variable `opendiscord.helpmenu`! */ -export class ODHelpMenuManager_Default extends ODHelpMenuManager { +export class ODHelpMenuManager_Default extends api.ODHelpMenuManager { get(id:HelpMenuCategoryId): ODHelpMenuManagerIds_Default[HelpMenuCategoryId] - get(id:ODValidId): ODHelpMenuCategory|null + get(id:api.ODValidId): api.ODHelpMenuCategory|null - get(id:ODValidId): ODHelpMenuCategory|null { + get(id:api.ODValidId): api.ODHelpMenuCategory|null { return super.get(id) } remove(id:HelpMenuCategoryId): ODHelpMenuManagerIds_Default[HelpMenuCategoryId] - remove(id:ODValidId): ODHelpMenuCategory|null + remove(id:api.ODValidId): api.ODHelpMenuCategory|null - remove(id:ODValidId): ODHelpMenuCategory|null { + remove(id:api.ODValidId): api.ODHelpMenuCategory|null { return super.remove(id) } exists(id:keyof ODHelpMenuManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -62,8 +61,8 @@ export class ODHelpMenuManager_Default extends ODHelpMenuManager { * It's used to generate typescript declarations for this class. */ export interface ODHelpMenuManagerCategoryIds_DefaultGeneral { - "opendiscord:help":ODHelpMenuCommandComponent, - "opendiscord:ticket":ODHelpMenuCommandComponent|null + "opendiscord:help":api.ODHelpMenuCommandComponent, + "opendiscord:ticket":api.ODHelpMenuCommandComponent|null } /**## ODHelpMenuCategory_DefaultGeneral `default_class` @@ -72,25 +71,25 @@ export interface ODHelpMenuManagerCategoryIds_DefaultGeneral { * * This default class is made for the `opendiscord:general` category in `opendiscord.helpmenu`! */ -export class ODHelpMenuCategory_DefaultGeneral extends ODHelpMenuCategory { +export class ODHelpMenuCategory_DefaultGeneral extends api.ODHelpMenuCategory { get(id:HelpMenuCategoryId): ODHelpMenuManagerCategoryIds_DefaultGeneral[HelpMenuCategoryId] - get(id:ODValidId): ODHelpMenuComponent|null + get(id:api.ODValidId): api.ODHelpMenuComponent|null - get(id:ODValidId): ODHelpMenuComponent|null { + get(id:api.ODValidId): api.ODHelpMenuComponent|null { return super.get(id) } remove(id:HelpMenuCategoryId): ODHelpMenuManagerCategoryIds_DefaultGeneral[HelpMenuCategoryId] - remove(id:ODValidId): ODHelpMenuComponent|null + remove(id:api.ODValidId): api.ODHelpMenuComponent|null - remove(id:ODValidId): ODHelpMenuComponent|null { + remove(id:api.ODValidId): api.ODHelpMenuComponent|null { return super.remove(id) } exists(id:keyof ODHelpMenuManagerCategoryIds_DefaultGeneral): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -100,9 +99,9 @@ export class ODHelpMenuCategory_DefaultGeneral extends ODHelpMenuCategory { * It's used to generate typescript declarations for this class. */ export interface ODHelpMenuManagerCategoryIds_DefaultTicketBasic { - "opendiscord:close":ODHelpMenuCommandComponent, - "opendiscord:delete":ODHelpMenuCommandComponent, - "opendiscord:reopen":ODHelpMenuCommandComponent + "opendiscord:close":api.ODHelpMenuCommandComponent, + "opendiscord:delete":api.ODHelpMenuCommandComponent, + "opendiscord:reopen":api.ODHelpMenuCommandComponent } /**## ODHelpMenuCategory_DefaultTicketBasic `default_class` @@ -111,25 +110,25 @@ export interface ODHelpMenuManagerCategoryIds_DefaultTicketBasic { * * This default class is made for the `opendiscord:ticket` category in `opendiscord.helpmenu`! */ -export class ODHelpMenuCategory_DefaultTicketBasic extends ODHelpMenuCategory { +export class ODHelpMenuCategory_DefaultTicketBasic extends api.ODHelpMenuCategory { get(id:HelpMenuCategoryId): ODHelpMenuManagerCategoryIds_DefaultTicketBasic[HelpMenuCategoryId] - get(id:ODValidId): ODHelpMenuComponent|null + get(id:api.ODValidId): api.ODHelpMenuComponent|null - get(id:ODValidId): ODHelpMenuComponent|null { + get(id:api.ODValidId): api.ODHelpMenuComponent|null { return super.get(id) } remove(id:HelpMenuCategoryId): ODHelpMenuManagerCategoryIds_DefaultTicketBasic[HelpMenuCategoryId] - remove(id:ODValidId): ODHelpMenuComponent|null + remove(id:api.ODValidId): api.ODHelpMenuComponent|null - remove(id:ODValidId): ODHelpMenuComponent|null { + remove(id:api.ODValidId): api.ODHelpMenuComponent|null { return super.remove(id) } exists(id:keyof ODHelpMenuManagerCategoryIds_DefaultTicketBasic): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -139,10 +138,10 @@ export class ODHelpMenuCategory_DefaultTicketBasic extends ODHelpMenuCategory { * It's used to generate typescript declarations for this class. */ export interface ODHelpMenuManagerCategoryIds_DefaultTicketAdvanced { - "opendiscord:pin":ODHelpMenuCommandComponent, - "opendiscord:unpin":ODHelpMenuCommandComponent, - "opendiscord:move":ODHelpMenuCommandComponent, - "opendiscord:rename":ODHelpMenuCommandComponent + "opendiscord:pin":api.ODHelpMenuCommandComponent, + "opendiscord:unpin":api.ODHelpMenuCommandComponent, + "opendiscord:move":api.ODHelpMenuCommandComponent, + "opendiscord:rename":api.ODHelpMenuCommandComponent } /**## ODHelpMenuCategory_DefaultTicketAdvanced `default_class` @@ -151,25 +150,25 @@ export interface ODHelpMenuManagerCategoryIds_DefaultTicketAdvanced { * * This default class is made for the `opendiscord:ticket` category in `opendiscord.helpmenu`! */ -export class ODHelpMenuCategory_DefaultTicketAdvanced extends ODHelpMenuCategory { +export class ODHelpMenuCategory_DefaultTicketAdvanced extends api.ODHelpMenuCategory { get(id:HelpMenuCategoryId): ODHelpMenuManagerCategoryIds_DefaultTicketAdvanced[HelpMenuCategoryId] - get(id:ODValidId): ODHelpMenuComponent|null + get(id:api.ODValidId): api.ODHelpMenuComponent|null - get(id:ODValidId): ODHelpMenuComponent|null { + get(id:api.ODValidId): api.ODHelpMenuComponent|null { return super.get(id) } remove(id:HelpMenuCategoryId): ODHelpMenuManagerCategoryIds_DefaultTicketAdvanced[HelpMenuCategoryId] - remove(id:ODValidId): ODHelpMenuComponent|null + remove(id:api.ODValidId): api.ODHelpMenuComponent|null - remove(id:ODValidId): ODHelpMenuComponent|null { + remove(id:api.ODValidId): api.ODHelpMenuComponent|null { return super.remove(id) } exists(id:keyof ODHelpMenuManagerCategoryIds_DefaultTicketAdvanced): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -179,11 +178,11 @@ export class ODHelpMenuCategory_DefaultTicketAdvanced extends ODHelpMenuCategory * It's used to generate typescript declarations for this class. */ export interface ODHelpMenuManagerCategoryIds_DefaultTicketUser { - "opendiscord:claim":ODHelpMenuCommandComponent, - "opendiscord:unclaim":ODHelpMenuCommandComponent, - "opendiscord:add":ODHelpMenuCommandComponent, - "opendiscord:remove":ODHelpMenuCommandComponent, - "opendiscord:transfer":ODHelpMenuCommandComponent, + "opendiscord:claim":api.ODHelpMenuCommandComponent, + "opendiscord:unclaim":api.ODHelpMenuCommandComponent, + "opendiscord:add":api.ODHelpMenuCommandComponent, + "opendiscord:remove":api.ODHelpMenuCommandComponent, + "opendiscord:transfer":api.ODHelpMenuCommandComponent, } /**## ODHelpMenuCategory_DefaultTicketUser `default_class` @@ -192,25 +191,25 @@ export interface ODHelpMenuManagerCategoryIds_DefaultTicketUser { * * This default class is made for the `opendiscord:ticket` category in `opendiscord.helpmenu`! */ -export class ODHelpMenuCategory_DefaultTicketUser extends ODHelpMenuCategory { +export class ODHelpMenuCategory_DefaultTicketUser extends api.ODHelpMenuCategory { get(id:HelpMenuCategoryId): ODHelpMenuManagerCategoryIds_DefaultTicketUser[HelpMenuCategoryId] - get(id:ODValidId): ODHelpMenuComponent|null + get(id:api.ODValidId): api.ODHelpMenuComponent|null - get(id:ODValidId): ODHelpMenuComponent|null { + get(id:api.ODValidId): api.ODHelpMenuComponent|null { return super.get(id) } remove(id:HelpMenuCategoryId): ODHelpMenuManagerCategoryIds_DefaultTicketUser[HelpMenuCategoryId] - remove(id:ODValidId): ODHelpMenuComponent|null + remove(id:api.ODValidId): api.ODHelpMenuComponent|null - remove(id:ODValidId): ODHelpMenuComponent|null { + remove(id:api.ODValidId): api.ODHelpMenuComponent|null { return super.remove(id) } exists(id:keyof ODHelpMenuManagerCategoryIds_DefaultTicketUser): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -220,11 +219,11 @@ export class ODHelpMenuCategory_DefaultTicketUser extends ODHelpMenuCategory { * It's used to generate typescript declarations for this class. */ export interface ODHelpMenuManagerCategoryIds_DefaultAdmin { - "opendiscord:panel":ODHelpMenuCommandComponent, - "opendiscord:blacklist-view":ODHelpMenuCommandComponent, - "opendiscord:blacklist-add":ODHelpMenuCommandComponent, - "opendiscord:blacklist-remove":ODHelpMenuCommandComponent, - "opendiscord:blacklist-get":ODHelpMenuCommandComponent + "opendiscord:panel":api.ODHelpMenuCommandComponent, + "opendiscord:blacklist-view":api.ODHelpMenuCommandComponent, + "opendiscord:blacklist-add":api.ODHelpMenuCommandComponent, + "opendiscord:blacklist-remove":api.ODHelpMenuCommandComponent, + "opendiscord:blacklist-get":api.ODHelpMenuCommandComponent } /**## ODHelpMenuCategory_DefaultAdmin `default_class` @@ -233,25 +232,25 @@ export interface ODHelpMenuManagerCategoryIds_DefaultAdmin { * * This default class is made for the `opendiscord:admin` category in `opendiscord.helpmenu`! */ -export class ODHelpMenuCategory_DefaultAdmin extends ODHelpMenuCategory { +export class ODHelpMenuCategory_DefaultAdmin extends api.ODHelpMenuCategory { get(id:HelpMenuCategoryId): ODHelpMenuManagerCategoryIds_DefaultAdmin[HelpMenuCategoryId] - get(id:ODValidId): ODHelpMenuComponent|null + get(id:api.ODValidId): api.ODHelpMenuComponent|null - get(id:ODValidId): ODHelpMenuComponent|null { + get(id:api.ODValidId): api.ODHelpMenuComponent|null { return super.get(id) } remove(id:HelpMenuCategoryId): ODHelpMenuManagerCategoryIds_DefaultAdmin[HelpMenuCategoryId] - remove(id:ODValidId): ODHelpMenuComponent|null + remove(id:api.ODValidId): api.ODHelpMenuComponent|null - remove(id:ODValidId): ODHelpMenuComponent|null { + remove(id:api.ODValidId): api.ODHelpMenuComponent|null { return super.remove(id) } exists(id:keyof ODHelpMenuManagerCategoryIds_DefaultAdmin): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -261,16 +260,16 @@ export class ODHelpMenuCategory_DefaultAdmin extends ODHelpMenuCategory { * It's used to generate typescript declarations for this class. */ export interface ODHelpMenuManagerCategoryIds_DefaultAdvanced { - "opendiscord:stats-global":ODHelpMenuCommandComponent, - "opendiscord:stats-reset":ODHelpMenuCommandComponent, - "opendiscord:stats-ticket":ODHelpMenuCommandComponent, - "opendiscord:stats-user":ODHelpMenuCommandComponent, - "opendiscord:autoclose-disable":ODHelpMenuCommandComponent, - "opendiscord:autoclose-enable":ODHelpMenuCommandComponent, - "opendiscord:autodelete-disable":ODHelpMenuCommandComponent, - "opendiscord:autodelete-enable":ODHelpMenuCommandComponent, - "opendiscord:topic-set":ODHelpMenuCommandComponent, - "opendiscord:priority-set":ODHelpMenuCommandComponent, + "opendiscord:stats-global":api.ODHelpMenuCommandComponent, + "opendiscord:stats-reset":api.ODHelpMenuCommandComponent, + "opendiscord:stats-ticket":api.ODHelpMenuCommandComponent, + "opendiscord:stats-user":api.ODHelpMenuCommandComponent, + "opendiscord:autoclose-disable":api.ODHelpMenuCommandComponent, + "opendiscord:autoclose-enable":api.ODHelpMenuCommandComponent, + "opendiscord:autodelete-disable":api.ODHelpMenuCommandComponent, + "opendiscord:autodelete-enable":api.ODHelpMenuCommandComponent, + "opendiscord:topic-set":api.ODHelpMenuCommandComponent, + "opendiscord:priority-set":api.ODHelpMenuCommandComponent, } /**## ODHelpMenuCategory_DefaultAdvanced `default_class` @@ -279,25 +278,25 @@ export interface ODHelpMenuManagerCategoryIds_DefaultAdvanced { * * This default class is made for the `opendiscord:advanced` category in `opendiscord.helpmenu`! */ -export class ODHelpMenuCategory_DefaultAdvanced extends ODHelpMenuCategory { +export class ODHelpMenuCategory_DefaultAdvanced extends api.ODHelpMenuCategory { get(id:HelpMenuCategoryId): ODHelpMenuManagerCategoryIds_DefaultAdvanced[HelpMenuCategoryId] - get(id:ODValidId): ODHelpMenuComponent|null + get(id:api.ODValidId): api.ODHelpMenuComponent|null - get(id:ODValidId): ODHelpMenuComponent|null { + get(id:api.ODValidId): api.ODHelpMenuComponent|null { return super.get(id) } remove(id:HelpMenuCategoryId): ODHelpMenuManagerCategoryIds_DefaultAdvanced[HelpMenuCategoryId] - remove(id:ODValidId): ODHelpMenuComponent|null + remove(id:api.ODValidId): api.ODHelpMenuComponent|null - remove(id:ODValidId): ODHelpMenuComponent|null { + remove(id:api.ODValidId): api.ODHelpMenuComponent|null { return super.remove(id) } exists(id:keyof ODHelpMenuManagerCategoryIds_DefaultAdvanced): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -314,25 +313,25 @@ export interface ODHelpMenuManagerCategoryIds_DefaultExtra {} * * This default class is made for the `opendiscord:general` category in `opendiscord.helpmenu`! */ -export class ODHelpMenuCategory_DefaultExtra extends ODHelpMenuCategory { +export class ODHelpMenuCategory_DefaultExtra extends api.ODHelpMenuCategory { get(id:HelpMenuCategoryId): ODHelpMenuManagerCategoryIds_DefaultExtra[HelpMenuCategoryId] - get(id:ODValidId): ODHelpMenuComponent|null + get(id:api.ODValidId): api.ODHelpMenuComponent|null - get(id:ODValidId): ODHelpMenuComponent|null { + get(id:api.ODValidId): api.ODHelpMenuComponent|null { return super.get(id) } remove(id:HelpMenuCategoryId): ODHelpMenuManagerCategoryIds_DefaultExtra[HelpMenuCategoryId] - remove(id:ODValidId): ODHelpMenuComponent|null + remove(id:api.ODValidId): api.ODHelpMenuComponent|null - remove(id:ODValidId): ODHelpMenuComponent|null { + remove(id:api.ODValidId): api.ODHelpMenuComponent|null { return super.remove(id) } exists(id:keyof ODHelpMenuManagerCategoryIds_DefaultExtra): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } \ No newline at end of file diff --git a/src/core/api/defaults/language.ts b/src/core/api/defaults/language.ts index 64270e2..649cebf 100644 --- a/src/core/api/defaults/language.ts +++ b/src/core/api/defaults/language.ts @@ -1,8 +1,7 @@ /////////////////////////////////////// //DEFAULT LANGUAGE MODULE /////////////////////////////////////// -import { ODValidId } from "../modules/base" -import { ODLanguageManager, ODLanguage } from "../modules/language" +import * as api from "@open-discord-bots/framework/api" /** (CONTRIBUTOR GUIDE) HOW TO ADD NEW LANGUAGES? * - Add the file to (./languages/) and make sure the metadata is valid. @@ -18,43 +17,43 @@ import { ODLanguageManager, ODLanguage } from "../modules/language" * It's used to generate typescript declarations for this class. */ export interface ODLanguageManagerIds_Default { - "opendiscord:custom":ODLanguage, - "opendiscord:english":ODLanguage, - "opendiscord:dutch":ODLanguage, - "opendiscord:portuguese":ODLanguage, - "opendiscord:czech":ODLanguage, - "opendiscord:german":ODLanguage, - "opendiscord:catalan":ODLanguage, - "opendiscord:hungarian":ODLanguage, - "opendiscord:spanish":ODLanguage, - "opendiscord:romanian":ODLanguage, - "opendiscord:ukrainian":ODLanguage, - "opendiscord:indonesian":ODLanguage, - "opendiscord:italian":ODLanguage, - "opendiscord:estonian":ODLanguage, - "opendiscord:finnish":ODLanguage, - "opendiscord:danish":ODLanguage, - "opendiscord:thai":ODLanguage, - "opendiscord:turkish":ODLanguage, - "opendiscord:french":ODLanguage, - "opendiscord:arabic":ODLanguage, - "opendiscord:hindi":ODLanguage, - "opendiscord:lithuanian":ODLanguage, - "opendiscord:polish":ODLanguage, - "opendiscord:latvian":ODLanguage, - "opendiscord:norwegian":ODLanguage, - "opendiscord:russian":ODLanguage, - "opendiscord:swedish":ODLanguage, - "opendiscord:vietnamese":ODLanguage, - "opendiscord:persian":ODLanguage, - "opendiscord:bengali":ODLanguage, - "opendiscord:greek":ODLanguage, - "opendiscord:japanese":ODLanguage, - "opendiscord:korean":ODLanguage, - "opendiscord:kurdish":ODLanguage, - "opendiscord:simplified-chinese":ODLanguage, - "opendiscord:slovenian":ODLanguage, - "opendiscord:tamil":ODLanguage, + "opendiscord:custom":api.ODLanguage, + "opendiscord:english":api.ODLanguage, + "opendiscord:dutch":api.ODLanguage, + "opendiscord:portuguese":api.ODLanguage, + "opendiscord:czech":api.ODLanguage, + "opendiscord:german":api.ODLanguage, + "opendiscord:catalan":api.ODLanguage, + "opendiscord:hungarian":api.ODLanguage, + "opendiscord:spanish":api.ODLanguage, + "opendiscord:romanian":api.ODLanguage, + "opendiscord:ukrainian":api.ODLanguage, + "opendiscord:indonesian":api.ODLanguage, + "opendiscord:italian":api.ODLanguage, + "opendiscord:estonian":api.ODLanguage, + "opendiscord:finnish":api.ODLanguage, + "opendiscord:danish":api.ODLanguage, + "opendiscord:thai":api.ODLanguage, + "opendiscord:turkish":api.ODLanguage, + "opendiscord:french":api.ODLanguage, + "opendiscord:arabic":api.ODLanguage, + "opendiscord:hindi":api.ODLanguage, + "opendiscord:lithuanian":api.ODLanguage, + "opendiscord:polish":api.ODLanguage, + "opendiscord:latvian":api.ODLanguage, + "opendiscord:norwegian":api.ODLanguage, + "opendiscord:russian":api.ODLanguage, + "opendiscord:swedish":api.ODLanguage, + "opendiscord:vietnamese":api.ODLanguage, + "opendiscord:persian":api.ODLanguage, + "opendiscord:bengali":api.ODLanguage, + "opendiscord:greek":api.ODLanguage, + "opendiscord:japanese":api.ODLanguage, + "opendiscord:korean":api.ODLanguage, + "opendiscord:kurdish":api.ODLanguage, + "opendiscord:simplified-chinese":api.ODLanguage, + "opendiscord:slovenian":api.ODLanguage, + "opendiscord:tamil":api.ODLanguage, //ADD NEW LANGUAGES HERE!!! } @@ -628,25 +627,25 @@ export type ODLanguageManagerTranslations_Default = ( * * This default class is made for the global variable `opendiscord.languages`! */ -export class ODLanguageManager_Default extends ODLanguageManager { +export class ODLanguageManager_Default extends api.ODLanguageManager { get(id:LanguageId): ODLanguageManagerIds_Default[LanguageId] - get(id:ODValidId): ODLanguage|null + get(id:api.ODValidId): api.ODLanguage|null - get(id:ODValidId): ODLanguage|null { + get(id:api.ODValidId): api.ODLanguage|null { return super.get(id) } remove(id:LanguageId): ODLanguageManagerIds_Default[LanguageId] - remove(id:ODValidId): ODLanguage|null + remove(id:api.ODValidId): api.ODLanguage|null - remove(id:ODValidId): ODLanguage|null { + remove(id:api.ODValidId): api.ODLanguage|null { return super.remove(id) } exists(id:keyof ODLanguageManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } @@ -658,16 +657,16 @@ export class ODLanguageManager_Default extends ODLanguageManager { } setCurrentLanguage(id:keyof ODLanguageManagerIds_Default): void - setCurrentLanguage(id:ODValidId): void + setCurrentLanguage(id:api.ODValidId): void - setCurrentLanguage(id:ODValidId): void { + setCurrentLanguage(id:api.ODValidId): void { return super.setCurrentLanguage(id) } setBackupLanguage(id:keyof ODLanguageManagerIds_Default): void - setBackupLanguage(id:ODValidId): void + setBackupLanguage(id:api.ODValidId): void - setBackupLanguage(id:ODValidId): void { + setBackupLanguage(id:api.ODValidId): void { return super.setBackupLanguage(id) } diff --git a/src/core/api/defaults/permission.ts b/src/core/api/defaults/permission.ts index 2a67d3e..119d407 100644 --- a/src/core/api/defaults/permission.ts +++ b/src/core/api/defaults/permission.ts @@ -1,8 +1,7 @@ /////////////////////////////////////// //DEFAULT PERMISSION MODULE /////////////////////////////////////// -import { ODDebugger } from "../modules/console" -import { ODPermissionManager } from "../modules/permission" +import * as api from "@open-discord-bots/framework/api" import { ODClientManager_Default } from "./client" /**## ODPermissionManager_Default `default_class` @@ -11,8 +10,8 @@ import { ODClientManager_Default } from "./client" * * This default class is made for the global variable `opendiscord.permissions`! */ -export class ODPermissionManager_Default extends ODPermissionManager { - constructor(debug:ODDebugger,client:ODClientManager_Default){ +export class ODPermissionManager_Default extends api.ODPermissionManager { + constructor(debug:api.ODDebugger,client:ODClientManager_Default){ super(debug,client,true) } } diff --git a/src/core/api/defaults/plugin.ts b/src/core/api/defaults/plugin.ts index b9644b4..03df1ec 100644 --- a/src/core/api/defaults/plugin.ts +++ b/src/core/api/defaults/plugin.ts @@ -1,8 +1,7 @@ /////////////////////////////////////// //DEFAULT POST MODULE /////////////////////////////////////// -import { ODValidId, ODManagerData } from "../modules/base" -import { ODPlugin, ODPluginClassManager, ODPluginManager } from "../modules/plugin" +import * as api from "@open-discord-bots/framework/api" /**## ODPluginManagerIds_Default `interface` * This interface is a list of ids available in the `ODPluginManager_Default` class. @@ -16,27 +15,27 @@ export interface ODPluginManagerIds_Default {} * * This default class is made for the global variable `opendiscord.plugins`! */ -export class ODPluginManager_Default extends ODPluginManager { +export class ODPluginManager_Default extends api.ODPluginManager { declare classes: ODPluginClassManager_Default get(id:PluginId): ODPluginManagerIds_Default[PluginId] - get(id:ODValidId): ODPlugin|null + get(id:api.ODValidId): api.ODPlugin|null - get(id:ODValidId): ODPlugin|null { + get(id:api.ODValidId): api.ODPlugin|null { return super.get(id) } remove(id:PluginId): ODPluginManagerIds_Default[PluginId] - remove(id:ODValidId): ODPlugin|null + remove(id:api.ODValidId): api.ODPlugin|null - remove(id:ODValidId): ODPlugin|null { + remove(id:api.ODValidId): api.ODPlugin|null { return super.remove(id) } exists(id:keyof ODPluginManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -53,25 +52,25 @@ export interface ODPluginClassManagerIds_Default {} * * This default class is made for the global variable `opendiscord.plugins.classes`! */ -export class ODPluginClassManager_Default extends ODPluginClassManager { +export class ODPluginClassManager_Default extends api.ODPluginClassManager { get(id:PluginClassId): ODPluginClassManagerIds_Default[PluginClassId] - get(id:ODValidId): ODManagerData|null + get(id:api.ODValidId): api.ODManagerData|null - get(id:ODValidId): ODManagerData|null { + get(id:api.ODValidId): api.ODManagerData|null { return super.get(id) } remove(id:PluginClassId): ODPluginClassManagerIds_Default[PluginClassId] - remove(id:ODValidId): ODManagerData|null + remove(id:api.ODValidId): api.ODManagerData|null - remove(id:ODValidId): ODManagerData|null { + remove(id:api.ODValidId): api.ODManagerData|null { return super.remove(id) } exists(id:keyof ODPluginClassManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } \ No newline at end of file diff --git a/src/core/api/defaults/post.ts b/src/core/api/defaults/post.ts index bdc64db..c0e4ab3 100644 --- a/src/core/api/defaults/post.ts +++ b/src/core/api/defaults/post.ts @@ -1,8 +1,7 @@ /////////////////////////////////////// //DEFAULT POST MODULE /////////////////////////////////////// -import { ODValidId } from "../modules/base" -import { ODPost, ODPostManager } from "../modules/post" +import * as api from "@open-discord-bots/framework/api" import * as discord from "discord.js" /**## ODPostManagerIds_Default `interface` @@ -10,8 +9,8 @@ import * as discord from "discord.js" * It's used to generate typescript declarations for this class. */ export interface ODPostManagerIds_Default { - "opendiscord:logs":ODPost|null, - "opendiscord:transcripts":ODPost|null + "opendiscord:logs":api.ODPost|null, + "opendiscord:transcripts":api.ODPost|null } /**## ODPostManager_Default `default_class` @@ -20,25 +19,25 @@ export interface ODPostManagerIds_Default { * * This default class is made for the global variable `opendiscord.code`! */ -export class ODPostManager_Default extends ODPostManager { +export class ODPostManager_Default extends api.ODPostManager { get(id:PostId): ODPostManagerIds_Default[PostId] - get(id:ODValidId): ODPost|null + get(id:api.ODValidId): api.ODPost|null - get(id:ODValidId): ODPost|null { + get(id:api.ODValidId): api.ODPost|null { return super.get(id) } remove(id:PostId): ODPostManagerIds_Default[PostId] - remove(id:ODValidId): ODPost|null + remove(id:api.ODValidId): api.ODPost|null - remove(id:ODValidId): ODPost|null { + remove(id:api.ODValidId): api.ODPost|null { return super.remove(id) } exists(id:keyof ODPostManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } \ No newline at end of file diff --git a/src/core/api/defaults/progressbar.ts b/src/core/api/defaults/progressbar.ts index f353472..2963b0d 100644 --- a/src/core/api/defaults/progressbar.ts +++ b/src/core/api/defaults/progressbar.ts @@ -1,9 +1,7 @@ /////////////////////////////////////// //DEFAULT PROGRESS BAR MODULE /////////////////////////////////////// -import { ODValidId } from "../modules/base" -import { ODValidConsoleColor } from "../modules/console" -import { ODManualProgressBar, ODProgressBar, ODProgressBarManager, ODProgressBarRenderer, ODProgressBarRendererManager } from "../modules/progressbar" +import * as api from "@open-discord-bots/framework/api" import ansis from "ansis" /**## ODProgressBarRenderer_DefaultSettingsLabel `type` @@ -16,17 +14,17 @@ export type ODProgressBarRenderer_DefaultSettingsLabel = "value"|"percentage"|"f */ export interface ODProgressBarRenderer_DefaultSettings { /**The color of the progress bar border. */ - borderColor:ODValidConsoleColor|"openticket", + borderColor:api.ODValidConsoleColor|"openticket", /**The color of the progress bar (filled side). */ - filledBarColor:ODValidConsoleColor|"openticket", + filledBarColor:api.ODValidConsoleColor|"openticket", /**The color of the progress bar (empty side). */ - emptyBarColor:ODValidConsoleColor|"openticket", + emptyBarColor:api.ODValidConsoleColor|"openticket", /**The color of the text before the progress bar. */ - prefixColor:ODValidConsoleColor|"openticket", + prefixColor:api.ODValidConsoleColor|"openticket", /**The color of the text after the progress bar. */ - suffixColor:ODValidConsoleColor|"openticket", + suffixColor:api.ODValidConsoleColor|"openticket", /**The color of the progress bar label. */ - labelColor:ODValidConsoleColor|"openticket", + labelColor:api.ODValidConsoleColor|"openticket", /**The character used in the left border. */ leftBorderChar:string, @@ -51,8 +49,8 @@ export interface ODProgressBarRenderer_DefaultSettings { showBorder:boolean, } -export class ODProgressBarRenderer_Default extends ODProgressBarRenderer { - constructor(id:ODValidId,settings:ODProgressBarRenderer_DefaultSettings){ +export class ODProgressBarRenderer_Default extends api.ODProgressBarRenderer { + constructor(id:api.ODValidId,settings:ODProgressBarRenderer_DefaultSettings){ super(id,(settings,min,max,value,rawPrefix,rawSuffix) => { const percentage = (value-min)/(max-min) const barLevel = Math.round(percentage*settings.barWidth) @@ -103,25 +101,25 @@ export interface ODProgressBarRendererManagerIds_Default { * * This default class is made for the global variable `opendiscord.progressbars.renderers`! */ -export class ODProgressBarRendererManager_Default extends ODProgressBarRendererManager { +export class ODProgressBarRendererManager_Default extends api.ODProgressBarRendererManager { get(id:ProgressBarId): ODProgressBarRendererManagerIds_Default[ProgressBarId] - get(id:ODValidId): ODProgressBarRenderer<{}>|null + get(id:api.ODValidId): api.ODProgressBarRenderer<{}>|null - get(id:ODValidId): ODProgressBarRenderer<{}>|null { + get(id:api.ODValidId): api.ODProgressBarRenderer<{}>|null { return super.get(id) } remove(id:ProgressBarId): ODProgressBarRendererManagerIds_Default[ProgressBarId] - remove(id:ODValidId): ODProgressBarRenderer<{}>|null + remove(id:api.ODValidId): api.ODProgressBarRenderer<{}>|null - remove(id:ODValidId): ODProgressBarRenderer<{}>|null { + remove(id:api.ODValidId): api.ODProgressBarRenderer<{}>|null { return super.remove(id) } exists(id:keyof ODProgressBarRendererManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -131,12 +129,12 @@ export class ODProgressBarRendererManager_Default extends ODProgressBarRendererM * It's used to generate typescript declarations for this class. */ export interface ODProgressBarManagerIds_Default { - "opendiscord:slash-command-remove":ODManualProgressBar, - "opendiscord:slash-command-create":ODManualProgressBar, - "opendiscord:slash-command-update":ODManualProgressBar, - "opendiscord:context-menu-remove":ODManualProgressBar, - "opendiscord:context-menu-create":ODManualProgressBar, - "opendiscord:context-menu-update":ODManualProgressBar, + "opendiscord:slash-command-remove":api.ODManualProgressBar, + "opendiscord:slash-command-create":api.ODManualProgressBar, + "opendiscord:slash-command-update":api.ODManualProgressBar, + "opendiscord:context-menu-remove":api.ODManualProgressBar, + "opendiscord:context-menu-create":api.ODManualProgressBar, + "opendiscord:context-menu-update":api.ODManualProgressBar, } /**## ODProgressBarManager_Default `default_class` @@ -145,27 +143,27 @@ export interface ODProgressBarManagerIds_Default { * * This default class is made for the global variable `opendiscord.progressbars`! */ -export class ODProgressBarManager_Default extends ODProgressBarManager { +export class ODProgressBarManager_Default extends api.ODProgressBarManager { declare renderers: ODProgressBarRendererManager_Default get(id:ProgressBarId): ODProgressBarManagerIds_Default[ProgressBarId] - get(id:ODValidId): ODProgressBar|null + get(id:api.ODValidId): api.ODProgressBar|null - get(id:ODValidId): ODProgressBar|null { + get(id:api.ODValidId): api.ODProgressBar|null { return super.get(id) } remove(id:ProgressBarId): ODProgressBarManagerIds_Default[ProgressBarId] - remove(id:ODValidId): ODProgressBar|null + remove(id:api.ODValidId): api.ODProgressBar|null - remove(id:ODValidId): ODProgressBar|null { + remove(id:api.ODValidId): api.ODProgressBar|null { return super.remove(id) } exists(id:keyof ODProgressBarManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } \ No newline at end of file diff --git a/src/core/api/defaults/responder.ts b/src/core/api/defaults/responder.ts index 8d7b317..c7db244 100644 --- a/src/core/api/defaults/responder.ts +++ b/src/core/api/defaults/responder.ts @@ -1,8 +1,7 @@ /////////////////////////////////////// //DEFAULT RESPONDER MODULE /////////////////////////////////////// -import { ODValidId } from "../modules/base" -import { ODAutocompleteResponder, ODAutocompleteResponderInstance, ODAutocompleteResponderManager, ODButtonResponder, ODButtonResponderInstance, ODButtonResponderManager, ODCommandResponder, ODCommandResponderInstance, ODCommandResponderManager, ODContextMenuResponder, ODContextMenuResponderInstance, ODContextMenuResponderManager, ODDropdownResponder, ODDropdownResponderInstance, ODDropdownResponderManager, ODModalResponder, ODModalResponderInstance, ODModalResponderManager, ODResponderManager } from "../modules/responder" +import * as api from "@open-discord-bots/framework/api" import { ODWorkerManager_Default } from "./worker" /**## ODResponderManager_Default `default_class` @@ -11,7 +10,7 @@ import { ODWorkerManager_Default } from "./worker" * * This default class is made for the global variable `opendiscord.responders`! */ -export class ODResponderManager_Default extends ODResponderManager { +export class ODResponderManager_Default extends api.ODResponderManager { declare commands: ODCommandResponderManager_Default declare buttons: ODButtonResponderManager_Default declare dropdowns: ODDropdownResponderManager_Default @@ -58,25 +57,25 @@ export interface ODCommandResponderManagerIds_Default { * * This default class is made for the global variable `opendiscord.responders.commands`! */ -export class ODCommandResponderManager_Default extends ODCommandResponderManager { +export class ODCommandResponderManager_Default extends api.ODCommandResponderManager { get(id:CommandResponderId): ODCommandResponder_Default - get(id:ODValidId): ODCommandResponder<"slash"|"text",any>|null + get(id:api.ODValidId): api.ODCommandResponder<"slash"|"text",any>|null - get(id:ODValidId): ODCommandResponder<"slash"|"text",any>|null { + get(id:api.ODValidId): api.ODCommandResponder<"slash"|"text",any>|null { return super.get(id) } remove(id:CommandResponderId): ODCommandResponder_Default - remove(id:ODValidId): ODCommandResponder<"slash"|"text",any>|null + remove(id:api.ODValidId): api.ODCommandResponder<"slash"|"text",any>|null - remove(id:ODValidId): ODCommandResponder<"slash"|"text",any>|null { + remove(id:api.ODValidId): api.ODCommandResponder<"slash"|"text",any>|null { return super.remove(id) } exists(id:keyof ODCommandResponderManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -87,8 +86,8 @@ export class ODCommandResponderManager_Default extends ODCommandResponderManager * * This default class is made for the default `ODCommandResponder`'s! */ -export class ODCommandResponder_Default extends ODCommandResponder { - declare workers: ODWorkerManager_Default +export class ODCommandResponder_Default extends api.ODCommandResponder { + declare workers: ODWorkerManager_Default } /**## ODButtonResponderManagerIds_Default `interface` @@ -125,25 +124,25 @@ export interface ODButtonResponderManagerIds_Default { * * This default class is made for the global variable `opendiscord.responders.buttons`! */ -export class ODButtonResponderManager_Default extends ODButtonResponderManager { +export class ODButtonResponderManager_Default extends api.ODButtonResponderManager { get(id:ButtonResponderId): ODButtonResponder_Default - get(id:ODValidId): ODButtonResponder<"button",any>|null + get(id:api.ODValidId): api.ODButtonResponder<"button",any>|null - get(id:ODValidId): ODButtonResponder<"button",any>|null { + get(id:api.ODValidId): api.ODButtonResponder<"button",any>|null { return super.get(id) } remove(id:ButtonResponderId): ODButtonResponder_Default - remove(id:ODValidId): ODButtonResponder<"button",any>|null + remove(id:api.ODValidId): api.ODButtonResponder<"button",any>|null - remove(id:ODValidId): ODButtonResponder<"button",any>|null { + remove(id:api.ODValidId): api.ODButtonResponder<"button",any>|null { return super.remove(id) } exists(id:keyof ODButtonResponderManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -154,8 +153,8 @@ export class ODButtonResponderManager_Default extends ODButtonResponderManager { * * This default class is made for the default `ODButtonResponder`'s! */ -export class ODButtonResponder_Default extends ODButtonResponder { - declare workers: ODWorkerManager_Default +export class ODButtonResponder_Default extends api.ODButtonResponder { + declare workers: ODWorkerManager_Default } /**## ODDropdownResponderManagerIds_Default `interface` @@ -172,25 +171,25 @@ export interface ODDropdownResponderManagerIds_Default { * * This default class is made for the global variable `opendiscord.responders.dropdowns`! */ -export class ODDropdownResponderManager_Default extends ODDropdownResponderManager { +export class ODDropdownResponderManager_Default extends api.ODDropdownResponderManager { get(id:DropdownResponderId): ODDropdownResponder_Default - get(id:ODValidId): ODDropdownResponder<"dropdown",any>|null + get(id:api.ODValidId): api.ODDropdownResponder<"dropdown",any>|null - get(id:ODValidId): ODDropdownResponder<"dropdown",any>|null { + get(id:api.ODValidId): api.ODDropdownResponder<"dropdown",any>|null { return super.get(id) } remove(id:DropdownResponderId): ODDropdownResponder_Default - remove(id:ODValidId): ODDropdownResponder<"dropdown",any>|null + remove(id:api.ODValidId): api.ODDropdownResponder<"dropdown",any>|null - remove(id:ODValidId): ODDropdownResponder<"dropdown",any>|null { + remove(id:api.ODValidId): api.ODDropdownResponder<"dropdown",any>|null { return super.remove(id) } exists(id:keyof ODDropdownResponderManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -201,8 +200,8 @@ export class ODDropdownResponderManager_Default extends ODDropdownResponderManag * * This default class is made for the default `ODDropdownResponder`'s! */ -export class ODDropdownResponder_Default extends ODDropdownResponder { - declare workers: ODWorkerManager_Default +export class ODDropdownResponder_Default extends api.ODDropdownResponder { + declare workers: ODWorkerManager_Default } /**## ODModalResponderManagerIds_Default `interface` @@ -226,25 +225,25 @@ export interface ODModalResponderManagerIds_Default { * * This default class is made for the global variable `opendiscord.responders.dropdowns`! */ -export class ODModalResponderManager_Default extends ODModalResponderManager { +export class ODModalResponderManager_Default extends api.ODModalResponderManager { get(id:ModalResponderId): ODModalResponder_Default - get(id:ODValidId): ODModalResponder<"modal",any>|null + get(id:api.ODValidId): api.ODModalResponder<"modal",any>|null - get(id:ODValidId): ODModalResponder<"modal",any>|null { + get(id:api.ODValidId): api.ODModalResponder<"modal",any>|null { return super.get(id) } remove(id:ModalResponderId): ODModalResponder_Default - remove(id:ODValidId): ODModalResponder<"modal",any>|null + remove(id:api.ODValidId): api.ODModalResponder<"modal",any>|null - remove(id:ODValidId): ODModalResponder<"modal",any>|null { + remove(id:api.ODValidId): api.ODModalResponder<"modal",any>|null { return super.remove(id) } exists(id:keyof ODModalResponderManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -255,8 +254,8 @@ export class ODModalResponderManager_Default extends ODModalResponderManager { * * This default class is made for the default `ODModalResponder`'s! */ -export class ODModalResponder_Default extends ODModalResponder { - declare workers: ODWorkerManager_Default +export class ODModalResponder_Default extends api.ODModalResponder { + declare workers: ODWorkerManager_Default } /**## ODContextMenuResponderManagerIds_Default `interface` @@ -273,25 +272,25 @@ export interface ODContextMenuResponderManagerIds_Default { * * This default class is made for the global variable `opendiscord.responders.contextMenus`! */ -export class ODContextMenuResponderManager_Default extends ODContextMenuResponderManager { +export class ODContextMenuResponderManager_Default extends api.ODContextMenuResponderManager { get(id:ModalResponderId): ODContextMenuResponder_Default - get(id:ODValidId): ODContextMenuResponder<"context-menu",any>|null + get(id:api.ODValidId): api.ODContextMenuResponder<"context-menu",any>|null - get(id:ODValidId): ODContextMenuResponder<"context-menu",any>|null { + get(id:api.ODValidId): api.ODContextMenuResponder<"context-menu",any>|null { return super.get(id) } remove(id:ModalResponderId): ODContextMenuResponder_Default - remove(id:ODValidId): ODContextMenuResponder<"context-menu",any>|null + remove(id:api.ODValidId): api.ODContextMenuResponder<"context-menu",any>|null - remove(id:ODValidId): ODContextMenuResponder<"context-menu",any>|null { + remove(id:api.ODValidId): api.ODContextMenuResponder<"context-menu",any>|null { return super.remove(id) } exists(id:keyof ODContextMenuResponderManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -302,8 +301,8 @@ export class ODContextMenuResponderManager_Default extends ODContextMenuResponde * * This default class is made for the default `ODContextMenuResponder`'s! */ -export class ODContextMenuResponder_Default extends ODContextMenuResponder { - declare workers: ODWorkerManager_Default +export class ODContextMenuResponder_Default extends api.ODContextMenuResponder { + declare workers: ODWorkerManager_Default } /**## ODAutocompleteResponderManagerIds_Default `interface` @@ -321,25 +320,25 @@ export interface ODAutocompleteResponderManagerIds_Default { * * This default class is made for the global variable `opendiscord.responders.autocomplete`! */ -export class ODAutocompleteResponderManager_Default extends ODAutocompleteResponderManager { +export class ODAutocompleteResponderManager_Default extends api.ODAutocompleteResponderManager { get(id:ModalResponderId): ODAutocompleteResponder_Default - get(id:ODValidId): ODAutocompleteResponder<"autocomplete",any>|null + get(id:api.ODValidId): api.ODAutocompleteResponder<"autocomplete",any>|null - get(id:ODValidId): ODAutocompleteResponder<"autocomplete",any>|null { + get(id:api.ODValidId): api.ODAutocompleteResponder<"autocomplete",any>|null { return super.get(id) } remove(id:ModalResponderId): ODAutocompleteResponder_Default - remove(id:ODValidId): ODAutocompleteResponder<"autocomplete",any>|null + remove(id:api.ODValidId): api.ODAutocompleteResponder<"autocomplete",any>|null - remove(id:ODValidId): ODAutocompleteResponder<"autocomplete",any>|null { + remove(id:api.ODValidId): api.ODAutocompleteResponder<"autocomplete",any>|null { return super.remove(id) } exists(id:keyof ODAutocompleteResponderManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -350,6 +349,6 @@ export class ODAutocompleteResponderManager_Default extends ODAutocompleteRespon * * This default class is made for the default `ODAutocompleteResponder`'s! */ -export class ODAutocompleteResponder_Default extends ODAutocompleteResponder { - declare workers: ODWorkerManager_Default +export class ODAutocompleteResponder_Default extends api.ODAutocompleteResponder { + declare workers: ODWorkerManager_Default } \ No newline at end of file diff --git a/src/core/api/defaults/session.ts b/src/core/api/defaults/session.ts index 8eef65b..1c46e56 100644 --- a/src/core/api/defaults/session.ts +++ b/src/core/api/defaults/session.ts @@ -1,8 +1,7 @@ /////////////////////////////////////// //DEFAULT SESSION MODULE /////////////////////////////////////// -import { ODValidId } from "../modules/base" -import { ODSession, ODSessionManager } from "../modules/session" +import * as api from "@open-discord-bots/framework/api" /**## ODSessionManagerIds_Default `interface` * This interface is a list of ids available in the `ODSessionManager_Default` class. @@ -18,25 +17,25 @@ export interface ODSessionManagerIds_Default { * * This default class is made for the global variable `opendiscord.sessions`! */ -export class ODSessionManager_Default extends ODSessionManager { +export class ODSessionManager_Default extends api.ODSessionManager { get(id:SessionId): ODSessionManagerIds_Default[SessionId] - get(id:ODValidId): ODSession|null + get(id:api.ODValidId): api.ODSession|null - get(id:ODValidId): ODSession|null { + get(id:api.ODValidId): api.ODSession|null { return super.get(id) } remove(id:SessionId): ODSessionManagerIds_Default[SessionId] - remove(id:ODValidId): ODSession|null + remove(id:api.ODValidId): api.ODSession|null - remove(id:ODValidId): ODSession|null { + remove(id:api.ODValidId): api.ODSession|null { return super.remove(id) } exists(id:keyof ODSessionManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } \ No newline at end of file diff --git a/src/core/api/defaults/startscreen.ts b/src/core/api/defaults/startscreen.ts index b3da322..19b43d7 100644 --- a/src/core/api/defaults/startscreen.ts +++ b/src/core/api/defaults/startscreen.ts @@ -1,21 +1,20 @@ /////////////////////////////////////// //DEFAULT STARTSCREEN MODULE /////////////////////////////////////// -import { ODValidId } from "../modules/base" -import { ODStartScreenCategoryComponent, ODStartScreenComponent, ODStartScreenFlagsCategoryComponent, ODStartScreenHeaderComponent, ODStartScreenLiveStatusCategoryComponent, ODStartScreenLogoComponent, ODStartScreenManager, ODStartScreenPluginsCategoryComponent, ODStartScreenPropertiesCategoryComponent } from "../modules/startscreen" +import * as api from "@open-discord-bots/framework/api" /**## ODStartScreenManagerIds_Default `interface` * This interface is a list of ids available in the `ODStartScreenManager_Default` class. * It's used to generate typescript declarations for this class. */ export interface ODStartScreenManagerIds_Default { - "opendiscord:logo":ODStartScreenLogoComponent, - "opendiscord:header":ODStartScreenHeaderComponent, - "opendiscord:flags":ODStartScreenFlagsCategoryComponent, - "opendiscord:plugins":ODStartScreenPluginsCategoryComponent, - "opendiscord:stats":ODStartScreenPropertiesCategoryComponent, - "opendiscord:livestatus":ODStartScreenLiveStatusCategoryComponent, - "opendiscord:logs":ODStartScreenCategoryComponent + "opendiscord:logo":api.ODStartScreenLogoComponent, + "opendiscord:header":api.ODStartScreenHeaderComponent, + "opendiscord:flags":api.ODStartScreenFlagsCategoryComponent, + "opendiscord:plugins":api.ODStartScreenPluginsCategoryComponent, + "opendiscord:stats":api.ODStartScreenPropertiesCategoryComponent, + "opendiscord:livestatus":api.ODStartScreenLiveStatusCategoryComponent, + "opendiscord:logs":api.ODStartScreenCategoryComponent } /**## ODStartScreenManager_Default `default_class` @@ -24,25 +23,25 @@ export interface ODStartScreenManagerIds_Default { * * This default class is made for the global variable `opendiscord.startscreen`! */ -export class ODStartScreenManager_Default extends ODStartScreenManager { +export class ODStartScreenManager_Default extends api.ODStartScreenManager { get(id:StartScreenId): ODStartScreenManagerIds_Default[StartScreenId] - get(id:ODValidId): ODStartScreenComponent|null + get(id:api.ODValidId): api.ODStartScreenComponent|null - get(id:ODValidId): ODStartScreenComponent|null { + get(id:api.ODValidId): api.ODStartScreenComponent|null { return super.get(id) } remove(id:StartScreenId): ODStartScreenManagerIds_Default[StartScreenId] - remove(id:ODValidId): ODStartScreenComponent|null + remove(id:api.ODValidId): api.ODStartScreenComponent|null - remove(id:ODValidId): ODStartScreenComponent|null { + remove(id:api.ODValidId): api.ODStartScreenComponent|null { return super.remove(id) } exists(id:keyof ODStartScreenManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } \ No newline at end of file diff --git a/src/core/api/defaults/stat.ts b/src/core/api/defaults/stat.ts index dd8486e..98b918d 100644 --- a/src/core/api/defaults/stat.ts +++ b/src/core/api/defaults/stat.ts @@ -1,8 +1,7 @@ /////////////////////////////////////// //DEFAULT SESSION MODULE /////////////////////////////////////// -import { ODValidId } from "../modules/base" -import { ODStatScope, ODStatGlobalScope, ODStatsManager, ODStat, ODBasicStat, ODDynamicStat, ODValidStatValue, ODStatScopeSetMode } from "../modules/stat" +import * as api from "@open-discord-bots/framework/api" /**## ODStatsManagerIds_Default `interface` * This interface is a list of ids available in the `ODStatsManager_Default` class. @@ -23,25 +22,25 @@ export interface ODStatsManagerIds_Default { * * This default class is made for the global variable `opendiscord.stats`! */ -export class ODStatsManager_Default extends ODStatsManager { +export class ODStatsManager_Default extends api.ODStatsManager { get(id:StatsId): ODStatsManagerIds_Default[StatsId] - get(id:ODValidId): ODStatScope|null + get(id:api.ODValidId): api.ODStatScope|null - get(id:ODValidId): ODStatScope|null { + get(id:api.ODValidId): api.ODStatScope|null { return super.get(id) } remove(id:StatsId): ODStatsManagerIds_Default[StatsId] - remove(id:ODValidId): ODStatScope|null + remove(id:api.ODValidId): api.ODStatScope|null - remove(id:ODValidId): ODStatScope|null { + remove(id:api.ODValidId): api.ODStatScope|null { return super.remove(id) } exists(id:keyof ODStatsManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -51,20 +50,20 @@ export class ODStatsManager_Default extends ODStatsManager { * It's used to generate typescript declarations for this class. */ export interface ODStatGlobalScopeIds_DefaultGlobal { - "opendiscord:tickets-created":ODBasicStat, - "opendiscord:tickets-closed":ODBasicStat, - "opendiscord:tickets-deleted":ODBasicStat, - "opendiscord:tickets-reopened":ODBasicStat, - "opendiscord:tickets-autoclosed":ODBasicStat, - "opendiscord:tickets-autodeleted":ODBasicStat, - "opendiscord:tickets-claimed":ODBasicStat, - "opendiscord:tickets-pinned":ODBasicStat, - "opendiscord:tickets-moved":ODBasicStat, - "opendiscord:tickets-transferred":ODBasicStat, - "opendiscord:users-blacklisted":ODBasicStat, - "opendiscord:transcripts-created":ODBasicStat, - "opendiscord:ticket-volume":ODDynamicStat, - "opendiscord:average-tickets":ODDynamicStat, + "opendiscord:tickets-created":api.ODBasicStat, + "opendiscord:tickets-closed":api.ODBasicStat, + "opendiscord:tickets-deleted":api.ODBasicStat, + "opendiscord:tickets-reopened":api.ODBasicStat, + "opendiscord:tickets-autoclosed":api.ODBasicStat, + "opendiscord:tickets-autodeleted":api.ODBasicStat, + "opendiscord:tickets-claimed":api.ODBasicStat, + "opendiscord:tickets-pinned":api.ODBasicStat, + "opendiscord:tickets-moved":api.ODBasicStat, + "opendiscord:tickets-transferred":api.ODBasicStat, + "opendiscord:users-blacklisted":api.ODBasicStat, + "opendiscord:transcripts-created":api.ODBasicStat, + "opendiscord:ticket-volume":api.ODDynamicStat, + "opendiscord:average-tickets":api.ODDynamicStat, } /**## ODStatGlobalScope_DefaultGlobal `default_class` @@ -73,53 +72,53 @@ export interface ODStatGlobalScopeIds_DefaultGlobal { * * This default class is made for the `opendiscord:global` category in `opendiscord.stats`! */ -export class ODStatGlobalScope_DefaultGlobal extends ODStatGlobalScope { +export class ODStatGlobalScope_DefaultGlobal extends api.ODStatGlobalScope { get(id:StatsId): ODStatGlobalScopeIds_DefaultGlobal[StatsId] - get(id:ODValidId): ODStat|null + get(id:api.ODValidId): api.ODStat|null - get(id:ODValidId): ODStat|null { + get(id:api.ODValidId): api.ODStat|null { return super.get(id) } remove(id:StatsId): ODStatGlobalScopeIds_DefaultGlobal[StatsId] - remove(id:ODValidId): ODStat|null + remove(id:api.ODValidId): api.ODStat|null - remove(id:ODValidId): ODStat|null { + remove(id:api.ODValidId): api.ODStat|null { return super.remove(id) } exists(id:keyof ODStatGlobalScopeIds_DefaultGlobal): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } - getStat(id:StatsId): Promise - getStat(id:ODValidId): Promise + getStat(id:StatsId): Promise + getStat(id:api.ODValidId): Promise - getStat(id:ODValidId): Promise { + getStat(id:api.ODValidId): Promise { return super.getStat(id) } - getAllStats(id:StatsId): Promise<{id:string,value:ODValidStatValue}[]> - getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> + getAllStats(id:StatsId): Promise<{id:string,value:api.ODValidStatValue}[]> + getAllStats(id:api.ODValidId): Promise<{id:string,value:api.ODValidStatValue}[]> - getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> { + getAllStats(id:api.ODValidId): Promise<{id:string,value:api.ODValidStatValue}[]> { return super.getAllStats(id) } - setStat(id:StatsId, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise - setStat(id:ODValidId, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise + setStat(id:StatsId, value:api.ODValidStatValue, mode:api.ODStatScopeSetMode): Promise + setStat(id:api.ODValidId, value:api.ODValidStatValue, mode:api.ODStatScopeSetMode): Promise - setStat(id:ODValidId, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise { + setStat(id:api.ODValidId, value:api.ODValidStatValue, mode:api.ODStatScopeSetMode): Promise { return super.setStat(id,value,mode) } - resetStat(id:ODValidId): Promise - resetStat(id:ODValidId): Promise + resetStat(id:api.ODValidId): Promise + resetStat(id:api.ODValidId): Promise - resetStat(id:ODValidId): Promise { + resetStat(id:api.ODValidId): Promise { return super.resetStat(id) } } @@ -129,9 +128,9 @@ export class ODStatGlobalScope_DefaultGlobal extends ODStatGlobalScope { * It's used to generate typescript declarations for this class. */ export interface ODStatGlobalScopeIds_DefaultSystem { - "opendiscord:startup-date":ODDynamicStat, - "opendiscord:system-uptime":ODDynamicStat, - "opendiscord:version":ODDynamicStat + "opendiscord:startup-date":api.ODDynamicStat, + "opendiscord:system-uptime":api.ODDynamicStat, + "opendiscord:version":api.ODDynamicStat } /**## ODStatGlobalScope_DefaultSystem `default_class` @@ -140,53 +139,53 @@ export interface ODStatGlobalScopeIds_DefaultSystem { * * This default class is made for the `opendiscord:system` category in `opendiscord.stats`! */ -export class ODStatGlobalScope_DefaultSystem extends ODStatGlobalScope { +export class ODStatGlobalScope_DefaultSystem extends api.ODStatGlobalScope { get(id:StatsId): ODStatGlobalScopeIds_DefaultSystem[StatsId] - get(id:ODValidId): ODStat|null + get(id:api.ODValidId): api.ODStat|null - get(id:ODValidId): ODStat|null { + get(id:api.ODValidId): api.ODStat|null { return super.get(id) } remove(id:StatsId): ODStatGlobalScopeIds_DefaultSystem[StatsId] - remove(id:ODValidId): ODStat|null + remove(id:api.ODValidId): api.ODStat|null - remove(id:ODValidId): ODStat|null { + remove(id:api.ODValidId): api.ODStat|null { return super.remove(id) } exists(id:keyof ODStatGlobalScopeIds_DefaultSystem): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } - getStat(id:StatsId): Promise - getStat(id:ODValidId): Promise + getStat(id:StatsId): Promise + getStat(id:api.ODValidId): Promise - getStat(id:ODValidId): Promise { + getStat(id:api.ODValidId): Promise { return super.getStat(id) } - getAllStats(id:StatsId): Promise<{id:string,value:ODValidStatValue}[]> - getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> + getAllStats(id:StatsId): Promise<{id:string,value:api.ODValidStatValue}[]> + getAllStats(id:api.ODValidId): Promise<{id:string,value:api.ODValidStatValue}[]> - getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> { + getAllStats(id:api.ODValidId): Promise<{id:string,value:api.ODValidStatValue}[]> { return super.getAllStats(id) } - setStat(id:StatsId, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise - setStat(id:ODValidId, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise + setStat(id:StatsId, value:api.ODValidStatValue, mode:api.ODStatScopeSetMode): Promise + setStat(id:api.ODValidId, value:api.ODValidStatValue, mode:api.ODStatScopeSetMode): Promise - setStat(id:ODValidId, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise { + setStat(id:api.ODValidId, value:api.ODValidStatValue, mode:api.ODStatScopeSetMode): Promise { return super.setStat(id,value,mode) } - resetStat(id:ODValidId): Promise - resetStat(id:ODValidId): Promise + resetStat(id:api.ODValidId): Promise + resetStat(id:api.ODValidId): Promise - resetStat(id:ODValidId): Promise { + resetStat(id:api.ODValidId): Promise { return super.resetStat(id) } } @@ -196,19 +195,19 @@ export class ODStatGlobalScope_DefaultSystem extends ODStatGlobalScope { * It's used to generate typescript declarations for this class. */ export interface ODStatScopeIds_DefaultUser { - "opendiscord:name":ODDynamicStat, - "opendiscord:role":ODDynamicStat, - "opendiscord:tickets-created":ODBasicStat, - "opendiscord:tickets-closed":ODBasicStat, - "opendiscord:tickets-deleted":ODBasicStat, - "opendiscord:tickets-reopened":ODBasicStat, - "opendiscord:tickets-claimed":ODBasicStat, - "opendiscord:tickets-pinned":ODBasicStat, - "opendiscord:tickets-moved":ODBasicStat, - "opendiscord:tickets-transferred":ODBasicStat, - "opendiscord:users-blacklisted":ODBasicStat, - "opendiscord:transcripts-created":ODBasicStat, - "opendiscord:current-tickets":ODDynamicStat, + "opendiscord:name":api.ODDynamicStat, + "opendiscord:role":api.ODDynamicStat, + "opendiscord:tickets-created":api.ODBasicStat, + "opendiscord:tickets-closed":api.ODBasicStat, + "opendiscord:tickets-deleted":api.ODBasicStat, + "opendiscord:tickets-reopened":api.ODBasicStat, + "opendiscord:tickets-claimed":api.ODBasicStat, + "opendiscord:tickets-pinned":api.ODBasicStat, + "opendiscord:tickets-moved":api.ODBasicStat, + "opendiscord:tickets-transferred":api.ODBasicStat, + "opendiscord:users-blacklisted":api.ODBasicStat, + "opendiscord:transcripts-created":api.ODBasicStat, + "opendiscord:current-tickets":api.ODDynamicStat, } /**## ODStatScope_DefaultUser `default_class` @@ -217,53 +216,53 @@ export interface ODStatScopeIds_DefaultUser { * * This default class is made for the `opendiscord:user` category in `opendiscord.stats`! */ -export class ODStatScope_DefaultUser extends ODStatScope { +export class ODStatScope_DefaultUser extends api.ODStatScope { get(id:StatsId): ODStatScopeIds_DefaultUser[StatsId] - get(id:ODValidId): ODStat|null + get(id:api.ODValidId): api.ODStat|null - get(id:ODValidId): ODStat|null { + get(id:api.ODValidId): api.ODStat|null { return super.get(id) } remove(id:StatsId): ODStatScopeIds_DefaultUser[StatsId] - remove(id:ODValidId): ODStat|null + remove(id:api.ODValidId): api.ODStat|null - remove(id:ODValidId): ODStat|null { + remove(id:api.ODValidId): api.ODStat|null { return super.remove(id) } exists(id:keyof ODStatScopeIds_DefaultUser): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } - getStat(id:StatsId, scopeId:string): Promise - getStat(id:ODValidId, scopeId:string): Promise + getStat(id:StatsId, scopeId:string): Promise + getStat(id:api.ODValidId, scopeId:string): Promise - getStat(id:ODValidId, scopeId:string): Promise { + getStat(id:api.ODValidId, scopeId:string): Promise { return super.getStat(id,scopeId) } - getAllStats(id:StatsId): Promise<{id:string,value:ODValidStatValue}[]> - getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> + getAllStats(id:StatsId): Promise<{id:string,value:api.ODValidStatValue}[]> + getAllStats(id:api.ODValidId): Promise<{id:string,value:api.ODValidStatValue}[]> - getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> { + getAllStats(id:api.ODValidId): Promise<{id:string,value:api.ODValidStatValue}[]> { return super.getAllStats(id) } - setStat(id:StatsId, scopeId:string, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise - setStat(id:ODValidId, scopeId:string, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise + setStat(id:StatsId, scopeId:string, value:api.ODValidStatValue, mode:api.ODStatScopeSetMode): Promise + setStat(id:api.ODValidId, scopeId:string, value:api.ODValidStatValue, mode:api.ODStatScopeSetMode): Promise - setStat(id:ODValidId, scopeId:string, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise { + setStat(id:api.ODValidId, scopeId:string, value:api.ODValidStatValue, mode:api.ODStatScopeSetMode): Promise { return super.setStat(id,scopeId,value,mode) } - resetStat(id:ODValidId, scopeId:string): Promise - resetStat(id:ODValidId, scopeId:string): Promise + resetStat(id:api.ODValidId, scopeId:string): Promise + resetStat(id:api.ODValidId, scopeId:string): Promise - resetStat(id:ODValidId, scopeId:string): Promise { + resetStat(id:api.ODValidId, scopeId:string): Promise { return super.resetStat(id,scopeId) } } @@ -273,15 +272,15 @@ export class ODStatScope_DefaultUser extends ODStatScope { * It's used to generate typescript declarations for this class. */ export interface ODStatScopeIds_DefaultTicket { - "opendiscord:name":ODDynamicStat, - "opendiscord:status":ODDynamicStat, - "opendiscord:claimed":ODDynamicStat, - "opendiscord:pinned":ODDynamicStat, - "opendiscord:creation-date":ODDynamicStat, - "opendiscord:creator":ODDynamicStat, - "opendiscord:ticket-age":ODDynamicStat, - "opendiscord:response-time":ODDynamicStat, - "opendiscord:resolution-time":ODDynamicStat, + "opendiscord:name":api.ODDynamicStat, + "opendiscord:status":api.ODDynamicStat, + "opendiscord:claimed":api.ODDynamicStat, + "opendiscord:pinned":api.ODDynamicStat, + "opendiscord:creation-date":api.ODDynamicStat, + "opendiscord:creator":api.ODDynamicStat, + "opendiscord:ticket-age":api.ODDynamicStat, + "opendiscord:response-time":api.ODDynamicStat, + "opendiscord:resolution-time":api.ODDynamicStat, } /**## ODStatScope_DefaultTicket `default_class` @@ -290,53 +289,53 @@ export interface ODStatScopeIds_DefaultTicket { * * This default class is made for the `opendiscord:ticket` category in `opendiscord.stats`! */ -export class ODStatScope_DefaultTicket extends ODStatScope { +export class ODStatScope_DefaultTicket extends api.ODStatScope { get(id:StatsId): ODStatScopeIds_DefaultTicket[StatsId] - get(id:ODValidId): ODStat|null + get(id:api.ODValidId): api.ODStat|null - get(id:ODValidId): ODStat|null { + get(id:api.ODValidId): api.ODStat|null { return super.get(id) } remove(id:StatsId): ODStatScopeIds_DefaultTicket[StatsId] - remove(id:ODValidId): ODStat|null + remove(id:api.ODValidId): api.ODStat|null - remove(id:ODValidId): ODStat|null { + remove(id:api.ODValidId): api.ODStat|null { return super.remove(id) } exists(id:keyof ODStatScopeIds_DefaultTicket): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } - getStat(id:StatsId, scopeId:string): Promise - getStat(id:ODValidId, scopeId:string): Promise + getStat(id:StatsId, scopeId:string): Promise + getStat(id:api.ODValidId, scopeId:string): Promise - getStat(id:ODValidId, scopeId:string): Promise { + getStat(id:api.ODValidId, scopeId:string): Promise { return super.getStat(id,scopeId) } - getAllStats(id:StatsId): Promise<{id:string,value:ODValidStatValue}[]> - getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> + getAllStats(id:StatsId): Promise<{id:string,value:api.ODValidStatValue}[]> + getAllStats(id:api.ODValidId): Promise<{id:string,value:api.ODValidStatValue}[]> - getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> { + getAllStats(id:api.ODValidId): Promise<{id:string,value:api.ODValidStatValue}[]> { return super.getAllStats(id) } - setStat(id:StatsId, scopeId:string, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise - setStat(id:ODValidId, scopeId:string, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise + setStat(id:StatsId, scopeId:string, value:api.ODValidStatValue, mode:api.ODStatScopeSetMode): Promise + setStat(id:api.ODValidId, scopeId:string, value:api.ODValidStatValue, mode:api.ODStatScopeSetMode): Promise - setStat(id:ODValidId, scopeId:string, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise { + setStat(id:api.ODValidId, scopeId:string, value:api.ODValidStatValue, mode:api.ODStatScopeSetMode): Promise { return super.setStat(id,scopeId,value,mode) } - resetStat(id:ODValidId, scopeId:string): Promise - resetStat(id:ODValidId, scopeId:string): Promise + resetStat(id:api.ODValidId, scopeId:string): Promise + resetStat(id:api.ODValidId, scopeId:string): Promise - resetStat(id:ODValidId, scopeId:string): Promise { + resetStat(id:api.ODValidId, scopeId:string): Promise { return super.resetStat(id,scopeId) } } @@ -346,7 +345,7 @@ export class ODStatScope_DefaultTicket extends ODStatScope { * It's used to generate typescript declarations for this class. */ export interface ODStatScopeIds_DefaultParticipants { - "opendiscord:participants":ODDynamicStat + "opendiscord:participants":api.ODDynamicStat } /**## ODStatScope_DefaultParticipants `default_class` @@ -355,53 +354,53 @@ export interface ODStatScopeIds_DefaultParticipants { * * This default class is made for the `opendiscord:participants` category in `opendiscord.stats`! */ -export class ODStatScope_DefaultParticipants extends ODStatScope { +export class ODStatScope_DefaultParticipants extends api.ODStatScope { get(id:StatsId): ODStatScopeIds_DefaultParticipants[StatsId] - get(id:ODValidId): ODStat|null + get(id:api.ODValidId): api.ODStat|null - get(id:ODValidId): ODStat|null { + get(id:api.ODValidId): api.ODStat|null { return super.get(id) } remove(id:StatsId): ODStatScopeIds_DefaultParticipants[StatsId] - remove(id:ODValidId): ODStat|null + remove(id:api.ODValidId): api.ODStat|null - remove(id:ODValidId): ODStat|null { + remove(id:api.ODValidId): api.ODStat|null { return super.remove(id) } exists(id:keyof ODStatScopeIds_DefaultParticipants): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } - getStat(id:StatsId, scopeId:string): Promise - getStat(id:ODValidId, scopeId:string): Promise + getStat(id:StatsId, scopeId:string): Promise + getStat(id:api.ODValidId, scopeId:string): Promise - getStat(id:ODValidId, scopeId:string): Promise { + getStat(id:api.ODValidId, scopeId:string): Promise { return super.getStat(id,scopeId) } - getAllStats(id:StatsId): Promise<{id:string,value:ODValidStatValue}[]> - getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> + getAllStats(id:StatsId): Promise<{id:string,value:api.ODValidStatValue}[]> + getAllStats(id:api.ODValidId): Promise<{id:string,value:api.ODValidStatValue}[]> - getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> { + getAllStats(id:api.ODValidId): Promise<{id:string,value:api.ODValidStatValue}[]> { return super.getAllStats(id) } - setStat(id:StatsId, scopeId:string, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise - setStat(id:ODValidId, scopeId:string, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise + setStat(id:StatsId, scopeId:string, value:api.ODValidStatValue, mode:api.ODStatScopeSetMode): Promise + setStat(id:api.ODValidId, scopeId:string, value:api.ODValidStatValue, mode:api.ODStatScopeSetMode): Promise - setStat(id:ODValidId, scopeId:string, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise { + setStat(id:api.ODValidId, scopeId:string, value:api.ODValidStatValue, mode:api.ODStatScopeSetMode): Promise { return super.setStat(id,scopeId,value,mode) } - resetStat(id:ODValidId, scopeId:string): Promise - resetStat(id:ODValidId, scopeId:string): Promise + resetStat(id:api.ODValidId, scopeId:string): Promise + resetStat(id:api.ODValidId, scopeId:string): Promise - resetStat(id:ODValidId, scopeId:string): Promise { + resetStat(id:api.ODValidId, scopeId:string): Promise { return super.resetStat(id,scopeId) } } @@ -411,7 +410,7 @@ export class ODStatScope_DefaultParticipants extends ODStatScope { * It's used to generate typescript declarations for this class. */ export interface ODStatScopeIds_DefaultMessages { - "opendiscord:count":ODDynamicStat + "opendiscord:count":api.ODDynamicStat } /**## ODStatScope_DefaultMessages `default_class` @@ -420,53 +419,53 @@ export interface ODStatScopeIds_DefaultMessages { * * This default class is made for the `opendiscord:participants` category in `opendiscord.stats`! */ -export class ODStatScope_DefaultMessages extends ODStatScope { +export class ODStatScope_DefaultMessages extends api.ODStatScope { get(id:StatsId): ODStatScopeIds_DefaultMessages[StatsId] - get(id:ODValidId): ODStat|null + get(id:api.ODValidId): api.ODStat|null - get(id:ODValidId): ODStat|null { + get(id:api.ODValidId): api.ODStat|null { return super.get(id) } remove(id:StatsId): ODStatScopeIds_DefaultMessages[StatsId] - remove(id:ODValidId): ODStat|null + remove(id:api.ODValidId): api.ODStat|null - remove(id:ODValidId): ODStat|null { + remove(id:api.ODValidId): api.ODStat|null { return super.remove(id) } exists(id:keyof ODStatScopeIds_DefaultMessages): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } - getStat(id:StatsId, scopeId:string): Promise - getStat(id:ODValidId, scopeId:string): Promise + getStat(id:StatsId, scopeId:string): Promise + getStat(id:api.ODValidId, scopeId:string): Promise - getStat(id:ODValidId, scopeId:string): Promise { + getStat(id:api.ODValidId, scopeId:string): Promise { return super.getStat(id,scopeId) } - getAllStats(id:StatsId): Promise<{id:string,value:ODValidStatValue}[]> - getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> + getAllStats(id:StatsId): Promise<{id:string,value:api.ODValidStatValue}[]> + getAllStats(id:api.ODValidId): Promise<{id:string,value:api.ODValidStatValue}[]> - getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> { + getAllStats(id:api.ODValidId): Promise<{id:string,value:api.ODValidStatValue}[]> { return super.getAllStats(id) } - setStat(id:StatsId, scopeId:string, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise - setStat(id:ODValidId, scopeId:string, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise + setStat(id:StatsId, scopeId:string, value:api.ODValidStatValue, mode:api.ODStatScopeSetMode): Promise + setStat(id:api.ODValidId, scopeId:string, value:api.ODValidStatValue, mode:api.ODStatScopeSetMode): Promise - setStat(id:ODValidId, scopeId:string, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise { + setStat(id:api.ODValidId, scopeId:string, value:api.ODValidStatValue, mode:api.ODStatScopeSetMode): Promise { return super.setStat(id,scopeId,value,mode) } - resetStat(id:ODValidId, scopeId:string): Promise - resetStat(id:ODValidId, scopeId:string): Promise + resetStat(id:api.ODValidId, scopeId:string): Promise + resetStat(id:api.ODValidId, scopeId:string): Promise - resetStat(id:ODValidId, scopeId:string): Promise { + resetStat(id:api.ODValidId, scopeId:string): Promise { return super.resetStat(id,scopeId) } } \ No newline at end of file diff --git a/src/core/api/defaults/verifybar.ts b/src/core/api/defaults/verifybar.ts index 7ee623b..84c1d05 100644 --- a/src/core/api/defaults/verifybar.ts +++ b/src/core/api/defaults/verifybar.ts @@ -1,10 +1,8 @@ /////////////////////////////////////// //DEFAULT VERIFYBAR MODULE /////////////////////////////////////// -import { ODValidId } from "../modules/base" -import { ODButtonResponderInstance } from "../modules/responder" +import * as api from "@open-discord-bots/framework/api" import { ODWorkerManager_Default } from "../defaults/worker" -import { ODVerifyBarManager, ODVerifyBar } from "../modules/verifybar" import * as discord from "discord.js" /**## ODVerifyBarManagerIds_Default `interface` @@ -37,25 +35,25 @@ export interface ODVerifyBarManagerIds_Default { * * This default class is made for the global variable `opendiscord.verifybars`! */ -export class ODVerifyBarManager_Default extends ODVerifyBarManager { +export class ODVerifyBarManager_Default extends api.ODVerifyBarManager { get(id:VerifyBarId): ODVerifyBar_Default - get(id:ODValidId): ODVerifyBar|null + get(id:api.ODValidId): api.ODVerifyBar|null - get(id:ODValidId): ODVerifyBar|null { + get(id:api.ODValidId): api.ODVerifyBar|null { return super.get(id) } remove(id:VerifyBarId): ODVerifyBar_Default - remove(id:ODValidId): ODVerifyBar|null + remove(id:api.ODValidId): api.ODVerifyBar|null - remove(id:ODValidId): ODVerifyBar|null { + remove(id:api.ODValidId): api.ODVerifyBar|null { return super.remove(id) } exists(id:keyof ODVerifyBarManagerIds_Default): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -66,7 +64,7 @@ export class ODVerifyBarManager_Default extends ODVerifyBarManager { * * This default class is made for the default `ODVerifyBar`'s! */ -export class ODVerifyBar_Default extends ODVerifyBar { - declare success: ODWorkerManager_Default|null},SuccessWorkerIds> - declare failure: ODWorkerManager_Default|null},FailureWorkerIds> +export class ODVerifyBar_Default extends api.ODVerifyBar { + declare success: ODWorkerManager_Default|null},SuccessWorkerIds> + declare failure: ODWorkerManager_Default|null},FailureWorkerIds> } \ No newline at end of file diff --git a/src/core/api/defaults/worker.ts b/src/core/api/defaults/worker.ts index 3642aee..621f5da 100644 --- a/src/core/api/defaults/worker.ts +++ b/src/core/api/defaults/worker.ts @@ -1,9 +1,7 @@ /////////////////////////////////////// //DEFAULT WORKER MODULE /////////////////////////////////////// -import { ODValidId } from "../modules/base" -import { ODWorker, ODWorkerManager } from "../modules/worker" - +import * as api from "@open-discord-bots/framework/api" /**## ODWorkerManager_Default `default_class` * This is a special class that adds type definitions & typescript to the ODWorkerManager class. @@ -11,25 +9,25 @@ import { ODWorker, ODWorkerManager } from "../modules/worker" * * This default class is made for the worker manager in actions, builders & responders! */ -export class ODWorkerManager_Default extends ODWorkerManager { - get(id:WorkerIds): ODWorker - get(id:ODValidId): ODWorker|null +export class ODWorkerManager_Default extends api.ODWorkerManager { + get(id:WorkerIds): api.ODWorker + get(id:api.ODValidId): api.ODWorker|null - get(id:ODValidId): ODWorker|null { + get(id:api.ODValidId): api.ODWorker|null { return super.get(id) } - remove(id:WorkerIds): ODWorker - remove(id:ODValidId): ODWorker|null + remove(id:WorkerIds): api.ODWorker + remove(id:api.ODValidId): api.ODWorker|null - remove(id:ODValidId): ODWorker|null { + remove(id:api.ODValidId): api.ODWorker|null { return super.remove(id) } exists(id:WorkerIds): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } \ No newline at end of file diff --git a/src/core/api/main.ts b/src/core/api/main.ts index f5e282a..3eeb687 100644 --- a/src/core/api/main.ts +++ b/src/core/api/main.ts @@ -1,193 +1,127 @@ -//BASE MODULES -import { ODEnvHelper, ODVersion } from "./modules/base" -import { ODConsoleManager, ODConsoleMessage, ODConsoleMessageParam, ODConsoleMessageTypes, ODDebugFileManager, ODDebugger, ODError } from "./modules/console" -import { ODCheckerStorage } from "./modules/checker" -import { ODDefaultsManager } from "./modules/defaults" +/////////////////////////////////////// +//OPEN TICKET MAIN MODULE +/////////////////////////////////////// +import * as api from "./api" +import * as utilities from "@open-discord-bots/framework/utilities" -//DEFAULT MODULES -import { ODVersionManager_Default } from "./defaults/base" -import { ODPluginManager_Default } from "./defaults/plugin" -import { ODEventManager_Default } from "./defaults/event" -import { ODConfigManager_Default} from "./defaults/config" -import { ODDatabaseManager_Default } from "./defaults/database" -import { ODFlagManager_Default } from "./defaults/flag" -import { ODSessionManager_Default } from "./defaults/session" -import { ODLanguageManager_Default } from "./defaults/language" -import { ODCheckerFunctionManager_Default, ODCheckerManager_Default, ODCheckerRenderer_Default, ODCheckerTranslationRegister_Default } from "./defaults/checker" -import { ODClientManager_Default } from "./defaults/client" -import { ODBuilderManager_Default } from "./defaults/builder" -import { ODResponderManager_Default } from "./defaults/responder" -import { ODActionManager_Default } from "./defaults/action" -import { ODPermissionManager_Default } from "./defaults/permission" -import { ODHelpMenuManager_Default } from "./defaults/helpmenu" -import { ODStatsManager_Default } from "./defaults/stat" -import { ODCodeManager_Default } from "./defaults/code" -import { ODCooldownManager_Default } from "./defaults/cooldown" -import { ODPostManager_Default } from "./defaults/post" -import { ODVerifyBarManager_Default } from "./defaults/verifybar" -import { ODProgressBarManager_Default } from "./defaults/progressbar" -import { ODStartScreenManager_Default } from "./defaults/startscreen" -import { ODLiveStatusManager_Default } from "./defaults/console" +export class ODOpenTicketMain extends api.ODMain { + declare versions: api.ODVersionManager_Default + declare events: api.ODEventManager_Default -//OPEN TICKET MODULES -import { ODOptionManager } from "./openticket/option" -import { ODPanelManager } from "./openticket/panel" -import { ODTicketManager } from "./openticket/ticket" -import { ODQuestionManager } from "./openticket/question" -import { ODBlacklistManager } from "./openticket/blacklist" -import { ODTranscriptManager_Default } from "./openticket/transcript" -import { ODRoleManager } from "./openticket/role" -import { ODPriorityManager_Default } from "./openticket/priority" - -/**## ODMain `class` - * This is the main Open Ticket class. - * It contains all managers from the entire bot & has shortcuts to the event & logging system. - * - * This class can't be overwritten or extended & is available as the global variable `openticket`! - */ -export class ODMain { - /**The manager that handles all versions in the bot. */ - versions: ODVersionManager_Default - - /**The timestamp that the (node.js) process of the bot started. */ - processStartupDate: Date = new Date() - /**The timestamp that the bot finished loading and is ready for usage. */ - readyStartupDate: Date|null = null - - /**The manager responsible for the debug file. (`otdebug.txt`) */ - debugfile: ODDebugFileManager - /**The manager responsible for the console system. (logs, errors, etc) */ - console: ODConsoleManager - /**The manager responsible for sending debug logs to the debug file. (`otdebug.txt`) */ - debug: ODDebugger - /**The manager containing all Open Ticket events. */ - events: ODEventManager_Default - - /**The manager that handles & executes all plugins in the bot. */ - plugins: ODPluginManager_Default - /**The manager that manages & checks all the console flags of the bot. (like `--debug`) */ - flags: ODFlagManager_Default - /**The manager responsible for progress bars in the console. */ - progressbars: ODProgressBarManager_Default - /**The manager that manages & contains all the config files of the bot. (like `config/general.json`) */ - configs: ODConfigManager_Default - /**The manager that manages & contains all the databases of the bot. (like `database/global.json`) */ - databases: ODDatabaseManager_Default - /**The manager that manages all the data sessions of the bot. (it's a temporary database) */ - sessions: ODSessionManager_Default - /**The manager that manages all languages & translations of the bot. (but not for plugins) */ - languages: ODLanguageManager_Default + declare plugins: api.ODPluginManager_Default + declare flags: api.ODFlagManager_Default + declare progressbars: api.ODProgressBarManager_Default + declare configs: api.ODConfigManager_Default + declare databases: api.ODDatabaseManager_Default + declare sessions: api.ODSessionManager_Default + declare languages: api.ODLanguageManager_Default - /**The manager that handles & executes all config checkers in the bot. (the code that checks if you have something wrong in your config) */ - checkers: ODCheckerManager_Default - /**The manager that manages all builders in the bot. (e.g. buttons, dropdowns, messages, modals, etc) */ - builders: ODBuilderManager_Default - /**The manager that manages all responders in the bot. (e.g. commands, buttons, dropdowns, modals) */ - responders: ODResponderManager_Default - /**The manager that manages all actions or procedures in the bot. (e.g. ticket-creation, ticket-deletion, ticket-claiming, etc) */ - actions: ODActionManager_Default - /**The manager that manages all verify bars in the bot. (the ✅ ❌ buttons) */ - verifybars: ODVerifyBarManager_Default - /**The manager that contains all permissions for commands & actions in the bot. (use it to check if someone has admin perms or not) */ - permissions: ODPermissionManager_Default - /**The manager that contains all cooldowns of the bot. (e.g. ticket-cooldowns) */ - cooldowns: ODCooldownManager_Default - /**The manager that manages & renders the Open Ticket help menu. (not the embed, but the text) */ - helpmenu: ODHelpMenuManager_Default - /**The manager that manages, saves & renders the Open Ticket statistics. (not the embed, but the text & database) */ - stats: ODStatsManager_Default - /**This manager is a place where you can put code that executes when the bot almost finishes the setup. (can be used for less important stuff that doesn't require an exact time-order) */ - code: ODCodeManager_Default - /**The manager that manages all posts (static discord channels) in the bot. (e.g. (transcript) logs, etc) */ - posts: ODPostManager_Default + declare checkers: api.ODCheckerManager_Default + declare builders: api.ODBuilderManager_Default + declare responders: api.ODResponderManager_Default + declare actions: api.ODActionManager_Default + declare verifybars: api.ODVerifyBarManager_Default + declare permissions: api.ODPermissionManager_Default + declare cooldowns: api.ODCooldownManager_Default + declare helpmenu: api.ODHelpMenuManager_Default + declare stats: api.ODStatsManager_Default + declare code: api.ODCodeManager_Default + declare posts: api.ODPostManager_Default - /**The manager responsible for everything related to the client. (e.g. status, login, slash & text commands, etc) */ - client: ODClientManager_Default - /**This manager contains A LOD of booleans. With these switches, you can turn off "default behaviours" from the bot. This is used if you want to replace the default Open Ticket code. */ - defaults: ODDefaultsManager - /**This manager manages all the variables in the ENV. It reads from both the `.env` file & the `process.env`. (these 2 will be combined) */ - env: ODEnvHelper + declare client: api.ODClientManager_Default + declare livestatus: api.ODLiveStatusManager_Default + declare startscreen: api.ODStartScreenManager_Default - /**The manager responsible for the livestatus system. (remote console logs) */ - livestatus: ODLiveStatusManager_Default - /**The manager responsible for the livestatus system. (remote console logs) */ - startscreen: ODStartScreenManager_Default + ///////////////////// + //// OPEN TICKET //// + ///////////////////// - //OPEN TICKET + /**Open Ticket specific fuses. With these fuses/switches, you can turn off "default behaviours" from the bot. Useful for replacing default behaviour with a custom implementation. */ + fuses: api.ODFuseManager /**The manager that manages all the data of questions in the bot. (these are used in options & tickets) */ - questions: ODQuestionManager + questions: api.ODQuestionManager /**The manager that manages all the data of options in the bot. (these are used for panels, ticket creation, reaction roles) */ - options: ODOptionManager + options: api.ODOptionManager /**The manager that manages all the data of panels in the bot. (panels contain the options) */ - panels: ODPanelManager + panels: api.ODPanelManager /**The manager that manages all tickets in the bot. (here, you can get & edit a lot of data from tickets) */ - tickets: ODTicketManager + tickets: api.ODTicketManager /**The manager that manages the ticket blacklist. (people who are blacklisted can't create a ticket) */ - blacklist: ODBlacklistManager + blacklist: api.ODBlacklistManager /**The manager that manages the ticket transcripts. (both the history & compilers) */ - transcripts: ODTranscriptManager_Default + transcripts: api.ODTranscriptManager_Default /**The manager that manages all reaction roles in the bot. (here, you can add additional data to roles) */ - roles: ODRoleManager + roles: api.ODRoleManager /**The manager that manages all priority levels in the bot. (register/edit ticket priority levels) */ - priorities: ODPriorityManager_Default + priorities: api.ODPriorityManager_Default constructor(){ - this.versions = new ODVersionManager_Default() - this.versions.add(ODVersion.fromString("opendiscord:version","v4.1.3")) - this.versions.add(ODVersion.fromString("opendiscord:api","v1.0.0")) - this.versions.add(ODVersion.fromString("opendiscord:transcripts","v2.1.0")) - this.versions.add(ODVersion.fromString("opendiscord:livestatus","v2.0.0")) + const version = api.ODVersion.fromString("opendiscord:version","v4.1.3") + const debugfile = new api.ODDebugFileManager("./","otdebug.txt",5000,version) + const console = new api.ODConsoleManager(100,debugfile) + const debug = new api.ODDebugger(console) + const client = new api.ODClientManager_Default(debug) + const livestatus = new api.ODLiveStatusManager_Default(debug,console) + const permissions = new api.ODPermissionManager_Default(debug,client) - this.debugfile = new ODDebugFileManager("./","otdebug.txt",5000,this.versions.get("opendiscord:version")) - this.console = new ODConsoleManager(100,this.debugfile) - this.debug = new ODDebugger(this.console) - this.events = new ODEventManager_Default(this.debug) + super({ + versions:new api.ODVersionManager_Default(), + debugfile,console,debug, + events:new api.ODEventManager_Default(debug), + processStartupDate:new Date(), + readyStartupDate:null, - this.plugins = new ODPluginManager_Default(this.debug) - this.flags = new ODFlagManager_Default(this.debug) - this.progressbars = new ODProgressBarManager_Default(this.debug) - this.configs = new ODConfigManager_Default(this.debug) - this.databases = new ODDatabaseManager_Default(this.debug) - this.sessions = new ODSessionManager_Default(this.debug) - this.languages = new ODLanguageManager_Default(this.debug,false) - - this.checkers = new ODCheckerManager_Default(this.debug,new ODCheckerStorage(),new ODCheckerRenderer_Default(),new ODCheckerTranslationRegister_Default(),new ODCheckerFunctionManager_Default(this.debug)) - this.builders = new ODBuilderManager_Default(this.debug) - this.client = new ODClientManager_Default(this.debug) - this.responders = new ODResponderManager_Default(this.debug,this.client) - this.actions = new ODActionManager_Default(this.debug) - this.verifybars = new ODVerifyBarManager_Default(this.debug) - this.permissions = new ODPermissionManager_Default(this.debug,this.client) - this.cooldowns = new ODCooldownManager_Default(this.debug) - this.helpmenu = new ODHelpMenuManager_Default(this.debug) - this.stats = new ODStatsManager_Default(this.debug) - this.code = new ODCodeManager_Default(this.debug) - this.posts = new ODPostManager_Default(this.debug) - - this.defaults = new ODDefaultsManager() - this.env = new ODEnvHelper() + plugins:new api.ODPluginManager_Default(debug), + flags:new api.ODFlagManager_Default(debug), + progressbars:new api.ODProgressBarManager_Default(debug), + configs:new api.ODConfigManager_Default(debug), + databases:new api.ODDatabaseManager_Default(debug), + sessions:new api.ODSessionManager_Default(debug), + languages:new api.ODLanguageManager_Default(debug,false), + + checkers:new api.ODCheckerManager_Default(debug,new api.ODCheckerStorage(),new api.ODCheckerRenderer_Default(),new api.ODCheckerTranslationRegister_Default(),new api.ODCheckerFunctionManager_Default(debug)), + builders:new api.ODBuilderManager_Default(debug), + client, + responders:new api.ODResponderManager_Default(debug,client), + actions:new api.ODActionManager_Default(debug), + verifybars:new api.ODVerifyBarManager_Default(debug), + permissions, + cooldowns:new api.ODCooldownManager_Default(debug), + helpmenu:new api.ODHelpMenuManager_Default(debug), + stats:new api.ODStatsManager_Default(debug), + code:new api.ODCodeManager_Default(debug), + posts:new api.ODPostManager_Default(debug), + + sharedFuses:utilities.sharedFuses, + env:new api.ODEnvHelper(), + livestatus, + startscreen:new api.ODStartScreenManager_Default(debug,livestatus), + },"openticket") - this.livestatus = new ODLiveStatusManager_Default(this.debug,this) - this.startscreen = new ODStartScreenManager_Default(this.debug,this.livestatus) + this.livestatus.useMain(this) + this.versions.add(api.ODVersion.fromString("opendiscord:version","v4.1.3")) + this.versions.add(api.ODVersion.fromString("opendiscord:transcripts","v2.1.0")) //OPEN TICKET - this.questions = new ODQuestionManager(this.debug) - this.options = new ODOptionManager(this.debug) - this.panels = new ODPanelManager(this.debug) - this.tickets = new ODTicketManager(this.debug,this.client) - this.blacklist = new ODBlacklistManager(this.debug) - this.transcripts = new ODTranscriptManager_Default(this.debug,this.tickets,this.client,this.permissions) - this.roles = new ODRoleManager(this.debug) - this.priorities = new ODPriorityManager_Default(this.debug) - } - - /**Log a message to the console. But in the Open Ticket style :) */ - log(message:ODConsoleMessage): void - log(message:ODError): void - log(message:string, type?:ODConsoleMessageTypes, params?:ODConsoleMessageParam[]): void - log(message:ODConsoleMessage|ODError|string, type?:ODConsoleMessageTypes, params?:ODConsoleMessageParam[]){ - if (message instanceof ODConsoleMessage) this.console.log(message) - else if (message instanceof ODError) this.console.log(message) - else if (["string","number","boolean","object"].includes(typeof message)) this.console.log(message,type,params) + this.fuses = new api.ODFuseManager({ + questionLoading:true, + optionLoading:true, + panelLoading:true, + ticketLoading:true, + roleLoading:true, + blacklistLoading:true, + transcriptCompilerLoading:true, + transcriptHistoryLoading:true, + autocloseCheckInterval:300000, //5 minutes + autodeleteCheckInterval:300000 //5 minutes + }) + this.questions = new api.ODQuestionManager(debug) + this.options = new api.ODOptionManager(debug) + this.panels = new api.ODPanelManager(debug) + this.tickets = new api.ODTicketManager(debug,client) + this.blacklist = new api.ODBlacklistManager(debug) + this.transcripts = new api.ODTranscriptManager_Default(debug,this.tickets,client,permissions) + this.roles = new api.ODRoleManager(debug) + this.priorities = new api.ODPriorityManager_Default(debug) } } \ No newline at end of file diff --git a/src/core/api/modules/action.ts b/src/core/api/modules/action.ts deleted file mode 100644 index 92a5993..0000000 --- a/src/core/api/modules/action.ts +++ /dev/null @@ -1,58 +0,0 @@ -/////////////////////////////////////// -//ACTION MODULE -/////////////////////////////////////// -import { ODId, ODManager, ODValidId, ODSystemError, ODManagerData } from "./base" -import { ODWorkerManager, ODWorkerCallback, ODWorker } from "./worker" -import { ODDebugger } from "./console" - -/**## ODActionImplementation `class` - * This is an Open Ticket action implementation. - * - * It is a basic implementation of the `ODWorkerManager` used by all `ODAction` classes. - * - * This class can't be used stand-alone & needs to be extended from! - */ -export class ODActionImplementation extends ODManagerData { - /**The manager that has all workers of this implementation */ - workers: ODWorkerManager - - constructor(id:ODValidId, callback?:ODWorkerCallback, priority?:number, callbackId?:ODValidId){ - super(id) - this.workers = new ODWorkerManager("descending") - if (callback) this.workers.add(new ODWorker(callbackId ? callbackId : id,priority ?? 0,callback)) - } - /**Execute all workers & return the result. */ - async run(source:Source, params:Params): Promise> { - throw new ODSystemError("Tried to build an unimplemented ODResponderImplementation") - } -} - -/**## ODActionManager `class` - * This is an Open Ticket action manager. - * - * It contains all Open Ticket actions. You can compare actions with some sort of "procedure". - * It's a complicated task that is divided into multiple functions. - * - * Some examples are `ticket-creation`, `ticket-closing`, `ticket-claiming`, ... - * - * It's recommended to use this system in combination with Open Ticket responders! - */ -export class ODActionManager extends ODManager> { - constructor(debug:ODDebugger){ - super(debug,"action") - } -} - -export class ODAction extends ODActionImplementation { - /**Run this action */ - async run(source:Source, params:Params): Promise> { - //create instance - const instance = {} - - //wait for workers to finish - await this.workers.executeWorkers(instance,source,params) - - //return data generated by workers - return instance - } -} \ No newline at end of file diff --git a/src/core/api/modules/base.ts b/src/core/api/modules/base.ts deleted file mode 100644 index ef70065..0000000 --- a/src/core/api/modules/base.ts +++ /dev/null @@ -1,763 +0,0 @@ -/////////////////////////////////////// -//BASE MODULE -/////////////////////////////////////// -import * as fs from "fs" -import { ODConsoleWarningMessage, ODDebugger } from "./console" - -/**## ODPromiseVoid `type` - * This is a simple type to represent a callback return value that could be a promise or not. - */ -export type ODPromiseVoid = void|Promise - -/**## ODOptionalPromise `type` - * This is a simple type to represent a type as normal value or a promise value. - */ -export type ODOptionalPromise = T|Promise - - -/**## ODValidButtonColor `type` - * This is a collection of all the possible button colors. - */ -export type ODValidButtonColor = "gray"|"red"|"green"|"blue" - -/**## ODValidId `type` - * This is a valid Open Ticket identifier. It can be an `ODId` or `string`! - * - * You will see this type in many functions from Open Ticket. - */ -export type ODValidId = string|ODId - -/**## ODValidJsonType `type` - * This is a collection of all types that can be stored in a JSON file! - * - * list: `string`, `number`, `boolean`, `array`, `object`, `null` - */ -export type ODValidJsonType = string|number|boolean|object|ODValidJsonType[]|null - - -/**## ODInterfaceWithPartialProperty `type` - * This is a utility type to create an interface where some properties are optional! - */ -export type ODInterfaceWithPartialProperty = Omit & Partial> - -/**## ODDiscordIdType `type` - * A list of all available discord ID types. Used in the config checker. - */ -export type ODDiscordIdType = "role"|"server"|"channel"|"category"|"user"|"member"|"interaction"|"message" - -/**## ODId `class` - * This is an Open Ticket identifier. - * - * It can only contain the following characters: `a-z`, `A-Z`, `0-9`, `:`, `-` & `_` - * - * You can use this class to assign a unique id when creating configs, databases, languages & more! - */ -export class ODId { - /**The full value of this `ODId` as a `string`. */ - #value: string - /**The full value of this `ODId` as a `string`. */ - set value(id:string){ - this._change(this.#value,id) - this.#value = id - } - get value(){ - return this.#value - } - /**The change listener for the parent `ODManager` of this `ODId`. */ - #change: ((oldId:string,newId:string) => void)|null = null - - constructor(id:ODValidId){ - if (typeof id != "string" && !(id instanceof ODId)) throw new ODSystemError("Invalid constructor parameter => id:ODValidId") - - if (typeof id == "string"){ - //id is string - const result: string[] = [] - const charregex = /[a-zA-Z0-9éèçàêâôûî\:\-\_]/ - - id.split("").forEach((char) => { - if (charregex.test(char)){ - result.push(char) - } - }) - - if (result.length > 0) this.#value = result.join("") - else throw new ODSystemError("invalid ID at 'new ODID(id: "+id+")'") - }else{ - //id is ODId - this.#value = id.#value - } - } - - /**Returns a string representation of this id. (same as `this.value`) */ - toString(){ - return this.#value - } - /**The namespace of the id before `:`. (e.g. `openticket` for `openticket:autoclose-enabled`) */ - getNamespace(){ - const splitted = this.#value.split(":") - if (splitted.length > 1) return splitted[0] - else return "" - } - /**The identifier of the id after `:`. (e.g. `autoclose-enabled` for `openticket:autoclose-enabled`) */ - getIdentifier(){ - const splitted = this.#value.split(":") - if (splitted.length > 1){ - splitted.shift() - return splitted.join(":") - }else return this.#value - } - /**Trigger an `onChange()` event in the parent `ODManager` of this class. */ - protected _change(oldId:string,newId:string){ - if (this.#change){ - try{ - this.#change(oldId,newId) - }catch(err){ - process.emit("uncaughtException",err) - throw new ODSystemError("Failed to execute _change() callback!") - } - } - } - /****(❌ SYSTEM ONLY!!)** Set the callback executed when a value inside this class changes. */ - changed(callback:((oldId:string,newId:string) => void)|null){ - this.#change = callback - } -} - -/**## ODManagerChangeHelper `class` - * This is an Open Ticket manager change helper. - * - * It is used to let the "onChange" event in the `ODManager` class work. - * You can use this class when extending your own `ODManager` - */ -export class ODManagerChangeHelper { - #change: (() => void)|null = null - - /**Trigger an `onChange()` event in the parent `ODManager` of this class. */ - protected _change(){ - if (this.#change){ - try{ - this.#change() - }catch(err){ - process.emit("uncaughtException",err) - throw new ODSystemError("Failed to execute _change() callback!") - } - } - } - /****(❌ SYSTEM ONLY!!)** Set the callback executed when a value inside this class changes. */ - changed(callback:(() => void)|null){ - this.#change = callback - } -} - -/**## ODManagerData `class` - * This is Open Ticket manager data. - * - * It provides a template for all classes that are used in the `ODManager`. - * - * There is an `id:ODId` property & also some events used in the manager. - */ -export class ODManagerData extends ODManagerChangeHelper { - /**The id of this data. */ - id: ODId - - constructor(id:ODValidId){ - if (typeof id != "string" && !(id instanceof ODId)) throw new ODSystemError("Invalid constructor parameter => id:ODValidId") - super() - this.id = new ODId(id) - } -} - -/**## ODManagerCallback `type` - * This is a callback for the `onChange` and `onRemove` events in the `ODManager` - */ -export type ODManagerCallback = (data:DataType) => void -/**## ODManagerAddCallback `type` - * This is a callback for the `onAdd` event in the `ODManager` - */ -export type ODManagerAddCallback = (data:DataType, overwritten:boolean) => void - -/**## ODManager `class` - * This is an Open Ticket manager. - * - * It can be used to store & manage classes based on their `ODId`. - * It is somewhat the same as the default JS `Map()`. - * You can extend this class when creating your own classes & managers. - * - * This class has many useful functions based on `ODId` (add, get, remove, getAll, getFiltered, exists, loopAll, ...) - */ -export class ODManager extends ODManagerChangeHelper { - /**Alias to Open Ticket debugger. */ - #debug?: ODDebugger - /**The message to send when debugging this manager. */ - #debugname?: string - /**The map storing all data classes in this manager. */ - #data: Map = new Map() - /**An array storing all listeners when data is added. */ - #addListeners: ODManagerAddCallback[] = [] - /**An array storing all listeners when data has changed. */ - #changeListeners: ODManagerCallback[] = [] - /**An array storing all listeners when data is removed. */ - #removeListeners: ODManagerCallback[] = [] - - constructor(debug?:ODDebugger, debugname?:string){ - super() - this.#debug = debug - this.#debugname = debugname - } - - /**Add data to the manager. The `ODId` in the data class will be used as identifier! You can optionally select to overwrite existing data!*/ - add(data:DataType|DataType[], overwrite?:boolean): boolean { - //repeat same command when data is an array - if (Array.isArray(data)){ - data.forEach((arrayData) => { - this.add(arrayData,overwrite) - }) - return false - } - - //add listener for data id change => transfer data within manager - data.id.changed((oldId,newId) => { - this.#data.delete(oldId) - this.#data.set(newId,data) - }) - - //add data - let didOverwrite: boolean - if (this.#data.has(data.id.value)){ - if (!overwrite) throw new ODSystemError("Id '"+data.id.value+"' already exists in "+this.#debugname+" manager. Use 'overwrite:true' to allow overwriting!") - this.#data.set(data.id.value,data) - didOverwrite = true - if (this.#debug) this.#debug.debug("Added new "+this.#debugname+" to manager",[{key:"id",value:data.id.value},{key:"overwrite",value:"true"}]) - - }else{ - this.#data.set(data.id.value,data) - didOverwrite = false - if (this.#debug) this.#debug.debug("Added new "+this.#debugname+" to manager",[{key:"id",value:data.id.value},{key:"overwrite",value:"false"}]) - - } - - //emit change listeners - data.changed(() => { - //notify change in upper-manager (because data in this manager changed) - this._change() - this.#changeListeners.forEach((cb) => { - try{ - cb(data) - }catch(err){ - throw new ODSystemError("Failed to run manager onChange() listener.\n"+err) - } - }) - }) - - //emit add listeners - this.#addListeners.forEach((cb) => { - try{ - cb(data,didOverwrite) - }catch(err){ - throw new ODSystemError("Failed to run manager onAdd() listener.\n"+err) - } - }) - - //notify change in upper-manager (because data added) - this._change() - - return didOverwrite - } - /**Get data that matches the `ODId`. Returns the found data.*/ - get(id:ODValidId): DataType|null { - const newId = new ODId(id) - const data = this.#data.get(newId.value) - if (data) return data - else return null - } - /**Remove data that matches the `ODId`. Returns the removed data. */ - remove(id:ODValidId): DataType|null { - const newId = new ODId(id) - const data = this.#data.get(newId.value) - - if (!data){ - if (this.#debug) this.#debug.debug("Removed "+this.#debugname+" from manager",[{key:"id",value:newId.value},{key:"found",value:"false"}]) - return null - }else{ - this.#data.delete(newId.value) - if (this.#debug) this.#debug.debug("Removed "+this.#debugname+" from manager",[{key:"id",value:newId.value},{key:"found",value:"true"}]) - } - - //remove all listeners - data.id.changed(null) - data.changed(null) - - //emit remove listeners - this.#removeListeners.forEach((cb) => { - try{ - cb(data) - }catch(err){ - throw new ODSystemError("Failed to run manager onRemove() listener.\n"+err) - } - }) - - //notify change in upper-manager (because data removed) - this._change() - - return data - } - /**Check if data that matches the `ODId` exists. Returns a boolean. */ - exists(id:ODValidId): boolean { - const newId = new ODId(id) - if (this.#data.has(newId.value)) return true - else return false - } - /**Get all data inside this manager*/ - getAll(): DataType[] { - return Array.from(this.#data.values()) - } - /**Get all data that matches inside the filter function*/ - getFiltered(predicate:(value:DataType, index:number, array:DataType[]) => unknown): DataType[] { - return Array.from(this.#data.values()).filter(predicate) - } - /**Get all data where the `ODId` matches the provided RegExp. */ - getRegex(regex:RegExp): DataType[] { - return Array.from(this.#data.values()).filter((data) => regex.test(data.id.value)) - } - /**Get the length/size/amount of the data inside this manager. */ - getLength(){ - return this.#data.size - } - /**Get a list of all the ids inside this manager*/ - getIds(): ODId[] { - const ids = Array.from(this.#data.keys()) - return ids.map((id) => new ODId(id)) - } - /**Run an iterator over all data in this manager. This method also supports async-await behaviour!*/ - async loopAll(cb:(data:DataType,id:ODId) => ODPromiseVoid): Promise { - for (const data of this.getAll()){ - await cb(data,data.id) - } - } - /**Use the Open Ticket debugger in this manager for logs*/ - useDebug(debug?:ODDebugger, debugname?:string){ - this.#debug = debug - this.#debugname = debugname - } - /**Listen for when data is added to this manager. */ - onAdd(callback:ODManagerAddCallback){ - this.#addListeners.push(callback) - } - /**Listen for when data is changed in this manager. */ - onChange(callback:ODManagerCallback){ - this.#changeListeners.push(callback) - } - /**Listen for when data is removed from this manager. */ - onRemove(callback:ODManagerCallback){ - this.#removeListeners.push(callback) - } -} - -/**## ODManagerWithSafety `class` - * This is an Open Ticket safe manager. - * - * It functions exactly the same as a normal `ODManager`, but it has 1 function extra! - * The `getSafe()` function will always return data, because when it doesn't find an id, it returns pre-configured backup data. - */ -export class ODManagerWithSafety extends ODManager { - /**The function that creates backup data returned in `getSafe()` when an id is missing in this manager. */ - #backupCreator: () => DataType - /** Temporary storage for manager debug name. */ - #debugname: string - - constructor(backupCreator:() => DataType, debug?:ODDebugger, debugname?:string){ - super(debug,debugname) - this.#backupCreator = backupCreator - this.#debugname = debugname ?? "unknown" - } - - /**Get data that matches the `ODId`. Returns the backup data when not found. - * - * ### ⚠️ This should only be used when the data doesn't need to be written/edited - */ - getSafe(id:ODValidId): DataType { - const data = super.get(id) - if (!data){ - process.emit("uncaughtException",new ODSystemError("ODManagerWithSafety:getSafe(\""+id+"\") => Unknown Id => Used backup data ("+this.#debugname+" manager)")) - return this.#backupCreator() - } - else return data - } -} - -/**## ODVersionManager `class` - * A Open Ticket version manager. - * - * It is used to manage different `ODVersion`'s from the bot. You will use it to check which version of the bot is used. - */ -export class ODVersionManager extends ODManager { - constructor(){ - super() - } -} - -/**## ODVersion `class` - * This is an Open Ticket version. - * - * It has many features like comparing versions & checking if they are compatible. - * - * You can use it in your own plugin, but most of the time you will use it to check the Open Ticket version! - */ -export class ODVersion extends ODManagerData { - /**The first number of the version (example: `v1.2.3` => `1`) */ - primary: number - /**The second number of the version (example: `v1.2.3` => `2`) */ - secondary: number - /**The third number of the version (example: `v1.2.3` => `3`) */ - tertiary: number - - constructor(id:ODValidId, primary:number, secondary:number, tertiary:number){ - super(id) - if (typeof primary != "number") throw new ODSystemError("Invalid constructor parameter => primary:number") - if (typeof secondary != "number") throw new ODSystemError("Invalid constructor parameter => secondary:number") - if (typeof tertiary != "number") throw new ODSystemError("Invalid constructor parameter => tertiary:number") - - this.primary = primary - this.secondary = secondary - this.tertiary = tertiary - } - - /**Get the version from a string (also possible with `v` prefix) - * @example const version = api.ODVersion.fromString("id","v1.2.3") //creates version 1.2.3 - */ - static fromString(id:ODValidId, version:string){ - if (typeof id != "string" && !(id instanceof ODId)) throw new ODSystemError("Invalid function parameter => id:ODValidId") - if (typeof version != "string") throw new ODSystemError("Invalid function parameter => version:string") - - const versionCheck = (version.startsWith("v")) ? version.substring(1) : version - const splittedVersion = versionCheck.split(".") - - return new this(id,Number(splittedVersion[0]),Number(splittedVersion[1]),Number(splittedVersion[2])) - } - /**Get the version as a string (`noprefix:true` => with `v` prefix) - * @example - * new api.ODVersion(1,0,0).toString(false) //returns "v1.0.0" - * new api.ODVersion(1,0,0).toString(true) //returns "1.0.0" - */ - toString(noprefix?:boolean){ - const prefix = noprefix ? "" : "v" - return prefix+[this.primary,this.secondary,this.tertiary].join(".") - } - /**Compare this version with another version and returns the result: `higher`, `lower` or `equal` - * @example - * new api.ODVersion(1,0,0).compare(new api.ODVersion(1,2,0)) //returns "lower" - * new api.ODVersion(1,3,0).compare(new api.ODVersion(1,2,0)) //returns "higher" - * new api.ODVersion(1,2,0).compare(new api.ODVersion(1,2,0)) //returns "equal" - */ - compare(comparator:ODVersion): "higher"|"lower"|"equal" { - if (!(comparator instanceof ODVersion)) throw new ODSystemError("Invalid function parameter => comparator:ODVersion") - - if (this.primary < comparator.primary) return "lower" - else if (this.primary > comparator.primary) return "higher" - else { - if (this.secondary < comparator.secondary) return "lower" - else if (this.secondary > comparator.secondary) return "higher" - else { - if (this.tertiary < comparator.tertiary) return "lower" - else if (this.tertiary > comparator.tertiary) return "higher" - else return "equal" - } - } - } - /**Check if this version is included in the list - * @example - * const list = [ - * new api.ODVersion(1,0,0), - * new api.ODVersion(1,0,1), - * new api.ODVersion(1,0,2) - * ] - * new api.ODVersion(1,0,0).compatible(list) //returns true - * new api.ODVersion(1,0,1).compatible(list) //returns true - * new api.ODVersion(1,0,3).compatible(list) //returns false - */ - compatible(list:ODVersion[]): boolean { - if (!Array.isArray(list)) throw new ODSystemError("Invalid function parameter => list:ODVersion[]") - if (!list.every((v) => (v instanceof ODVersion))) throw new ODSystemError("Invalid function parameter => list:ODVersion[]") - - return list.some((v) => { - return (v.toString() === this.toString()) - }) - } - /**Check if this version is higher or equal to the provided `requirement`. */ - min(requirement:string|ODVersion){ - if (typeof requirement == "string") requirement = ODVersion.fromString("temp",requirement) - - //skip when primary version is higher or lower than current one. - if (this.primary < requirement.primary) return false - else if (this.primary > requirement.primary) return true - - //skip when secondary version is higher or lower than current one. - if (this.secondary < requirement.secondary) return false - else if (this.secondary > requirement.secondary) return true - - //skip when tertiary version is higher or lower than current one. - if (this.tertiary < requirement.tertiary) return false - else if (this.tertiary > requirement.tertiary) return true - - return true - } - /**Check if this version is lower or equal to the provided `requirement`. */ - max(requirement:string|ODVersion){ - if (typeof requirement == "string") requirement = ODVersion.fromString("temp",requirement) - - //skip when primary version is higher or lower than current one. - if (this.primary < requirement.primary) return true - else if (this.primary > requirement.primary) return false - - //skip when secondary version is higher or lower than current one. - if (this.secondary < requirement.secondary) return true - else if (this.secondary > requirement.secondary) return false - - //skip when tertiary version is higher or lower than current one. - if (this.tertiary < requirement.tertiary) return true - else if (this.tertiary > requirement.tertiary) return false - - return true - } - /**Check if this version is matches the major version (`vX.X`) of the provided `requirement`. */ - major(requirement:string|ODVersion){ - if (typeof requirement == "string") requirement = ODVersion.fromString("temp",requirement) - return (this.primary == requirement.primary && this.secondary == requirement.secondary) - } - /**Check if this version is matches the minor version (`vX.X.X`) of the provided `requirement`. */ - minor(requirement:string|ODVersion){ - if (typeof requirement == "string") requirement = ODVersion.fromString("temp",requirement) - return (this.primary == requirement.primary && this.secondary == requirement.secondary && this.tertiary == requirement.tertiary) - } -} - -/**## ODHTTPGetRequest `class` - * This is a class that can help you with creating simple HTTP GET requests. - * - * It works using the native node.js fetch() method. You can configure all options in the constructor! - * @example - * const request = new api.ODHTTPGetRequest("https://www.example.com/abc.txt",false,{}) - * - * const result = await request.run() - * result.body //the response body (string) - * result.status //the response code (number) - * result.response //the full response (object) - */ -export class ODHTTPGetRequest { - /**The url used in the request */ - url: string - /**The request config for additional options */ - config: RequestInit - /**Throw on error OR return http code 500 */ - throwOnError: boolean - - constructor(url:string,throwOnError:boolean,config?:RequestInit){ - if (typeof url != "string") throw new ODSystemError("Invalid constructor parameter => url:string") - if (typeof throwOnError != "boolean") throw new ODSystemError("Invalid constructor parameter => throwOnError:boolean") - if (typeof config != "undefined" && typeof config != "object") throw new ODSystemError("Invalid constructor parameter => config?:RequestInit") - - this.url = url - this.throwOnError = throwOnError - const newConfig = config ?? {} - newConfig.method = "GET" - if (newConfig.headers) Object.assign(newConfig.headers,{"User-Agent":"OpenDiscordBots-OpenTicket/4.1.3"}) - else newConfig.headers = {"User-Agent":"OpenDiscordBots-OpenTicket/4.1.3"} - this.config = newConfig - } - - /**Execute the GET request.*/ - run(): Promise<{status:number, body:string, response?:Response}> { - return new Promise(async (resolve,reject) => { - try{ - const response = await fetch(this.url,this.config) - resolve({ - status:response.status, - body:(await response.text()), - response:response - }) - }catch(err){ - if (this.throwOnError) return reject("[OPENTICKET ERROR]: ODHTTPGetRequest => Unknown fetch() error: "+err) - else return resolve({ - status:500, - body:"Open Ticket Error: Unknown fetch() error: "+err, - }) - } - }) - } -} - -/**## ODHTTPPostRequest `class` - * This is a class that can help you with creating simple HTTP POST requests. - * - * It works using the native node.js fetch() method. You can configure all options in the constructor! - * @example - * const request = new api.ODHTTPPostRequest("https://www.example.com/abc.txt",false,{}) - * - * const result = await request.run() - * result.body //the response body (string) - * result.status //the response code (number) - * result.response //the full response (object) - */ -export class ODHTTPPostRequest { - /**The url used in the request */ - url: string - /**The request config for additional options */ - config: RequestInit - /**Throw on error OR return http code 500 */ - throwOnError: boolean - - constructor(url:string,throwOnError:boolean,config?:RequestInit){ - if (typeof url != "string") throw new ODSystemError("Invalid constructor parameter => url:string") - if (typeof throwOnError != "boolean") throw new ODSystemError("Invalid constructor parameter => throwOnError:boolean") - if (typeof config != "undefined" && typeof config != "object") throw new ODSystemError("Invalid constructor parameter => config?:RequestInit") - - this.url = url - this.throwOnError = throwOnError - const newConfig = config ?? {} - newConfig.method = "POST" - if (newConfig.headers) Object.assign(newConfig.headers,{"User-Agent":"OpenDiscordBots-OpenTicket/4.1.3"}) - else newConfig.headers = {"User-Agent":"OpenDiscordBots-OpenTicket/4.1.3"} - this.config = newConfig - } - - /**Execute the POST request.*/ - run(): Promise<{status:number, body:string, response?:Response}> { - return new Promise(async (resolve,reject) => { - try{ - const response = await fetch(this.url,this.config) - resolve({ - status:response.status, - body:(await response.text()), - response:response - }) - }catch(err){ - if (this.throwOnError) return reject("[OPENTICKET ERROR]: ODHTTPPostRequest => Unknown fetch() error: "+err) - else return resolve({ - status:500, - body:"Open Ticket Error: Unknown fetch() error!", - }) - } - }) - } -} - -/**## ODEnvHelper `class` - * This is a utility class that helps you with reading the ENV. - * - * It has support for the built-in `process.env` & `.env` file - * @example - * const envHelper = new api.ODEnvHelper() - * - * const variableA = envHelper.getVariable("value-a") - * const variableB = envHelper.getVariable("value-b","dotenv") //only get from .env - * const variableA = envHelper.getVariable("value-c","env") //only get from process.env - */ -export class ODEnvHelper { - /**All variables found in the `.env` file */ - dotenv: object - /**All variables found in `process.env` */ - env: object - - constructor(customEnvPath?:string){ - if (typeof customEnvPath != "undefined" && typeof customEnvPath != "string") throw new ODSystemError("Invalid constructor parameter => customEnvPath?:string") - - const path = customEnvPath ? customEnvPath : ".env" - this.dotenv = fs.existsSync(path) ? this.#readDotEnv(fs.readFileSync(path)) : {} - this.env = process.env - } - - /**Get a variable from the env */ - getVariable(name:string,source?:"dotenv"|"env"): any|undefined { - if (typeof name != "string") throw new ODSystemError("Invalid function parameter => name:string") - if ((typeof source != "undefined" && typeof source != "string") || (source && !["env","dotenv"].includes(source))) throw new ODSystemError("Invalid function parameter => source:'dotenv'|'env'") - - if (source == "dotenv"){ - return this.dotenv[name] - }else if (source == "env"){ - return this.env[name] - }else{ - //when no source specified => .env has priority over process.env - if (this.dotenv[name]) return this.dotenv[name] - else return this.env[name] - } - } - - //THIS CODE IS COPIED FROM THE DODENV-LIB - //Repo: https://github.com/motdotla/dotenv - //Source: https://github.com/motdotla/dotenv/blob/master/lib/main.js#L12 - #readDotEnv(src:Buffer){ - const LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg - const obj = {} - - // Convert buffer to string - let lines = src.toString() - - // Convert line breaks to same format - lines = lines.replace(/\r\n?/mg, '\n') - - let match - while ((match = LINE.exec(lines)) != null) { - const key = match[1] - - // Default undefined or null to empty string - let value = (match[2] || '') - - // Remove whitespace - value = value.trim() - - // Check if double quoted - const maybeQuote = value[0] - - // Remove surrounding quotes - value = value.replace(/^(['"`])([\s\S]*)\1$/mg, '$2') - - // Expand newlines if double quoted - if (maybeQuote === '"') { - value = value.replace(/\\n/g, '\n') - value = value.replace(/\\r/g, '\r') - } - - // Add to object - obj[key] = value - } - return obj - } -} - -/**## ODSystemError `class` - * A wrapper for the node.js `Error` class that makes the error look better in the console! - * - * This wrapper is made for Open Ticket system errors! **It can only be used by Open Ticket itself!** - */ -export class ODSystemError extends Error { - /**This variable gets detected by the error handling system to know how to render it */ - _ODErrorType = "system" - - /**Create an `ODSystemError` directly from an `Error` class */ - static fromError(err:Error){ - err["_ODErrorType"] = "system" - return err as ODSystemError - } -} - -/**## ODPluginError `class` - * A wrapper for the node.js `Error` class that makes the error look better in the console! - * - * This wrapper is made for Open Ticket plugin errors! **It can only be used by plugins!** - */ -export class ODPluginError extends Error { - /**This variable gets detected by the error handling system to know how to render it */ - _ODErrorType = "plugin" - - /**Create an `ODPluginError` directly from an `Error` class */ - static fromError(err:Error){ - err["_ODErrorType"] = "plugin" - return err as ODPluginError - } -} - -/**Oh, what could this be `¯\_(ツ)_/¯` */ -export interface ODEasterEggs { - creator:string, - translators:string[] -} \ No newline at end of file diff --git a/src/core/api/modules/builder.ts b/src/core/api/modules/builder.ts deleted file mode 100644 index f864f2a..0000000 --- a/src/core/api/modules/builder.ts +++ /dev/null @@ -1,1554 +0,0 @@ -/////////////////////////////////////// -//BUILDER MODULE -/////////////////////////////////////// -import { ODId, ODValidButtonColor, ODValidId, ODSystemError, ODInterfaceWithPartialProperty, ODManagerWithSafety, ODManagerData } from "./base" -import * as discord from "discord.js" -import { ODWorkerManager, ODWorkerCallback, ODWorker } from "./worker" -import { ODDebugger } from "./console" - -/**## ODBuilderImplementation `class` - * This is an Open Ticket builder implementation. - * - * It is a basic implementation of the `ODWorkerManager` used by all `ODBuilder` classes. - * - * This class can't be used stand-alone & needs to be extended from! - */ -export class ODBuilderImplementation extends ODManagerData { - /**The manager that has all workers of this implementation */ - workers: ODWorkerManager - /**Cache a build or create it every time from scratch when this.build() gets executed. */ - allowCache: boolean = false - /**Did the build already got created/cached? */ - didCache: boolean = false - /**The cache of this build. */ - cache:BuildType|null = null - - constructor(id:ODValidId, callback?:ODWorkerCallback, priority?:number, callbackId?:ODValidId){ - super(id) - this.workers = new ODWorkerManager("ascending") - if (callback) this.workers.add(new ODWorker(callbackId ? callbackId : id,priority ?? 0,callback)) - } - - /**Set if caching is allowed */ - setCacheMode(allowed:boolean){ - this.allowCache = allowed - this.resetCache() - return this - } - /**Reset the current cache */ - resetCache(){ - this.cache = null - this.didCache = false - return this - } - /**Execute all workers & return the result. */ - async build(source:Source, params:Params): Promise { - throw new ODSystemError("Tried to build an unimplemented ODBuilderImplementation") - } -} - -/**## ODBuilderManager `class` - * This is an Open Ticket builder manager. - * - * It contains all Open Ticket builders. You can find messages, embeds, files & dropdowns, buttons & modals all here! - * - * Using the Open Ticket builder system has a few advantages compared to vanilla discord.js: - * - plugins can extend/edit messages - * - automatically reply on error - * - independent workers (with priority) - * - fail-safe design using try-catch - * - cache frequently used objects - * - get to know the source of the build request for a specific message, button, etc - * - And so much more! - */ -export class ODBuilderManager { - /**The manager for all button builders */ - buttons: ODButtonManager - /**The manager for all dropdown builders */ - dropdowns: ODDropdownManager - /**The manager for all file/attachment builders */ - files: ODFileManager - /**The manager for all embed builders */ - embeds: ODEmbedManager - /**The manager for all message builders */ - messages: ODMessageManager - /**The manager for all modal builders */ - modals: ODModalManager - - constructor(debug:ODDebugger){ - this.buttons = new ODButtonManager(debug) - this.dropdowns = new ODDropdownManager(debug) - this.files = new ODFileManager(debug) - this.embeds = new ODEmbedManager(debug) - this.messages = new ODMessageManager(debug) - this.modals = new ODModalManager(debug) - } -} - -/**## ODComponentBuildResult `interface` - * This interface contains the result from a built component (button/dropdown). This can be used in the `ODMessage` builder! - */ -export interface ODComponentBuildResult { - /**The id of this component (button or dropdown) */ - id:ODId, - /**The discord component or `\n` when it is a spacer between action rows */ - component:discord.MessageActionRowComponentBuilder|"\n"|null -} - -/**## ODButtonManager `class` - * This is an Open Ticket button manager. - * - * It contains all Open Ticket button builders. Here, you can add your own buttons or edit existing ones! - * - * It's recommended to use this system in combination with all the other Open Ticket builders! - */ -export class ODButtonManager extends ODManagerWithSafety> { - constructor(debug:ODDebugger){ - super(() => { - return new ODButton("opendiscord:unknown-button",(instance,params,source,cancel) => { - instance.setCustomId("od:unknown-button") - instance.setMode("button") - instance.setColor("red") - instance.setLabel("") - instance.setEmoji("✖") - instance.setDisabled(true) - cancel() - }) - },debug,"button") - } - - /**Get a newline component for buttons & dropdowns! */ - getNewLine(id:ODValidId): ODComponentBuildResult { - return { - id:new ODId(id), - component:"\n" - } - } -} - -/**## ODButtonData `interface` - * This interface contains the data to build a button. - */ -export interface ODButtonData { - /**The custom id of this button */ - customId:string, - /**The mode of this button */ - mode:"button"|"url", - /**The url for when the mode is set to "url" */ - url:string|null, - /**The button color */ - color:ODValidButtonColor|null, - /**The button label */ - label:string|null, - /**The button emoji */ - emoji:string|null, - /**Is the button disabled? */ - disabled:boolean -} - -/**## ODButtonInstance `class` - * This is an Open Ticket button instance. - * - * It contains all properties & functions to build a button! - */ -export class ODButtonInstance { - /**The current data of this button */ - data: ODButtonData = { - customId:"", - mode:"button", - url:null, - color:null, - label:null, - emoji:null, - disabled:false - } - - /**Set the custom id of this button */ - setCustomId(id:ODButtonData["customId"]){ - this.data.customId = id - return this - } - /**Set the mode of this button */ - setMode(mode:ODButtonData["mode"]){ - this.data.mode = mode - return this - } - /**Set the url of this button */ - setUrl(url:ODButtonData["url"]){ - this.data.url = url - return this - } - /**Set the color of this button */ - setColor(color:ODButtonData["color"]){ - this.data.color = color - return this - } - /**Set the label of this button */ - setLabel(label:ODButtonData["label"]){ - this.data.label = label - return this - } - /**Set the emoji of this button */ - setEmoji(emoji:ODButtonData["emoji"]){ - this.data.emoji = emoji - return this - } - /**Disable this button */ - setDisabled(disabled:ODButtonData["disabled"]){ - this.data.disabled = disabled - return this - } -} - -/**## ODButton `class` - * This is an Open Ticket button builder. - * - * With this class, you can create a button to use in a message. - * The only difference with normal buttons is that this one can be edited by Open Ticket plugins! - * - * This is possible by using "workers" or multiple functions that will be executed in priority order! - */ -export class ODButton extends ODBuilderImplementation { - /**Build this button & compile it for discord.js */ - async build(source:Source, params:Params): Promise { - if (this.didCache && this.cache && this.allowCache) return this.cache - - try { - //create instance - const instance = new ODButtonInstance() - - //wait for workers to finish - await this.workers.executeWorkers(instance,source,params) - - //create the discord.js button - const button = new discord.ButtonBuilder() - if (instance.data.mode == "button") button.setCustomId(instance.data.customId) - if (instance.data.mode == "url") button.setStyle(discord.ButtonStyle.Link) - else if (instance.data.color == "gray") button.setStyle(discord.ButtonStyle.Secondary) - else if (instance.data.color == "blue") button.setStyle(discord.ButtonStyle.Primary) - else if (instance.data.color == "green") button.setStyle(discord.ButtonStyle.Success) - else if (instance.data.color == "red") button.setStyle(discord.ButtonStyle.Danger) - if (instance.data.url) button.setURL(instance.data.url) - if (instance.data.label) button.setLabel(instance.data.label) - if (instance.data.emoji) button.setEmoji(instance.data.emoji) - if (instance.data.disabled) button.setDisabled(instance.data.disabled) - if (!instance.data.emoji && !instance.data.label) button.setLabel(instance.data.customId) - - this.cache = {id:this.id,component:button} - this.didCache = true - return {id:this.id,component:button} - }catch(err){ - process.emit("uncaughtException",new ODSystemError("ODButton:build(\""+this.id.value+"\") => Major Error (see next error)")) - process.emit("uncaughtException",err) - return {id:this.id,component:null} - } - } -} - -/**## ODQuickButton `class` - * This is an Open Ticket quick button builder. - * - * With this class, you can quickly create a button to use in a message. - * This quick button can be used by Open Ticket plugins instead of the normal builders to speed up the process! - * - * Because of the quick functionality, these buttons are less customisable by other plugins. - */ -export class ODQuickButton { - /**The id of this button. */ - id: ODId - /**The current data of this button */ - data: Partial - - constructor(id:ODValidId,data:Partial){ - this.id = new ODId(id) - this.data = data - } - - /**Build this button & compile it for discord.js */ - async build(): Promise { - try { - //create the discord.js button - const button = new discord.ButtonBuilder() - if (this.data.mode == "button" || (!this.data.mode && this.data.customId)) button.setCustomId(this.data.customId ?? "od:unknown-button") - if (this.data.mode == "url") button.setStyle(discord.ButtonStyle.Link) - else if (this.data.color == "gray") button.setStyle(discord.ButtonStyle.Secondary) - else if (this.data.color == "blue") button.setStyle(discord.ButtonStyle.Primary) - else if (this.data.color == "green") button.setStyle(discord.ButtonStyle.Success) - else if (this.data.color == "red") button.setStyle(discord.ButtonStyle.Danger) - else button.setStyle(discord.ButtonStyle.Secondary) - if (this.data.url) button.setURL(this.data.url) - if (this.data.label) button.setLabel(this.data.label) - if (this.data.emoji) button.setEmoji(this.data.emoji) - if (this.data.disabled) button.setDisabled(this.data.disabled) - if (!this.data.emoji && !this.data.label) button.setLabel(this.data.customId ?? "od:unknown-button") - - return {id:this.id,component:button} - }catch(err){ - process.emit("uncaughtException",new ODSystemError("ODQuickButton:build(\""+this.id.value+"\") => Major Error (see next error)")) - process.emit("uncaughtException",err) - return {id:this.id,component:null} - } - } -} - -/**## ODDropdownManager `class` - * This is an Open Ticket dropdown manager. - * - * It contains all Open Ticket dropdown builders. Here, you can add your own dropdowns or edit existing ones! - * - * It's recommended to use this system in combination with all the other Open Ticket builders! - */ -export class ODDropdownManager extends ODManagerWithSafety> { - constructor(debug:ODDebugger){ - super(() => { - return new ODDropdown("opendiscord:unknown-dropdown",(instance,params,source,cancel) => { - instance.setCustomId("od:unknown-dropdown") - instance.setType("string") - instance.setPlaceholder("❌ ") - instance.setDisabled(true) - instance.setOptions([ - {emoji:"❌",label:"",value:"error"} - ]) - cancel() - }) - },debug,"dropdown") - } - - /**Get a newline component for buttons & dropdowns! */ - getNewLine(id:ODValidId): ODComponentBuildResult { - return { - id:new ODId(id), - component:"\n" - } - } -} - -/**## ODDropdownData `interface` - * This interface contains the data to build a dropdown. - */ -export interface ODDropdownData { - /**The custom id of this dropdown */ - customId:string, - /**The type of this dropdown */ - type:"string"|"role"|"channel"|"user"|"mentionable", - /**The placeholder of this dropdown */ - placeholder:string|null, - /**The minimum amount of items to be selected in this dropdown */ - minValues:number|null, - /**The maximum amount of items to be selected in this dropdown */ - maxValues:number|null, - /**Is this dropdown disabled? */ - disabled:boolean, - /**Allowed channel types when the type is "channel" */ - channelTypes:discord.ChannelType[] - - /**The options when the type is "string" */ - options:discord.SelectMenuComponentOptionData[], - /**The options when the type is "user" */ - users:discord.User[], - /**The options when the type is "role" */ - roles:discord.Role[], - /**The options when the type is "channel" */ - channels:discord.Channel[], - /**The options when the type is "mentionable" */ - mentionables:(discord.User|discord.Role)[], -} - -/**## ODDropdownInstance `class` - * This is an Open Ticket dropdown instance. - * - * It contains all properties & functions to build a dropdown! - */ -export class ODDropdownInstance { - /**The current data of this dropdown */ - data: ODDropdownData = { - customId:"", - type:"string", - placeholder:null, - minValues:null, - maxValues:null, - disabled:false, - channelTypes:[], - - options:[], - users:[], - roles:[], - channels:[], - mentionables:[] - } - - /**Set the custom id of this dropdown */ - setCustomId(id:ODDropdownData["customId"]){ - this.data.customId = id - return this - } - /**Set the type of this dropdown */ - setType(type:ODDropdownData["type"]){ - this.data.type = type - return this - } - /**Set the placeholder of this dropdown */ - setPlaceholder(placeholder:ODDropdownData["placeholder"]){ - this.data.placeholder = placeholder - return this - } - /**Set the minimum amount of values in this dropdown */ - setMinValues(minValues:ODDropdownData["minValues"]){ - this.data.minValues = minValues - return this - } - /**Set the maximum amount of values ax this dropdown */ - setMaxValues(maxValues:ODDropdownData["maxValues"]){ - this.data.maxValues = maxValues - return this - } - /**Set the disabled of this dropdown */ - setDisabled(disabled:ODDropdownData["disabled"]){ - this.data.disabled = disabled - return this - } - /**Set the channel types of this dropdown */ - setChannelTypes(channelTypes:ODDropdownData["channelTypes"]){ - this.data.channelTypes = channelTypes - return this - } - /**Set the options of this dropdown (when `type == "string"`) */ - setOptions(options:ODDropdownData["options"]){ - this.data.options = options - return this - } - /**Set the users of this dropdown (when `type == "user"`) */ - setUsers(users:ODDropdownData["users"]){ - this.data.users = users - return this - } - /**Set the roles of this dropdown (when `type == "role"`) */ - setRoles(roles:ODDropdownData["roles"]){ - this.data.roles = roles - return this - } - /**Set the channels of this dropdown (when `type == "channel"`) */ - setChannels(channels:ODDropdownData["channels"]){ - this.data.channels = channels - return this - } - /**Set the mentionables of this dropdown (when `type == "mentionable"`) */ - setMentionables(mentionables:ODDropdownData["mentionables"]){ - this.data.mentionables = mentionables - return this - } -} - -/**## ODDropdown `class` - * This is an Open Ticket dropdown builder. - * - * With this class, you can create a dropdown to use in a message. - * The only difference with normal dropdowns is that this one can be edited by Open Ticket plugins! - * - * This is possible by using "workers" or multiple functions that will be executed in priority order! - */ -export class ODDropdown extends ODBuilderImplementation { - /**Build this dropdown & compile it for discord.js */ - async build(source:Source, params:Params): Promise { - if (this.didCache && this.cache && this.allowCache) return this.cache - - try{ - //create instance - const instance = new ODDropdownInstance() - - //wait for workers to finish - await this.workers.executeWorkers(instance,source,params) - - //create the discord.js dropdown - if (instance.data.type == "string"){ - const dropdown = new discord.StringSelectMenuBuilder() - dropdown.setCustomId(instance.data.customId) - dropdown.setOptions(...instance.data.options) - if (instance.data.placeholder) dropdown.setPlaceholder(instance.data.placeholder) - if (instance.data.minValues) dropdown.setMinValues(instance.data.minValues) - if (instance.data.maxValues) dropdown.setMaxValues(instance.data.maxValues) - if (instance.data.disabled) dropdown.setDisabled(instance.data.disabled) - - this.cache = {id:this.id,component:dropdown} - this.didCache = true - return {id:this.id,component:dropdown} - - }else if (instance.data.type == "user"){ - const dropdown = new discord.UserSelectMenuBuilder() - dropdown.setCustomId(instance.data.customId) - if (instance.data.users.length > 0) dropdown.setDefaultUsers(...instance.data.users.map((u) => u.id)) - if (instance.data.placeholder) dropdown.setPlaceholder(instance.data.placeholder) - if (instance.data.minValues) dropdown.setMinValues(instance.data.minValues) - if (instance.data.maxValues) dropdown.setMaxValues(instance.data.maxValues) - if (instance.data.disabled) dropdown.setDisabled(instance.data.disabled) - - this.cache = {id:this.id,component:dropdown} - this.didCache = true - return {id:this.id,component:dropdown} - - }else if (instance.data.type == "role"){ - const dropdown = new discord.RoleSelectMenuBuilder() - dropdown.setCustomId(instance.data.customId) - if (instance.data.roles.length > 0) dropdown.setDefaultRoles(...instance.data.roles.map((r) => r.id)) - if (instance.data.placeholder) dropdown.setPlaceholder(instance.data.placeholder) - if (instance.data.minValues) dropdown.setMinValues(instance.data.minValues) - if (instance.data.maxValues) dropdown.setMaxValues(instance.data.maxValues) - if (instance.data.disabled) dropdown.setDisabled(instance.data.disabled) - - this.cache = {id:this.id,component:dropdown} - this.didCache = true - return {id:this.id,component:dropdown} - - }else if (instance.data.type == "channel"){ - const dropdown = new discord.ChannelSelectMenuBuilder() - dropdown.setCustomId(instance.data.customId) - if (instance.data.channels.length > 0) dropdown.setDefaultChannels(...instance.data.channels.map((c) => c.id)) - if (instance.data.placeholder) dropdown.setPlaceholder(instance.data.placeholder) - if (instance.data.minValues) dropdown.setMinValues(instance.data.minValues) - if (instance.data.maxValues) dropdown.setMaxValues(instance.data.maxValues) - if (instance.data.disabled) dropdown.setDisabled(instance.data.disabled) - - this.cache = {id:this.id,component:dropdown} - this.didCache = true - return {id:this.id,component:dropdown} - - }else if (instance.data.type == "mentionable"){ - const dropdown = new discord.MentionableSelectMenuBuilder() - - const values: ({type:discord.SelectMenuDefaultValueType.User,id:string}|{type:discord.SelectMenuDefaultValueType.Role,id:string})[] = [] - instance.data.mentionables.forEach((m) => { - if (m instanceof discord.User){ - values.push({type:discord.SelectMenuDefaultValueType.User,id:m.id}) - }else{ - values.push({type:discord.SelectMenuDefaultValueType.Role,id:m.id}) - } - }) - - dropdown.setCustomId(instance.data.customId) - if (instance.data.mentionables.length > 0) dropdown.setDefaultValues(...values) - if (instance.data.placeholder) dropdown.setPlaceholder(instance.data.placeholder) - if (instance.data.minValues) dropdown.setMinValues(instance.data.minValues) - if (instance.data.maxValues) dropdown.setMaxValues(instance.data.maxValues) - if (instance.data.disabled) dropdown.setDisabled(instance.data.disabled) - - this.cache = {id:this.id,component:dropdown} - this.didCache = true - return {id:this.id,component:dropdown} - }else{ - throw new Error("Tried to build an ODDropdown with unknown type!") - } - }catch(err){ - process.emit("uncaughtException",new ODSystemError("ODDropdown:build(\""+this.id.value+"\") => Major Error (see next error)")) - process.emit("uncaughtException",err) - return {id:this.id,component:null} - } - } -} - -/**## ODQuickDropdown `class` - * This is an Open Ticket quick dropdown builder. - * - * With this class, you can quickly create a dropdown to use in a message. - * This quick dropdown can be used by Open Ticket plugins instead of the normal builders to speed up the process! - * - * Because of the quick functionality, these dropdowns are less customisable by other plugins. - */ -export class ODQuickDropdown { - /**The id of this dropdown. */ - id: ODId - /**The current data of this dropdown */ - data: Partial - - constructor(id:ODValidId,data:Partial){ - this.id = new ODId(id) - this.data = data - } - - /**Build this dropdown & compile it for discord.js */ - async build(): Promise { - try{ - //create the discord.js dropdown - if (this.data.type == "string"){ - if (!this.data.options) throw new ODSystemError("ODQuickDropdown:build(): "+this.id.value+" => Dropdown requires at least 1 option to be present.") - const dropdown = new discord.StringSelectMenuBuilder() - dropdown.setCustomId(this.data.customId ?? "od:unknown-dropdown") - dropdown.setOptions(...this.data.options) - if (this.data.placeholder) dropdown.setPlaceholder(this.data.placeholder) - if (this.data.minValues) dropdown.setMinValues(this.data.minValues) - if (this.data.maxValues) dropdown.setMaxValues(this.data.maxValues) - if (this.data.disabled) dropdown.setDisabled(this.data.disabled) - - return {id:this.id,component:dropdown} - - }else if (this.data.type == "user"){ - if (!this.data.users) throw new ODSystemError("ODQuickDropdown:build(): "+this.id.value+" => Dropdown requires at least 1 user option to be present.") - const dropdown = new discord.UserSelectMenuBuilder() - dropdown.setCustomId(this.data.customId ?? "od:unknown-dropdown") - if (this.data.users.length > 0) dropdown.setDefaultUsers(...this.data.users.map((u) => u.id)) - if (this.data.placeholder) dropdown.setPlaceholder(this.data.placeholder) - if (this.data.minValues) dropdown.setMinValues(this.data.minValues) - if (this.data.maxValues) dropdown.setMaxValues(this.data.maxValues) - if (this.data.disabled) dropdown.setDisabled(this.data.disabled) - - return {id:this.id,component:dropdown} - - }else if (this.data.type == "role"){ - if (!this.data.roles) throw new ODSystemError("ODQuickDropdown:build(): "+this.id.value+" => Dropdown requires at least 1 role option to be present.") - const dropdown = new discord.RoleSelectMenuBuilder() - dropdown.setCustomId(this.data.customId ?? "od:unknown-dropdown") - if (this.data.roles.length > 0) dropdown.setDefaultRoles(...this.data.roles.map((r) => r.id)) - if (this.data.placeholder) dropdown.setPlaceholder(this.data.placeholder) - if (this.data.minValues) dropdown.setMinValues(this.data.minValues) - if (this.data.maxValues) dropdown.setMaxValues(this.data.maxValues) - if (this.data.disabled) dropdown.setDisabled(this.data.disabled) - - return {id:this.id,component:dropdown} - - }else if (this.data.type == "channel"){ - if (!this.data.channels) throw new ODSystemError("ODQuickDropdown:build(): "+this.id.value+" => Dropdown requires at least 1 channel option to be present.") - const dropdown = new discord.ChannelSelectMenuBuilder() - dropdown.setCustomId(this.data.customId ?? "od:unknown-dropdown") - if (this.data.channels.length > 0) dropdown.setDefaultChannels(...this.data.channels.map((c) => c.id)) - if (this.data.placeholder) dropdown.setPlaceholder(this.data.placeholder) - if (this.data.minValues) dropdown.setMinValues(this.data.minValues) - if (this.data.maxValues) dropdown.setMaxValues(this.data.maxValues) - if (this.data.disabled) dropdown.setDisabled(this.data.disabled) - - return {id:this.id,component:dropdown} - - }else if (this.data.type == "mentionable"){ - if (!this.data.mentionables) throw new ODSystemError("ODQuickDropdown:build(): "+this.id.value+" => Dropdown requires at least 1 mentionable option to be present.") - const dropdown = new discord.MentionableSelectMenuBuilder() - - const values: ({type:discord.SelectMenuDefaultValueType.User,id:string}|{type:discord.SelectMenuDefaultValueType.Role,id:string})[] = [] - this.data.mentionables.forEach((m) => { - if (m instanceof discord.User){ - values.push({type:discord.SelectMenuDefaultValueType.User,id:m.id}) - }else{ - values.push({type:discord.SelectMenuDefaultValueType.Role,id:m.id}) - } - }) - - dropdown.setCustomId(this.data.customId ?? "od:unknown-dropdown") - if (this.data.mentionables.length > 0) dropdown.setDefaultValues(...values) - if (this.data.placeholder) dropdown.setPlaceholder(this.data.placeholder) - if (this.data.minValues) dropdown.setMinValues(this.data.minValues) - if (this.data.maxValues) dropdown.setMaxValues(this.data.maxValues) - if (this.data.disabled) dropdown.setDisabled(this.data.disabled) - - return {id:this.id,component:dropdown} - }else{ - throw new Error("Tried to build an ODQuickDropdown with unknown type!") - } - }catch(err){ - process.emit("uncaughtException",new ODSystemError("ODQuickDropdown:build(\""+this.id.value+"\") => Major Error (see next error)")) - process.emit("uncaughtException",err) - return {id:this.id,component:null} - } - } -} - -/**## ODFileManager `class` - * This is an Open Ticket file manager. - * - * It contains all Open Ticket file builders. Here, you can add your own files or edit existing ones! - * - * It's recommended to use this system in combination with all the other Open Ticket builders! - */ -export class ODFileManager extends ODManagerWithSafety> { - constructor(debug:ODDebugger){ - super(() => { - return new ODFile("opendiscord:unknown-file",(instance,params,source,cancel) => { - instance.setName("openticket_unknown-file.txt") - instance.setDescription("❌ ") - instance.setContents("Couldn't find file in registery `opendiscord.builders.files`") - cancel() - }) - },debug,"file") - } -} - -/**## ODFileData `interface` - * This interface contains the data to build a file. - */ -export interface ODFileData { - /**The file buffer, string or raw data */ - file:discord.BufferResolvable - /**The name of the file */ - name:string, - /**The description of the file */ - description:string|null, - /**Set the file to be a spoiler */ - spoiler:boolean -} - -/**## ODFileBuildResult `interface` - * This interface contains the result from a built file (attachment). This can be used in the `ODMessage` builder! - */ -export interface ODFileBuildResult { - /**The id of this file */ - id:ODId, - /**The discord file */ - file:discord.AttachmentBuilder|null -} - -/**## ODFileInstance `class` - * This is an Open Ticket file instance. - * - * It contains all properties & functions to build a file! - */ -export class ODFileInstance { - /**The current data of this file */ - data: ODFileData = { - file:"", - name:"file.txt", - description:null, - spoiler:false - } - - /**Set the file path of this attachment */ - setFile(file:string){ - this.data.file = file - return this - } - /**Set the file contents of this attachment */ - setContents(contents:string|Buffer){ - this.data.file = (typeof contents == "string") ? Buffer.from(contents) : contents - return this - } - /**Set the name of this attachment */ - setName(name:ODFileData["name"]){ - this.data.name = name - return this - } - /**Set the description of this attachment */ - setDescription(description:ODFileData["description"]){ - this.data.description = description - return this - } - /**Set this attachment to show as a spoiler */ - setSpoiler(spoiler:ODFileData["spoiler"]){ - this.data.spoiler = spoiler - return this - } -} - -/**## ODFile `class` - * This is an Open Ticket file builder. - * - * With this class, you can create a file to use in a message. - * The only difference with normal files is that this one can be edited by Open Ticket plugins! - * - * This is possible by using "workers" or multiple functions that will be executed in priority order! - */ -export class ODFile extends ODBuilderImplementation { - /**Build this attachment & compile it for discord.js */ - async build(source:Source, params:Params): Promise { - if (this.didCache && this.cache && this.allowCache) return this.cache - - try{ - //create instance - const instance = new ODFileInstance() - - //wait for workers to finish - await this.workers.executeWorkers(instance,source,params) - - //create the discord.js attachment - const file = new discord.AttachmentBuilder(instance.data.file) - file.setName(instance.data.name ? instance.data.name : "file.txt") - if (instance.data.description) file.setDescription(instance.data.description) - if (instance.data.spoiler) file.setSpoiler(instance.data.spoiler) - - - this.cache = {id:this.id,file} - this.didCache = true - return {id:this.id,file} - }catch(err){ - process.emit("uncaughtException",new ODSystemError("ODFile:build(\""+this.id.value+"\") => Major Error (see next error)")) - process.emit("uncaughtException",err) - return {id:this.id,file:null} - } - } -} - -/**## ODQuickFile `class` - * This is an Open Ticket quick file builder. - * - * With this class, you can quickly create a file to use in a message. - * This quick file can be used by Open Ticket plugins instead of the normal builders to speed up the process! - * - * Because of the quick functionality, these files are less customisable by other plugins. - */ -export class ODQuickFile { - /**The id of this file. */ - id: ODId - /**The current data of this file */ - data: Partial - - constructor(id:ODValidId,data:Partial){ - this.id = new ODId(id) - this.data = data - } - - /**Build this attachment & compile it for discord.js */ - async build(): Promise { - try{ - //create the discord.js attachment - const file = new discord.AttachmentBuilder(this.data.file ?? "") - file.setName(this.data.name ? this.data.name : "file.txt") - if (this.data.description) file.setDescription(this.data.description) - if (this.data.spoiler) file.setSpoiler(this.data.spoiler) - - return {id:this.id,file} - }catch(err){ - process.emit("uncaughtException",new ODSystemError("ODQuickFile:build(\""+this.id.value+"\") => Major Error (see next error)")) - process.emit("uncaughtException",err) - return {id:this.id,file:null} - } - } -} - -/**## ODEmbedManager `class` - * This is an Open Ticket embed manager. - * - * It contains all Open Ticket embed builders. Here, you can add your own embeds or edit existing ones! - * - * It's recommended to use this system in combination with all the other Open Ticket builders! - */ -export class ODEmbedManager extends ODManagerWithSafety> { - constructor(debug:ODDebugger){ - super(() => { - return new ODEmbed("opendiscord:unknown-embed",(instance,params,source,cancel) => { - instance.setFooter("opendiscord:unknown-embed") - instance.setColor("#ff0000") - instance.setTitle("❌ ") - instance.setDescription("Couldn't find embed in registery `opendiscord.builders.embeds`") - cancel() - }) - },debug,"embed") - } -} - -/**## ODEmbedData `interface` - * This interface contains the data to build an embed. - */ -export interface ODEmbedData { - /**The title of the embed */ - title:string|null, - /**The color of the embed */ - color:discord.ColorResolvable|string|null, - /**The url of the embed */ - url:string|null, - /**The description of the embed */ - description:string|null, - /**The author text of the embed */ - authorText:string|null, - /**The author image of the embed */ - authorImage:string|null, - /**The author url of the embed */ - authorUrl:string|null, - /**The footer text of the embed */ - footerText:string|null, - /**The footer image of the embed */ - footerImage:string|null, - /**The image of the embed */ - image:string|null, - /**The thumbnail of the embed */ - thumbnail:string|null, - /**The fields of the embed */ - fields:ODInterfaceWithPartialProperty[], - /**The timestamp of the embed */ - timestamp:number|Date|null -} - -/**## ODEmbedBuildResult `interface` - * This interface contains the result from a built embed. This can be used in the `ODMessage` builder! - */ -export interface ODEmbedBuildResult { - /**The id of this embed */ - id:ODId, - /**The discord embed */ - embed:discord.EmbedBuilder|null -} - -/**## ODEmbedInstance `class` - * This is an Open Ticket embed instance. - * - * It contains all properties & functions to build an embed! - */ -export class ODEmbedInstance { - /**The current data of this embed */ - data: ODEmbedData = { - title:null, - color:null, - url:null, - description:null, - authorText:null, - authorImage:null, - authorUrl:null, - footerText:null, - footerImage:null, - image:null, - thumbnail:null, - fields:[], - timestamp:null - } - - /**Set the title of this embed */ - setTitle(title:ODEmbedData["title"]){ - this.data.title = title - return this - } - /**Set the color of this embed */ - setColor(color:ODEmbedData["color"]){ - this.data.color = color - return this - } - /**Set the url of this embed */ - setUrl(url:ODEmbedData["url"]){ - this.data.url = url - return this - } - /**Set the description of this embed */ - setDescription(description:ODEmbedData["description"]){ - this.data.description = description - return this - } - /**Set the author of this embed */ - setAuthor(text:ODEmbedData["authorText"], image?:ODEmbedData["authorImage"], url?:ODEmbedData["authorUrl"]){ - this.data.authorText = text - this.data.authorImage = image ?? null - this.data.authorUrl = url ?? null - return this - } - /**Set the footer of this embed */ - setFooter(text:ODEmbedData["footerText"], image?:ODEmbedData["footerImage"]){ - this.data.footerText = text - this.data.footerImage = image ?? null - return this - } - /**Set the image of this embed */ - setImage(image:ODEmbedData["image"]){ - this.data.image = image - return this - } - /**Set the thumbnail of this embed */ - setThumbnail(thumbnail:ODEmbedData["thumbnail"]){ - this.data.thumbnail = thumbnail - return this - } - /**Set the fields of this embed */ - setFields(fields:ODEmbedData["fields"]){ - //TEMP CHECKS - fields.forEach((field,index) => { - if (field.value.length >= 1024) throw new ODSystemError("ODEmbed:setFields() => field "+index+" reached 1024 character limit!") - if (field.name.length >= 256) throw new ODSystemError("ODEmbed:setFields() => field "+index+" reached 256 name character limit!") - }) - - this.data.fields = fields - return this - } - /**Add fields to this embed */ - addFields(...fields:ODEmbedData["fields"]){ - //TEMP CHECKS - fields.forEach((field,index) => { - if (field.value.length >= 1024) throw new ODSystemError("ODEmbed:addFields() => field "+index+" reached 1024 character limit!") - if (field.name.length >= 256) throw new ODSystemError("ODEmbed:addFields() => field "+index+" reached 256 name character limit!") - }) - - this.data.fields.push(...fields) - return this - } - /**Clear all fields from this embed */ - clearFields(){ - this.data.fields = [] - return this - } - /**Set the timestamp of this embed */ - setTimestamp(timestamp:ODEmbedData["timestamp"]){ - this.data.timestamp = timestamp - return this - } -} - -/**## ODEmbed `class` - * This is an Open Ticket embed builder. - * - * With this class, you can create a embed to use in a message. - * The only difference with normal embeds is that this one can be edited by Open Ticket plugins! - * - * This is possible by using "workers" or multiple functions that will be executed in priority order! - */ -export class ODEmbed extends ODBuilderImplementation { - /**Build this embed & compile it for discord.js */ - async build(source:Source, params:Params): Promise { - if (this.didCache && this.cache && this.allowCache) return this.cache - - try{ - //create instance - const instance = new ODEmbedInstance() - - //wait for workers to finish - await this.workers.executeWorkers(instance,source,params) - - //create the discord.js embed - const embed = new discord.EmbedBuilder() - if (instance.data.title) embed.setTitle(instance.data.title) - if (instance.data.color) embed.setColor(instance.data.color as discord.ColorResolvable) - if (instance.data.url) embed.setURL(instance.data.url) - if (instance.data.description) embed.setDescription(instance.data.description) - if (instance.data.authorText) embed.setAuthor({ - name:instance.data.authorText, - iconURL:instance.data.authorImage ?? undefined, - url:instance.data.authorUrl ?? undefined - }) - if (instance.data.footerText) embed.setFooter({ - text:instance.data.footerText, - iconURL:instance.data.footerImage ?? undefined, - }) - if (instance.data.image) embed.setImage(instance.data.image) - if (instance.data.thumbnail) embed.setThumbnail(instance.data.thumbnail) - if (instance.data.timestamp) embed.setTimestamp(instance.data.timestamp) - if (instance.data.fields.length > 0) embed.setFields(instance.data.fields) - - this.cache = {id:this.id,embed} - this.didCache = true - return {id:this.id,embed} - }catch(err){ - process.emit("uncaughtException",new ODSystemError("ODEmbed:build(\""+this.id.value+"\") => Major Error (see next error)")) - process.emit("uncaughtException",err) - return {id:this.id,embed:null} - } - } -} - -/**## ODQuickEmbed `class` - * This is an Open Ticket quick embed builder. - * - * With this class, you can quickly create a embed to use in a message. - * This quick embed can be used by Open Ticket plugins instead of the normal builders to speed up the process! - * - * Because of the quick functionality, these embeds are less customisable by other plugins. - */ -export class ODQuickEmbed { - /**The id of this embed. */ - id: ODId - /**The current data of this embed */ - data: Partial - - constructor(id:ODValidId,data:Partial){ - this.id = new ODId(id) - this.data = data - } - - /**Build this embed & compile it for discord.js */ - async build(): Promise { - try{ - //create the discord.js embed - const embed = new discord.EmbedBuilder() - if (this.data.title) embed.setTitle(this.data.title) - if (this.data.color) embed.setColor(this.data.color as discord.ColorResolvable) - if (this.data.url) embed.setURL(this.data.url) - if (this.data.description) embed.setDescription(this.data.description) - if (this.data.authorText) embed.setAuthor({ - name:this.data.authorText, - iconURL:this.data.authorImage ?? undefined, - url:this.data.authorUrl ?? undefined - }) - if (this.data.footerText) embed.setFooter({ - text:this.data.footerText, - iconURL:this.data.footerImage ?? undefined, - }) - if (this.data.image) embed.setImage(this.data.image) - if (this.data.thumbnail) embed.setThumbnail(this.data.thumbnail) - if (this.data.timestamp) embed.setTimestamp(this.data.timestamp) - if (this.data.fields && this.data.fields.length > 0) embed.setFields(this.data.fields) - - return {id:this.id,embed} - }catch(err){ - process.emit("uncaughtException",new ODSystemError("ODQuickEmbed:build(\""+this.id.value+"\") => Major Error (see next error)")) - process.emit("uncaughtException",err) - return {id:this.id,embed:null} - } - } -} - -/**## ODMessageManager `class` - * This is an Open Ticket message manager. - * - * It contains all Open Ticket message builders. Here, you can add your own messages or edit existing ones! - * - * It's recommended to use this system in combination with all the other Open Ticket builders! - */ -export class ODMessageManager extends ODManagerWithSafety> { - constructor(debug:ODDebugger){ - super(() => { - return new ODMessage("opendiscord:unknown-message",(instance,params,source,cancel) => { - instance.setContent("**❌ **\nCouldn't find message in registery `opendiscord.builders.messages`") - cancel() - }) - },debug,"message") - } -} - -/**## ODMessageData `interface` - * This interface contains the data to build a message. - */ -export interface ODMessageData { - /**The content of this message. `null` when no content */ - content:string|null, - /**Poll data for this message */ - poll:discord.PollData|null, - /**Try to make this message ephemeral when available */ - ephemeral:boolean, - - /**Embeds from this message */ - embeds:ODEmbedBuildResult[], - /**Components from this message */ - components:ODComponentBuildResult[], - /**Files from this message */ - files:ODFileBuildResult[], - - /**Additional options that aren't covered by the Open Ticket api!*/ - additionalOptions:Omit -} - -/**## ODMessageBuildResult `interface` - * This interface contains the result from a built message. This can be sent in a discord channel! - */ -export interface ODMessageBuildResult { - /**The id of this message */ - id:ODId, - /**The discord message */ - message:Omit, - /**When enabled, the bot will try to send this as an ephemeral message */ - ephemeral:boolean -} - -/**## ODMessageBuildSentResult `interface` - * This interface contains the result from a sent built message. This can be used to edit, view & save the message that got created. - */ -export interface ODMessageBuildSentResult { - /**Did the message get sent successfully? */ - success:boolean, - /**The message that got sent. */ - message:discord.Message|null -} - -/**## ODMessageInstance `class` - * This is an Open Ticket message instance. - * - * It contains all properties & functions to build a message! - */ -export class ODMessageInstance { - /**The current data of this message */ - data: ODMessageData = { - content:null, - poll:null, - ephemeral:false, - embeds:[], - components:[], - files:[], - additionalOptions:{} - } - - /**Set the content of this message */ - setContent(content:ODMessageData["content"]){ - this.data.content = content - return this - } - /**Set the poll of this message */ - setPoll(poll:ODMessageData["poll"]){ - this.data.poll = poll - return this - } - /**Make this message ephemeral when possible */ - setEphemeral(ephemeral:ODMessageData["ephemeral"]){ - this.data.ephemeral = ephemeral - return this - } - /**Set the embeds of this message */ - setEmbeds(...embeds:ODEmbedBuildResult[]){ - this.data.embeds = embeds - return this - } - /**Add an embed to this message! */ - addEmbed(embed:ODEmbedBuildResult){ - this.data.embeds.push(embed) - return this - } - /**Remove an embed from this message */ - removeEmbed(id:ODValidId){ - const index = this.data.embeds.findIndex((embed) => embed.id.value === new ODId(id).value) - if (index > -1) this.data.embeds.splice(index,1) - return this - } - /**Get an embed from this message */ - getEmbed(id:ODValidId){ - const embed = this.data.embeds.find((embed) => embed.id.value === new ODId(id).value) - if (embed) return embed.embed - else return null - } - /**Set the components of this message */ - setComponents(...components:ODComponentBuildResult[]){ - this.data.components = components - return this - } - /**Add a component to this message! */ - addComponent(component:ODComponentBuildResult){ - this.data.components.push(component) - return this - } - /**Remove a component from this message */ - removeComponent(id:ODValidId){ - const index = this.data.components.findIndex((component) => component.id.value === new ODId(id).value) - if (index > -1) this.data.components.splice(index,1) - return this - } - /**Get a component from this message */ - getComponent(id:ODValidId){ - const component = this.data.components.find((component) => component.id.value === new ODId(id).value) - if (component) return component.component - else return null - } - /**Set the files of this message */ - setFiles(...files:ODFileBuildResult[]){ - this.data.files = files - return this - } - /**Add a file to this message! */ - addFile(file:ODFileBuildResult){ - this.data.files.push(file) - return this - } - /**Remove a file from this message */ - removeFile(id:ODValidId){ - const index = this.data.files.findIndex((file) => file.id.value === new ODId(id).value) - if (index > -1) this.data.files.splice(index,1) - return this - } - /**Get a file from this message */ - getFile(id:ODValidId){ - const file = this.data.files.find((file) => file.id.value === new ODId(id).value) - if (file) return file.file - else return null - } -} - -/**## ODMessage `class` - * This is an Open Ticket message builder. - * - * With this class, you can create a message to send in a discord channel. - * The only difference with normal messages is that this one can be edited by Open Ticket plugins! - * - * This is possible by using "workers" or multiple functions that will be executed in priority order! - */ -export class ODMessage extends ODBuilderImplementation { - /**Build this message & compile it for discord.js */ - async build(source:Source, params:Params){ - if (this.didCache && this.cache && this.allowCache) return this.cache - - //create instance - const instance = new ODMessageInstance() - - //wait for workers to finish - await this.workers.executeWorkers(instance,source,params) - - //create the discord.js message - const componentArray: discord.ActionRowBuilder[] = [] - let currentRow: discord.ActionRowBuilder = new discord.ActionRowBuilder() - instance.data.components.forEach((c) => { - //return when component crashed - if (c.component == null) return - else if (c.component == "\n"){ - //create new current row when required - if (currentRow.components.length > 0){ - componentArray.push(currentRow) - currentRow = new discord.ActionRowBuilder() - } - }else if (c.component instanceof discord.BaseSelectMenuBuilder){ - //push current row when not empty - if (currentRow.components.length > 0){ - componentArray.push(currentRow) - currentRow = new discord.ActionRowBuilder() - } - currentRow.addComponents(c.component) - //create new current row after dropdown - componentArray.push(currentRow) - currentRow = new discord.ActionRowBuilder() - }else{ - //push button to current row - currentRow.addComponents(c.component) - } - - //create new row when 5 rows in length - if (currentRow.components.length == 5){ - componentArray.push(currentRow) - currentRow = new discord.ActionRowBuilder() - } - }) - //push final row to array - if (currentRow.components.length > 0) componentArray.push(currentRow) - - const filteredEmbeds = instance.data.embeds.map((e) => e.embed).filter((e) => e instanceof discord.EmbedBuilder) as discord.EmbedBuilder[] - const filteredFiles = instance.data.files.map((f) => f.file).filter((f) => f instanceof discord.AttachmentBuilder) as discord.AttachmentBuilder[] - - const message : discord.MessageCreateOptions = { - content:instance.data.content ?? "", - poll:instance.data.poll ?? undefined, - embeds:filteredEmbeds, - components:componentArray, - files:filteredFiles - } - - let result = {id:this.id,message,ephemeral:instance.data.ephemeral} - - Object.assign(result.message,instance.data.additionalOptions) - - this.cache = result - this.didCache = true - return result - } -} - -/**## ODQuickMessage `class` - * This is an Open Ticket quick message builder. - * - * With this class, you can quickly create a message to send in a discord channel. - * This quick message can be used by Open Ticket plugins instead of the normal builders to speed up the process! - * - * Because of the quick functionality, these messages are less customisable by other plugins. - */ -export class ODQuickMessage { - /**The id of this message. */ - id: ODId - /**The current data of this message. */ - data: Partial - - constructor(id:ODValidId,data:Partial){ - this.id = new ODId(id) - this.data = data - } - - /**Build this message & compile it for discord.js */ - async build(): Promise { - //create the discord.js message - const componentArray: discord.ActionRowBuilder[] = [] - let currentRow: discord.ActionRowBuilder = new discord.ActionRowBuilder() - this.data.components?.forEach((c) => { - //return when component crashed - if (c.component == null) return - else if (c.component == "\n"){ - //create new current row when required - if (currentRow.components.length > 0){ - componentArray.push(currentRow) - currentRow = new discord.ActionRowBuilder() - } - }else if (c.component instanceof discord.BaseSelectMenuBuilder){ - //push current row when not empty - if (currentRow.components.length > 0){ - componentArray.push(currentRow) - currentRow = new discord.ActionRowBuilder() - } - currentRow.addComponents(c.component) - //create new current row after dropdown - componentArray.push(currentRow) - currentRow = new discord.ActionRowBuilder() - }else{ - //push button to current row - currentRow.addComponents(c.component) - } - - //create new row when 5 rows in length - if (currentRow.components.length == 5){ - componentArray.push(currentRow) - currentRow = new discord.ActionRowBuilder() - } - }) - //push final row to array - if (currentRow.components.length > 0) componentArray.push(currentRow) - - const filteredEmbeds = (this.data.embeds?.map((e) => e.embed).filter((e) => e instanceof discord.EmbedBuilder) as discord.EmbedBuilder[]) ?? [] - const filteredFiles = (this.data.files?.map((f) => f.file).filter((f) => f instanceof discord.AttachmentBuilder) as discord.AttachmentBuilder[]) ?? [] - - const message : discord.MessageCreateOptions = { - content:this.data.content ?? "", - poll:this.data.poll ?? undefined, - embeds:filteredEmbeds, - components:componentArray, - files:filteredFiles - } - - let result = {id:this.id,message,ephemeral:this.data.ephemeral ?? false} - - Object.assign(result.message,this.data.additionalOptions) - return result - } -} - -/**## ODModalManager `class` - * This is an Open Ticket modal manager. - * - * It contains all Open Ticket modal builders. Here, you can add your own modals or edit existing ones! - * - * It's recommended to use this system in combination with all the other Open Ticket builders! - */ -export class ODModalManager extends ODManagerWithSafety> { - constructor(debug:ODDebugger){ - super(() => { - return new ODModal("opendiscord:unknown-modal",(instance,params,source,cancel) => { - instance.setCustomId("od:unknown-modal") - instance.setTitle("❌ ") - instance.setQuestions( - { - style:"short", - customId:"error", - label:"error", - placeholder:"Contact the bot creator for more info!" - } - ) - cancel() - }) - },debug,"modal") - } -} - -/**## ODModalDataQuestion `interface` - * This interface contains the data to build a modal question. - */ -export interface ODModalDataQuestion { - /**The style of this modal question */ - style:"short"|"paragraph", - /**The custom id of this modal question */ - customId:string - /**The label of this modal question */ - label?:string, - /**The min length of this modal question */ - minLength?:number, - /**The max length of this modal question */ - maxLength?:number, - /**Is this modal question required? */ - required?:boolean, - /**The placeholder of this modal question */ - placeholder?:string, - /**The initial value of this modal question */ - value?:string -} - -/**## ODModalData `interface` - * This interface contains the data to build a modal. - */ -export interface ODModalData { - /**The custom id of this modal */ - customId:string, - /**The title of this modal */ - title:string|null, - /**The collection of questions in this modal */ - questions:ODModalDataQuestion[], -} - -/**## ODModalBuildResult `interface` - * This interface contains the result from a built modal (form). This can be used in the `ODMessage` builder! - */ -export interface ODModalBuildResult { - /**The id of this modal */ - id:ODId, - /**The discord modal */ - modal:discord.ModalBuilder -} - -/**## ODModalInstance `class` - * This is an Open Ticket modal instance. - * - * It contains all properties & functions to build a modal! - */ -export class ODModalInstance { - /**The current data of this modal */ - data: ODModalData = { - customId:"", - title:null, - questions:[] - } - - /**Set the custom id of this modal */ - setCustomId(customId:ODModalData["customId"]){ - this.data.customId = customId - return this - } - /**Set the title of this modal */ - setTitle(title:ODModalData["title"]){ - this.data.title = title - return this - } - /**Set the questions of this modal */ - setQuestions(...questions:ODModalData["questions"]){ - this.data.questions = questions - return this - } - /**Add a question to this modal! */ - addQuestion(question:ODModalDataQuestion){ - this.data.questions.push(question) - return this - } - /**Remove a question from this modal */ - removeQuestion(customId:string){ - const index = this.data.questions.findIndex((question) => question.customId === customId) - if (index > -1) this.data.questions.splice(index,1) - return this - } - /**Get a question from this modal */ - getQuestion(customId:string){ - const question = this.data.questions.find((question) => question.customId === customId) - if (question) return question - else return null - } -} - -/**## ODModal `class` - * This is an Open Ticket modal builder. - * - * With this class, you can create a modal to use as response in interactions. - * The only difference with normal modals is that this one can be edited by Open Ticket plugins! - * - * This is possible by using "workers" or multiple functions that will be executed in priority order! - */ -export class ODModal extends ODBuilderImplementation { - /**Build this modal & compile it for discord.js */ - async build(source:Source, params:Params){ - if (this.didCache && this.cache && this.allowCache) return this.cache - - //create instance - const instance = new ODModalInstance() - - //wait for workers to finish - await this.workers.executeWorkers(instance,source,params) - - //create the discord.js modal - const modal = new discord.ModalBuilder() - modal.setCustomId(instance.data.customId) - if (instance.data.title) modal.setTitle(instance.data.title) - else modal.setTitle(instance.data.customId) - - instance.data.questions.forEach((question) => { - const input = new discord.TextInputBuilder() - .setStyle(question.style == "paragraph" ? discord.TextInputStyle.Paragraph : discord.TextInputStyle.Short) - .setCustomId(question.customId) - .setLabel(question.label ? question.label : question.customId) - .setRequired(question.required ? true : false) - - if (question.minLength) input.setMinLength(question.minLength) - if (question.maxLength) input.setMaxLength(question.maxLength) - if (question.value) input.setValue(question.value) - if (question.placeholder) input.setPlaceholder(question.placeholder) - - modal.addComponents( - new discord.ActionRowBuilder() - .addComponents(input) - ) - }) - - this.cache = {id:this.id,modal} - this.didCache = true - return {id:this.id,modal} - } -} \ No newline at end of file diff --git a/src/core/api/modules/checker.ts b/src/core/api/modules/checker.ts deleted file mode 100644 index ceb2e84..0000000 --- a/src/core/api/modules/checker.ts +++ /dev/null @@ -1,1549 +0,0 @@ -/////////////////////////////////////// -//CONFIG CHECKER MODULE -/////////////////////////////////////// -import { ODDiscordIdType, ODId, ODManager, ODManagerData, ODValidId, ODValidJsonType } from "./base" -import { ODConfig } from "./config" -import { ODLanguageManager } from "./language" -import { ODDebugger } from "./console" - -/**## ODCheckerResult `interface` - * This interface is the result from a config checker check() function. - */ -export interface ODCheckerResult { - valid:boolean - messages:ODCheckerMessage[] -} - -/**## ODCheckerManager `class` - * This is an Open Ticket checker manager. - * - * It manages all config checkers in the bot and allows plugins to access config checkers from Open Ticket & other plugins! - * - * You can use this class to get/add a config checker (`ODChecker`) in your plugin! - */ -export class ODCheckerManager extends ODManager { - /**The global temporary storage shared between all config checkers. */ - storage: ODCheckerStorage - /**The class responsible for rendering the config checker report. */ - renderer: ODCheckerRenderer - /**The class responsible for translating the config checker report. */ - translation: ODCheckerTranslationRegister - /**Final functions are global functions executed just before the report is created. */ - functions: ODCheckerFunctionManager - /**A variable containing the last result returned from `checkAll()` */ - lastResult: ODCheckerResult|null = null - - constructor(debug:ODDebugger, storage:ODCheckerStorage, renderer:ODCheckerRenderer, translation:ODCheckerTranslationRegister, functions:ODCheckerFunctionManager){ - super(debug,"config checker") - this.storage = storage - this.renderer = renderer - this.translation = translation - this.functions = functions - } - /**Check all config checkers registered in this manager.*/ - checkAll(sort:boolean): ODCheckerResult { - this.storage.reset() - - let isValid = true - const final: ODCheckerMessage[] = [] - - const checkers = this.getAll() - checkers.sort((a,b) => b.priority-a.priority) - - checkers.forEach((checker) => { - const res = checker.check() - final.push(...res.messages) - - if (!res.valid) isValid = false - }) - - this.functions.getAll().forEach((func) => { - const res = func.func(this,this.functions) - final.push(...res.messages) - - if (!res.valid) isValid = false - }) - - //sort messages => (info, warning, error) - if (sort) final.sort((a,b) => { - const typeA = (a.type == "error") ? 2 : (a.type == "warning") ? 1 : 0 - const typeB = (b.type == "error") ? 2 : (b.type == "warning") ? 1 : 0 - - return typeA-typeB - }) - - this.lastResult = { - valid:isValid, - messages:final - } - - return { - valid:isValid, - messages:final - } - } - /**Create temporary and unlisted `ODConfig`, `ODChecker` & `ODCheckerStorage` classes. This will help you use a `ODCheckerStructure` validator without officially registering it in `opendiscord.checkers`. */ - createTemporaryCheckerEnvironment(){ - return new ODChecker("opendiscord:temporary-environment",new ODCheckerStorage(),0,new ODConfig("opendiscord:temporary-environment",{}),new ODCheckerStructure("opendiscord:temporary-environment",{})) - } -} - -/**## ODCheckerStorage `class` - * This is an Open Ticket checker storage. - * - * It stores temporary data to share between config checkers! - * (e.g. The `messages.json` needs to access the `"id"` from `options.json`) - * - * - * You can use this class when you create your own config checker implementation! (not required for using the built-in config checker) - */ -export class ODCheckerStorage { - /**This is the array that stores all the data. ❌ **(don't edit unless really needed!)***/ - storage: {source:ODId, key:string, value:any}[] = [] - - /**Get data from the database (`source` => id of `ODChecker`) */ - get(source:ODValidId, key:string): any|null { - const result = this.storage.find(d => (d.source.value == new ODId(source).value) && (d.key == key)) - return (result) ? result.value : null - } - /**Add data to the database (`source` => id of `ODChecker`). This function also overwrites existing data!*/ - set(source:ODValidId, key:string, value:any){ - const index = this.storage.findIndex(d => (d.source.value == new ODId(source).value) && (d.key == key)) - if (index > -1){ - //overwrite - this.storage[index] = { - source:new ODId(source), - key,value - } - return true - }else{ - this.storage.push({ - source:new ODId(source), - key,value - }) - return false - } - } - /**Delete data from the database (`source` => id of `ODChecker`) */ - delete(source:ODValidId, key:string){ - const index = this.storage.findIndex(d => (d.source.value == new ODId(source).value) && (d.key == key)) - if (index > -1){ - //delete - this.storage.splice(index,1) - return true - }else return false - } - - /**Reset the entire database */ - reset(){ - this.storage = [] - } -} - -/**## ODCheckerRenderer `class` - * This is an Open Ticket checker renderer. - * - * It's responsible for rendering the config checker result in the console. - * This class doesn't provide any components! You need to create them by extending this class - * - * You can use this class if you want to change how the config checker looks! - */ -export class ODCheckerRenderer { - /**Get all components */ - getComponents(compact:boolean, renderEmpty:boolean, translation:ODCheckerTranslationRegister, data:ODCheckerResult): string[] { - return [] - } - /**Render all components */ - render(components:string[]){ - if (components.length < 1) return - console.log("\n") - components.forEach((c) => { - console.log(c) - }) - console.log("\n") - } -} - -/**## ODCheckerTranslationRegister `class` - * This is an Open Ticket checker translation register. - * - * It's used to store & manage the translation for each message from the config checker! - * Most translations are stored by message id, but there are some exceptions like the additional text on the checker report. - * - * You can use this class if you want to translate your config checker messages! **This is optional & isn't required for the checker to work!** - */ -export class ODCheckerTranslationRegister { - /**This is the array that stores all the data. ❌ **(don't edit unless really needed!)***/ - #translations: {type:"message"|"other", id:string, translation:string}[] = [] - - /**Get the translation from a config checker message/sentence */ - get(type:"message"|"other", id:string): string|null { - const result = this.#translations.find(d => (d.id == id) && (d.type == type)) - return (result) ? result.translation : null - } - /**Set the translation for a config checker message/sentence. This function also overwrites existing translations!*/ - set(type:"message"|"other", id:string, translation:string){ - const index = this.#translations.findIndex(d => (d.id == id) && (d.type == type)) - if (index > -1){ - //overwrite - this.#translations[index] = {type,id,translation} - return true - }else{ - this.#translations.push({type,id,translation}) - return false - } - } - /**Delete the translation for a config checker message/sentence. */ - delete(type:"message"|"other", id:string){ - const index = this.#translations.findIndex(d => (d.id == id) && (d.type == type)) - if (index > -1){ - //delete - this.#translations.splice(index,1) - return true - }else return false - } - - /**Get all translations */ - getAll(){ - return this.#translations - } - - /**Insert the translation params into the text. */ - insertTranslationParams(text:string, translationParams:string[]){ - translationParams.forEach((value,index) => { - text = text.replace(`{${index}}`,value) - }) - return text - } - /**A shortcut to copy translations from the `ODLanguageManager` to `ODCheckerTranslationRegister` */ - quickTranslate(manager:ODLanguageManager, translationId:string, type:"other"|"message", id:string){ - const translation = manager.getTranslation(translationId) - if (translation) this.set(type,id,translation) - } -} - -/**## ODCheckerFunctionCallback `type` - * This is the function used in the `ODCheckerFunction` class. - */ -export type ODCheckerFunctionCallback = (manager:ODCheckerManager, functions:ODCheckerFunctionManager) => ODCheckerResult - -/**## ODCheckerFunction `class` - * This is an Open Ticket config checker function. - * - * It is a global function that will be executed after all config checkers. It can do additional checks for invalid/missing configurations. - * It's mostly used for things that need to be checked globally! - */ -export class ODCheckerFunction extends ODManagerData { - /**The function which will be executed globally after all config checkers. */ - func: ODCheckerFunctionCallback - - constructor(id:ODValidId, func:ODCheckerFunctionCallback){ - super(id) - this.func = func - } -} - -/**## ODCheckerFunctionManager `class` - * This is an Open Ticket config checker function manager. - * - * It manages all `ODCheckerFunction`'s and it has some extra shortcuts for frequently used methods. - */ -export class ODCheckerFunctionManager extends ODManager { - constructor(debug:ODDebugger){ - super(debug,"config checker function") - } - - /**A shortcut to create a warning, info or error message */ - createMessage(checkerId:ODValidId, id:ODValidId, filepath:string, type:"info"|"warning"|"error", message:string, locationTrace:ODCheckerLocationTrace, docs:string|null, translationParams:string[], locationId:ODId, locationDocs:string|null): ODCheckerMessage { - return { - checkerId:new ODId(checkerId), - messageId:new ODId(id), - locationId, - - type,message, - path:this.locationTraceToString(locationTrace), - filepath, - translationParams, - - messageDocs:docs, - locationDocs - } - } - /**Create a string from the location trace (path)*/ - locationTraceToString(trace:ODCheckerLocationTrace){ - const final: ODCheckerLocationTrace = [] - trace.forEach((t) => { - if (typeof t == "number"){ - final.push(`:${t}`) - }else{ - final.push(`."${t}"`) - } - }) - return final.join("").substring(1) - } - /**De-reference the locationTrace array. Use this before adding a value to the array*/ - locationTraceDeref(trace:ODCheckerLocationTrace): ODCheckerLocationTrace { - return JSON.parse(JSON.stringify(trace)) - } -} - -/**## ODCheckerLocationTrace `type` - * This type is an array of strings & numbers which represents the location trace from the config checker. - * It's used to generate a path to the error (e.g. `"abc"."efg".1."something"`) - */ -export type ODCheckerLocationTrace = (string|number)[] - -/**## ODCheckerOptions `interface` - * This interface contains all optional properties to customise in the `ODChecker` class. - */ -export interface ODCheckerOptions { - /**The name of this config in the Interactive Setup CLI. */ - cliDisplayName?:string - /**The description of this config in the Interactive Setup CLI. */ - cliDisplayDescription?:string -} - -/**## ODChecker `class` - * This is an Open Ticket config checker. - * - * It checks a specific config file for invalid/missing configurations. This data can then be used to show to the user what's wrong! - * You can check for example if a string is longer/shorter than a certain amount of characters & more! - * - * You can use this class when you create your own custom config file & you want to check it for syntax errors. - */ -export class ODChecker extends ODManagerData { - /**The storage of this checker (reference for `ODCheckerManager.storage`) */ - storage: ODCheckerStorage - /**The higher the priority, the faster it gets checked! */ - priority: number - /**The config file that needs to be checked */ - config: ODConfig - /**The structure of the config file */ - structure: ODCheckerStructure - /**Temporary storage for all error messages from the check() method (not recommended to use) */ - messages: ODCheckerMessage[] = [] - /**Temporary storage for the quit status from the check() method (not recommended to use) */ - quit: boolean = false - /**All additional properties of this config checker. */ - options: ODCheckerOptions - - constructor(id:ODValidId, storage: ODCheckerStorage, priority:number, config:ODConfig, structure:ODCheckerStructure, options?:ODCheckerOptions){ - super(id) - this.storage = storage - this.priority = priority - this.config = config - this.structure = structure - this.options = options ?? {} - } - - /**Get a human-readable number string. */ - #ordinalNumber(num:number){ - const i = Math.abs(Math.round(num)) - const cent = i % 100 - if (cent >= 10 && cent <= 20) return i+'th' - const dec = i % 10 - if (dec === 1) return i+'st' - if (dec === 2) return i+'nd' - if (dec === 3) return i+'rd' - return i+'th' - } - /**Run this checker. Returns all errors*/ - check(): ODCheckerResult { - this.messages = [] - this.quit = false - - this.structure.check(this,this.config.data,[]) - return { - valid:!this.quit, - messages:this.messages - } - } - /**Create a string from the location trace/path in a human readable format. */ - locationTraceToString(trace:ODCheckerLocationTrace){ - const final: ODCheckerLocationTrace = [] - trace.forEach((t) => { - if (typeof t == "number"){ - final.push(`:(${this.#ordinalNumber(t+1)})`) - }else{ - final.push(`."${t}"`) - } - }) - return final.join("").substring(1) - } - /**De-reference the locationTrace array. Use this before adding a value to the array*/ - locationTraceDeref(trace:ODCheckerLocationTrace): ODCheckerLocationTrace { - return JSON.parse(JSON.stringify(trace)) - } - - /**A shortcut to create a warning, info or error message */ - createMessage(id:ODValidId, type:"info"|"warning"|"error", message:string, locationTrace:ODCheckerLocationTrace, docs:string|null, translationParams:string[], locationId:ODId, locationDocs:string|null){ - if (type == "error") this.quit = true - this.messages.push({ - checkerId:this.id, - messageId:new ODId(id), - locationId, - - type,message, - path:this.locationTraceToString(locationTrace), - filepath:this.config.path, - translationParams, - - messageDocs:docs, - locationDocs - }) - } -} - -/**## ODCheckerMessage `interface` - * This interface is an object which has all variables required for a config checker message! - */ -export interface ODCheckerMessage { - checkerId:ODId, - messageId:ODId, - locationId:ODId, - - type:"info"|"warning"|"error", - message:string, - path:string, - filepath:string, - translationParams:string[], - - messageDocs:string|null, - locationDocs:string|null -} - -/**## ODCheckerStructureOptions `interface` - * This interface has the basic options for the `ODCheckerStructure`! - */ -export interface ODCheckerStructureOptions { - /**Add a custom checker function. Returns `true` when valid. */ - custom?:(checker:ODChecker, value:ODValidJsonType, locationTrace:ODCheckerLocationTrace, locationId:ODId, locationDocs:string|null) => boolean, - /**Set the url to the documentation of this variable. */ - docs?:string, - /**The name of this config in the Interactive Setup CLI. */ - cliDisplayName?:string - /**The description of this config in the Interactive Setup CLI. */ - cliDisplayDescription?:string - /**Hide the description of this config in the Interactive Setup CLI parent view/list. */ - cliHideDescriptionInParent?:boolean - /**The default value of this variable when creating it in the Interactive Setup CLI. When not specified, the user will be asked to insert a value. */ - cliInitDefaultValue?:ODValidJsonType -} - -/**## ODCheckerStructure `class` - * This is an Open Ticket config checker structure. - * - * This class will check for a single variable in a config file, customise it in the settings! - * If you want prebuilt checkers (for strings, booleans, numbers, ...), check the other `ODCheckerStructure`'s! - * - * **Not recommended to use!** It's recommended to extend from another `ODConfigCheckerStructure` class! - */ -export class ODCheckerStructure { - /**The id of this checker structure */ - id: ODId - /**The options for this checker structure */ - options: ODCheckerStructureOptions - - constructor(id:ODValidId, options:ODCheckerStructureOptions){ - this.id = new ODId(id) - this.options = options - } - - /**Check a variable if it matches all settings in this checker. This function is automatically executed by Open Ticket! */ - check(checker:ODChecker, value:ODValidJsonType, locationTrace:ODCheckerLocationTrace): boolean { - if (typeof this.options.custom != "undefined"){ - return this.options.custom(checker,value,locationTrace,this.id,(this.options.docs ?? null)) - }else return true - } -} - -/**## ODCheckerObjectStructureOptions `interface` - * This interface has the options for `ODCheckerObjectStructure`! - */ -export interface ODCheckerObjectStructureOptions extends ODCheckerStructureOptions { - /**Add a checker for a property in an object (can also be optional) */ - children:{key:string, priority?:number, optional?:boolean, cliHideInEditMode?:boolean, checker:ODCheckerStructure}[], - /**A list of keys to skip when creating this object with the Interactive Setup CLI. The default value of these properties will be used instead. */ - cliInitSkipKeys?:string[], - /**The key of a (primitive) property in this object to show the value of in the Interactive Setup CLI when listed in an array. */ - cliDisplayKeyInParentArray?:string, - /**A list of additional (primitive) property keys in this object to show the value of in the Interactive Setup CLI when listed in an array. */ - cliDisplayAdditionalKeysInParentArray?:string[] -} - -/**## ODCheckerObjectStructure `class` - * This is an Open Ticket config checker structure. - * - * This class will check for an object variable in a config file, customise it in the settings! - * A checker for the children can be set in the settings. - */ -export class ODCheckerObjectStructure extends ODCheckerStructure { - declare options: ODCheckerObjectStructureOptions - - constructor(id:ODValidId, options:ODCheckerObjectStructureOptions){ - super(id,options) - } - - check(checker:ODChecker, value:object, locationTrace:ODCheckerLocationTrace): boolean { - const lt = checker.locationTraceDeref(locationTrace) - - //check type & options - if (typeof value != "object"){ - checker.createMessage("opendiscord:invalid-type","error","This property needs to be the type: object!",lt,null,["object"],this.id,(this.options.docs ?? null)) - return false - } - - //sort children - if (typeof this.options.children == "undefined") return super.check(checker,value,locationTrace) - const sortedChildren = this.options.children.sort((a,b) => { - if ((a.priority ?? 0) < (b.priority ?? 0)) return -1 - else if ((a.priority ?? 0) > (b.priority ?? 0)) return 1 - else return 0 - }) - - //check children - let localQuit = false - sortedChildren.forEach((child) => { - const localLt = checker.locationTraceDeref(lt) - localLt.push(child.key) - - if (typeof value[child.key] == "undefined"){ - if (!child.optional){ - localQuit = true - checker.createMessage("opendiscord:property-missing","error",`The property "${child.key}" is mising from this object!`,lt,null,[`"${child.key}"`],this.id,(this.options.docs ?? null)) - }else{ - checker.createMessage("opendiscord:property-optional","info",`The property "${child.key}" is optional in this object!`,lt,null,[`"${child.key}"`],this.id,(this.options.docs ?? null)) - } - }else if (!child.checker.check(checker,value[child.key],localLt)) localQuit = true - }) - - //do local quit or check custom function - if (localQuit) return false - else return super.check(checker,value,locationTrace) - } -} - -/**## ODCheckerStringStructureOptions `interface` - * This interface has the options for `ODCheckerStringStructure`! - */ -export interface ODCheckerStringStructureOptions extends ODCheckerStructureOptions { - /**The minimum length of this string */ - minLength?:number, - /**The maximum length of this string */ - maxLength?:number, - /**Set the required length of this string */ - length?:number, - /**This string needs to start with ... */ - startsWith?:string, - /**This string needs to end with ... */ - endsWith?:string, - /**This string needs to contain ... */ - contains?:string, - /**This string is not allowed to contain ... */ - invertedContains?:string, - /**You need to choose between ... */ - choices?:string[], - /**This string needs to be in lowercase. */ - lowercaseOnly?:boolean, - /**This string needs to be in uppercase. */ - uppercaseOnly?:boolean, - /**This string shouldn't contain any special characters (allowed: A-Z, a-z, 0-9, space, a few punctuation marks, ...). */ - noSpecialCharacters?:boolean, - /**Do not allow any spaces in this string. */ - withoutSpaces?:boolean, - /**Give a warning when a sentence doesn't start with a capital letter. Or require every word to start with a capital letter. (Ignores numbers, unicode characters, ...) */ - capitalLetterWarning?:false|"sentence"|"word" - /**Give a warning when a sentence doesn't end with a punctuation letter (.,?!) */ - punctuationWarning?:boolean - /**The string needs to match this regex */ - regex?:RegExp, - /**Provide an optional list for autocomplete when using the Interactive Setup CLI. Defaults to the `choices` option. */ - cliAutocompleteList?:string[], - /**Dynamically provide a list for autocomplete items when using the Interactive Setup CLI. */ - cliAutocompleteFunc?:() => Promise -} - -/**## ODCheckerStringStructure `class` - * This is an Open Ticket config checker structure. - * - * This class will check for a string variable in a config file, customise it in the settings! - */ -export class ODCheckerStringStructure extends ODCheckerStructure { - declare options: ODCheckerStringStructureOptions - - constructor(id:ODValidId, options:ODCheckerStringStructureOptions){ - super(id,options) - } - - check(checker:ODChecker, value:string, locationTrace:ODCheckerLocationTrace): boolean { - const lt = checker.locationTraceDeref(locationTrace) - - //check type & options - if (typeof value != "string"){ - checker.createMessage("opendiscord:invalid-type","error","This property needs to be the type: string!",lt,null,["string"],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.minLength != "undefined" && value.length < this.options.minLength){ - checker.createMessage("opendiscord:string-too-short","error",`This string can't be shorter than ${this.options.minLength} characters!`,lt,null,[this.options.minLength.toString()],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.maxLength != "undefined" && value.length > this.options.maxLength){ - checker.createMessage("opendiscord:string-too-long","error",`This string can't be longer than ${this.options.maxLength} characters!`,lt,null,[this.options.maxLength.toString()],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.length != "undefined" && value.length !== this.options.length){ - checker.createMessage("opendiscord:string-length-invalid","error",`This string needs to be ${this.options.length} characters long!`,lt,null,[this.options.length.toString()],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.startsWith != "undefined" && !value.startsWith(this.options.startsWith)){ - checker.createMessage("opendiscord:string-starts-with","error",`This string needs to start with "${this.options.startsWith}"!`,lt,null,[`"${this.options.startsWith}"`],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.endsWith != "undefined" && !value.endsWith(this.options.endsWith)){ - checker.createMessage("opendiscord:string-ends-with","error",`This string needs to end with "${this.options.endsWith}"!`,lt,null,[`"${this.options.endsWith}"`],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.contains != "undefined" && !value.includes(this.options.contains)){ - checker.createMessage("opendiscord:string-contains","error",`This string needs to contain "${this.options.contains}"!`,lt,null,[`"${this.options.contains}"`],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.invertedContains != "undefined" && value.includes(this.options.invertedContains)){ - checker.createMessage("opendiscord:string-inverted-contains","error",`This string is not allowed to contain "${this.options.invertedContains}"!`,lt,null,[`"${this.options.invertedContains}"`],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.choices != "undefined" && !this.options.choices.includes(value)){ - checker.createMessage("opendiscord:string-choices","error",`This string can only be one of the following values: "${this.options.choices.join(`", "`)}"!`,lt,null,[`"${this.options.choices.join(`", "`)}"`],this.id,(this.options.docs ?? null)) - return false - }else if (this.options.lowercaseOnly && value !== value.toLowerCase()){ - checker.createMessage("opendiscord:string-lowercase","error",`This string must be written in lowercase only!`,lt,null,[],this.id,(this.options.docs ?? null)) - return false - }else if (this.options.uppercaseOnly && value !== value.toUpperCase()){ - checker.createMessage("opendiscord:string-uppercase","error",`This string must be written in uppercase only!`,lt,null,[],this.id,(this.options.docs ?? null)) - return false - }else if (this.options.noSpecialCharacters && !/^[A-Za-z0-9 ]*$/.test(value)){ - checker.createMessage("opendiscord:string-special-characters","error",`This string is not allowed to contain any special characters! (a-z, 0-9 & space only)`,lt,null,[],this.id,(this.options.docs ?? null)) - return false - }else if (this.options.withoutSpaces && value.includes(" ")){ - checker.createMessage("opendiscord:string-no-spaces","error",`This string is not allowed to contain spaces!`,lt,null,[],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.regex != "undefined" && !this.options.regex.test(value)){ - checker.createMessage("opendiscord:string-regex","error","This string is invalid!",lt,null,[],this.id,(this.options.docs ?? null)) - return false - }else{ - //warnings - if ((this.options.capitalLetterWarning == "word" && !value.split(" ").every((word) => word.length == 0 || /^[^a-z].*/.test(word)))) checker.createMessage("opendiscord:string-capital-word","warning",`It's recommended that each word in this string starts with a capital letter!`,lt,null,[],this.id,(this.options.docs ?? null)) - if ((this.options.capitalLetterWarning == "sentence" && !value.split(/ *[.?!] */).every((sentence) => sentence.length == 0 || /^[^a-z].*/.test(sentence)))) checker.createMessage("opendiscord:string-capital-sentence","warning",`It looks like some sentences in this string don't start with a capital letter!`,lt,null,[],this.id,(this.options.docs ?? null)) - if (this.options.punctuationWarning && value.length > 0 && (!value.endsWith(".") && !value.endsWith("?") && !value.endsWith("!") && !value.endsWith("'") && !value.endsWith('"') && !value.endsWith(",") && !value.endsWith(";") && !value.endsWith(":") && !value.endsWith("="))) checker.createMessage("opendiscord:string-punctuation","warning",`It looks like the sentence in this string doesn't end with a punctuation mark!`,lt,null,[],this.id,(this.options.docs ?? null)) - - return super.check(checker,value,locationTrace) - } - } -} - -/**## ODCheckerNumberStructureOptions `interface` - * This interface has the options for `ODCheckerNumberStructure`! - */ -export interface ODCheckerNumberStructureOptions extends ODCheckerStructureOptions { - /**Is `NaN` (not a number) allowed? (`false` by default) */ - nanAllowed?:boolean - /**The minimum length of this number */ - minLength?:number, - /**The maximum length of this number */ - maxLength?:number, - /**Set the required length of this number */ - length?:number, - /**The minimum value of this number */ - min?:number, - /**The maximum value of this number */ - max?:number, - /**This number is required to match the value */ - is?:number, - /**Only allow a multiple of ... starting at `this.offset` or 0 */ - step?:number, - /**The offset for the step function. */ - offset?:number, - /**This number needs to start with ... */ - startsWith?:string, - /**This number needs to end with ... */ - endsWith?:string, - /**This number needs to contain ... */ - contains?:string, - /**This number is not allowed to contain ... */ - invertedContains?:string, - /**You need to choose between ... */ - choices?:number[], - /**Are numbers with a decimal value allowed? */ - floatAllowed?:boolean, - /**Are negative numbers allowed (without zero) */ - negativeAllowed?:boolean, - /**Are positive numers allowed (without zero) */ - positiveAllowed?:boolean, - /**Is zero allowed? */ - zeroAllowed?:boolean -} - -/**## ODCheckerNumberStructure `class` - * This is an Open Ticket config checker structure. - * - * This class will check for a number variable in a config file, customise it in the settings! - */ -export class ODCheckerNumberStructure extends ODCheckerStructure { - declare options: ODCheckerNumberStructureOptions - - constructor(id:ODValidId, options:ODCheckerNumberStructureOptions){ - super(id,options) - } - - check(checker:ODChecker, value:number, locationTrace:ODCheckerLocationTrace): boolean { - const lt = checker.locationTraceDeref(locationTrace) - - //offset for step - const stepOffset = (typeof this.options.offset != "undefined") ? this.options.offset : 0 - - //check type & options - if (typeof value != "number"){ - checker.createMessage("opendiscord:invalid-type","error","This property needs to be the type: number!",lt,null,["number"],this.id,(this.options.docs ?? null)) - return false - }else if (!this.options.nanAllowed && isNaN(value)){ - checker.createMessage("opendiscord:number-nan","error",`This number can't be NaN (Not A Number)!`,lt,null,[],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.minLength != "undefined" && value.toString().length < this.options.minLength){ - checker.createMessage("opendiscord:number-too-short","error",`This number can't be shorter than ${this.options.minLength} characters!`,lt,null,[this.options.minLength.toString()],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.maxLength != "undefined" && value.toString().length > this.options.maxLength){ - checker.createMessage("opendiscord:number-too-long","error",`This number can't be longer than ${this.options.maxLength} characters!`,lt,null,[this.options.maxLength.toString()],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.length != "undefined" && value.toString().length !== this.options.length){ - checker.createMessage("opendiscord:number-length-invalid","error",`This number needs to be ${this.options.length} characters long!`,lt,null,[this.options.length.toString()],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.min != "undefined" && value < this.options.min){ - checker.createMessage("opendiscord:number-too-small","error",`This number needs to be at least ${this.options.min}!`,lt,null,[this.options.min.toString()],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.max != "undefined" && value > this.options.max){ - checker.createMessage("opendiscord:number-too-large","error",`This number needs to be at most ${this.options.max}!`,lt,null,[this.options.max.toString()],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.is != "undefined" && value == this.options.is){ - checker.createMessage("opendiscord:number-not-equal","error",`This number needs to be ${this.options.is}!`,lt,null,[this.options.is.toString()],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.step != "undefined" && ((value - stepOffset) % this.options.step) !== 0){ - if (stepOffset > 0) checker.createMessage("opendiscord:number-step-offset","error",`This number needs to be a multiple of ${this.options.step} starting with ${stepOffset}!`,lt,null,[this.options.step.toString(),stepOffset.toString()],this.id,(this.options.docs ?? null)) - else checker.createMessage("opendiscord:number-step","error",`This number needs to be a multiple of ${this.options.step}!`,lt,null,[this.options.step.toString()],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.startsWith != "undefined" && !value.toString().startsWith(this.options.startsWith)){ - checker.createMessage("opendiscord:number-starts-with","error",`This number needs to start with "${this.options.startsWith}"!`,lt,null,[`"${this.options.startsWith}"`],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.endsWith != "undefined" && !value.toString().endsWith(this.options.endsWith)){ - checker.createMessage("opendiscord:number-ends-with","error",`This number needs to end with "${this.options.endsWith}"!`,lt,null,[`"${this.options.endsWith}"`],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.contains != "undefined" && !value.toString().includes(this.options.contains)){ - checker.createMessage("opendiscord:number-contains","error",`This number needs to contain "${this.options.contains}"!`,lt,null,[`"${this.options.contains}"`],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.invertedContains != "undefined" && value.toString().includes(this.options.invertedContains)){ - checker.createMessage("opendiscord:number-inverted-contains","error",`This number is not allowed to contain "${this.options.invertedContains}"!`,lt,null,[`"${this.options.invertedContains}"`],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.choices != "undefined" && !this.options.choices.includes(value)){ - checker.createMessage("opendiscord:number-choices","error",`This number can only be one of the following values: "${this.options.choices.join(`", "`)}"!`,lt,null,[`"${this.options.choices.join(`", "`)}"`],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.floatAllowed != "undefined" && !this.options.floatAllowed && (value % 1) !== 0){ - checker.createMessage("opendiscord:number-float","error","This number can't be a decimal!",lt,null,[],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.negativeAllowed != "undefined" && !this.options.negativeAllowed && value < 0){ - checker.createMessage("opendiscord:number-negative","error","This number can't be negative!",lt,null,[],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.positiveAllowed != "undefined" && !this.options.positiveAllowed && value > 0){ - checker.createMessage("opendiscord:number-positive","error","This number can't be positive!",lt,null,[],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.zeroAllowed != "undefined" && !this.options.zeroAllowed && value === 0){ - checker.createMessage("opendiscord:number-zero","error","This number can't be zero!",lt,null,[],this.id,(this.options.docs ?? null)) - return false - }else return super.check(checker,value,locationTrace) - } -} - -/**## ODCheckerBooleanStructureOptions `interface` - * This interface has the options for `ODCheckerBooleanStructure`! - */ -export interface ODCheckerBooleanStructureOptions extends ODCheckerStructureOptions { - /**Is `true` allowed? */ - trueAllowed?:boolean, - /**Is `false` allowed? */ - falseAllowed?:boolean -} - -/**## ODCheckerBooleanStructure `class` - * This is an Open Ticket config checker structure. - * - * This class will check for a boolean variable in a config file, customise it in the settings! - */ -export class ODCheckerBooleanStructure extends ODCheckerStructure { - declare options: ODCheckerBooleanStructureOptions - - constructor(id:ODValidId, options:ODCheckerBooleanStructureOptions){ - super(id,options) - } - - check(checker:ODChecker, value:boolean, locationTrace:ODCheckerLocationTrace): boolean { - const lt = checker.locationTraceDeref(locationTrace) - - //check type & options - if (typeof value != "boolean"){ - checker.createMessage("opendiscord:invalid-type","error","This property needs to be the type: boolean!",lt,null,["boolean"],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.trueAllowed != "undefined" && !this.options.trueAllowed && value == true){ - checker.createMessage("opendiscord:boolean-true","error","This boolean can't be true!",lt,null,[],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.falseAllowed != "undefined" && !this.options.falseAllowed && value == false){ - checker.createMessage("opendiscord:boolean-false","error","This boolean can't be false!",lt,null,[],this.id,(this.options.docs ?? null)) - return false - }else return super.check(checker,value,locationTrace) - } -} - -/**## ODCheckerArrayStructureOptions `interface` - * This interface has the options for `ODCheckerArrayStructure`! - */ -export interface ODCheckerArrayStructureOptions extends ODCheckerStructureOptions { - /**The checker for all the properties in this array */ - propertyChecker?:ODCheckerStructure, - /**Don't allow this array to be empty */ - disableEmpty?:boolean, - /**This array is required to be empty */ - emptyRequired?:boolean, - /**The minimum length of this array */ - minLength?:number, - /**The maximum length of this array */ - maxLength?:number, - /**The length of the array needs to be the same as this value */ - length?:number, - /**Allow double values (only for `string`, `number` & `boolean`) */ - allowDoubles?:boolean - /**Only allow these types in the array (for multi-type propertyCheckers) */ - allowedTypes?:("string"|"number"|"boolean"|"null"|"array"|"object"|"other")[], - /**The name of the properties inside this array. Used in the GUI of the Interactive Setup CLI. */ - cliDisplayPropertyName?:string -} - -/**## ODCheckerArrayStructure `class` - * This is an Open Ticket config checker structure. - * - * This class will check for an array variable in a config file, customise it in the settings! - */ -export class ODCheckerArrayStructure extends ODCheckerStructure { - declare options: ODCheckerArrayStructureOptions - - constructor(id:ODValidId, options:ODCheckerArrayStructureOptions){ - super(id,options) - } - - check(checker:ODChecker, value:Array, locationTrace:ODCheckerLocationTrace): boolean { - const lt = checker.locationTraceDeref(locationTrace) - - if (!Array.isArray(value)){ - checker.createMessage("opendiscord:invalid-type","error","This property needs to be the type: array!",lt,null,["array"],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.disableEmpty != "undefined" && this.options.disableEmpty && value.length == 0){ - checker.createMessage("opendiscord:array-empty-disabled","error","This array isn't allowed to be empty!",lt,null,[],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.emptyRequired != "undefined" && this.options.emptyRequired && value.length != 0){ - checker.createMessage("opendiscord:array-empty-required","error","This array is required to be empty!",lt,null,[],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.minLength != "undefined" && value.length < this.options.minLength){ - checker.createMessage("opendiscord:array-too-short","error",`This array needs to have a length of at least ${this.options.minLength}!`,lt,null,[this.options.minLength.toString()],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.maxLength != "undefined" && value.length > this.options.maxLength){ - checker.createMessage("opendiscord:array-too-long","error",`This array needs to have a length of at most ${this.options.maxLength}!`,lt,null,[this.options.maxLength.toString()],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.length != "undefined" && value.length == this.options.length){ - checker.createMessage("opendiscord:array-length-invalid","error",`This array needs to have a length of ${this.options.length}!`,lt,null,[this.options.length.toString()],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.allowedTypes != "undefined" && !this.#arrayAllowedTypesCheck(value,this.options.allowedTypes)){ - checker.createMessage("opendiscord:array-invalid-types","error",`This array can only contain the following types: ${this.options.allowedTypes.join(", ")}!`,lt,null,[this.options.allowedTypes.join(", ").toString()],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.options.allowDoubles != "undefined" && !this.options.allowDoubles && this.#arrayHasDoubles(value)){ - checker.createMessage("opendiscord:array-double","error","This array doesn't allow the same value twice!",lt,null,[],this.id,(this.options.docs ?? null)) - return false - }else{ - //check all properties - let localQuit = false - if (this.options.propertyChecker) value.forEach((property,index) => { - if (!this.options.propertyChecker) return - - const localLt = checker.locationTraceDeref(lt) - localLt.push(index) - - if (!this.options.propertyChecker.check(checker,property,localLt)) localQuit = true - }) - - //return false if invalid properties - if (localQuit){ - checker.quit = true - return false - }else return super.check(checker,value,locationTrace) - } - } - - /**Check this array for the allowed types */ - #arrayAllowedTypesCheck(array:any[],allowedTypes:("string"|"number"|"boolean"|"null"|"array"|"object"|"other")[]): boolean { - //return TRUE if ALL values are valid - return !array.some((value) => { - if (allowedTypes.includes("string") && typeof value == "string"){ - return false //this value is valid - }else if (allowedTypes.includes("number") && typeof value == "number"){ - return false //this value is valid - }else if (allowedTypes.includes("boolean") && typeof value == "boolean"){ - return false //this value is valid - }else if (allowedTypes.includes("object") && typeof value == "object"){ - return false //this value is valid - }else if (allowedTypes.includes("array") && Array.isArray(value)){ - return false //this value is valid - }else if (allowedTypes.includes("null") && value === null){ - return false //this value is valid - }else if (allowedTypes.includes("other")){ - return false //this value is valid - }else{ - return true //this value is invalid - } - }) - } - /**Check this array for doubles */ - #arrayHasDoubles(array:any[]): boolean { - const alreadyFound: string[] = [] - let hasDoubles = false - array.forEach((value) => { - if (alreadyFound.includes(value)) hasDoubles = true - else alreadyFound.push(value) - }) - - return hasDoubles - } -} - -/**## ODCheckerNullStructureOptions `interface` - * This interface has the options for `ODCheckerNullStructure`! - */ -export interface ODCheckerNullStructureOptions extends ODCheckerStructureOptions { - /**Is the value allowed to be null */ - nullAllowed?:boolean -} - -/**## ODCheckerNullStructure `class` - * This is an Open Ticket config checker structure. - * - * This class will check for a null variable in a config file, customise it in the settings! - */ -export class ODCheckerNullStructure extends ODCheckerStructure { - declare options: ODCheckerNullStructureOptions - - constructor(id:ODValidId, options:ODCheckerNullStructureOptions){ - super(id,options) - } - - check(checker:ODChecker, value:null, locationTrace:ODCheckerLocationTrace): boolean { - const lt = checker.locationTraceDeref(locationTrace) - - //check type & options - if (typeof this.options.nullAllowed != "undefined" && !this.options.nullAllowed && value == null){ - checker.createMessage("opendiscord:null-invalid","error","This property can't be null!",lt,null,[],this.id,(this.options.docs ?? null)) - return false - }else if (value !== null){ - checker.createMessage("opendiscord:invalid-type","error","This property needs to be the type: null!",lt,null,["null"],this.id,(this.options.docs ?? null)) - return false - }else return super.check(checker,value,locationTrace) - } -} - -/**## ODCheckerTypeSwitchStructureOptions `interface` - * This interface has the options for `ODCheckerTypeSwitchStructure`! - */ -export interface ODCheckerTypeSwitchStructureOptions extends ODCheckerStructureOptions { - /**A checker that will always run (replaces all other checkers) */ - all?:ODCheckerStructure, - /**A checker when the property is a string */ - string?:ODCheckerStringStructure, - /**A checker when the property is a number */ - number?:ODCheckerNumberStructure, - /**A checker when the property is a boolean */ - boolean?:ODCheckerBooleanStructure, - /**A checker when the property is null */ - null?:ODCheckerNullStructure, - /**A checker when the property is an array */ - array?:ODCheckerArrayStructure, - /**A checker when the property is an object */ - object?:ODCheckerObjectStructure, - /**A checker when the property is something else */ - other?:ODCheckerStructure, - /**A list of allowed types */ - allowedTypes:("string"|"number"|"boolean"|"null"|"array"|"object"|"other")[] -} - -/**## ODCheckerTypeSwitchStructure `class` - * This is an Open Ticket config checker structure. - * - * This class will switch checkers based on the type of the variable in a config file, customise it in the settings! - */ -export class ODCheckerTypeSwitchStructure extends ODCheckerStructure { - declare options: ODCheckerTypeSwitchStructureOptions - - constructor(id:ODValidId, options:ODCheckerTypeSwitchStructureOptions){ - super(id,options) - } - - check(checker:ODChecker, value:any, locationTrace:ODCheckerLocationTrace): boolean { - const lt = checker.locationTraceDeref(locationTrace) - - if (this.options.all){ - return this.options.all.check(checker,value,lt) - - }else if (this.options.string && typeof value == "string"){ - return this.options.string.check(checker,value,lt) - - }else if (this.options.number && typeof value == "number"){ - return this.options.number.check(checker,value,lt) - - }else if (this.options.boolean && typeof value == "boolean"){ - return this.options.boolean.check(checker,value,lt) - - }else if (this.options.array && Array.isArray(value)){ - return this.options.array.check(checker,value,lt) - - }else if (this.options.null && value === null){ - return this.options.null.check(checker,value,lt) - - }else if (this.options.object && typeof value == "object"){ - return this.options.object.check(checker,value,lt) - - }else if (this.options.other){ - return this.options.other.check(checker,value,lt) - - }else if (this.options.allowedTypes && this.options.allowedTypes.length > 0){ - checker.createMessage("opendiscord:switch-invalid-type","error",`This needs to be one of the following types: ${this.options.allowedTypes.join(", ")}!`,lt,null,[this.options.allowedTypes.join(", ")],this.id,(this.options.docs ?? null)) - return false - }else return super.check(checker,value,locationTrace) - } -} - -/**## ODCheckerObjectSwitchStructureOptions `interface` - * This interface has the options for `ODCheckerObjectSwitchStructure`! - */ -export interface ODCheckerObjectSwitchStructureOptions extends ODCheckerStructureOptions { - /**An array of object checkers with their name, properties & priority. */ - objects:{ - /**The properties to match for this checker to be used. */ - properties:{key:string, value:boolean|string|number}[], - /**The name for this object type (used in rendering) */ - name:string, - /**The higher the priority, the earlier this checker will be tested. */ - priority:number, - /**The object checker used once the properties have been matched. */ - checker:ODCheckerObjectStructure - }[] -} - -/**## ODCheckerObjectSwitchStructure `class` - * This is an Open Ticket config checker structure. - * - * This class will switch object checkers based on a variable match in one of the objects, customise it in the settings! - */ -export class ODCheckerObjectSwitchStructure extends ODCheckerStructure { - declare options: ODCheckerObjectSwitchStructureOptions - - constructor(id:ODValidId, options:ODCheckerObjectSwitchStructureOptions){ - super(id,options) - } - - check(checker:ODChecker, value:object, locationTrace:ODCheckerLocationTrace): boolean { - const lt = checker.locationTraceDeref(locationTrace) - - if (this.options.objects){ - //check type & options - if (typeof value != "object"){ - checker.createMessage("opendiscord:invalid-type","error","This property needs to be the type: object!",lt,null,["object"],this.id,(this.options.docs ?? null)) - return false - } - - //sort objects - const sortedObjects = this.options.objects.sort((a,b) => { - if (a.priority < b.priority) return -1 - else if (a.priority > b.priority) return 1 - else return 0 - }) - - - //check objects - let localQuit = false - let didSelectObject = false - sortedObjects.forEach((obj) => { - if (!obj.properties.some((p) => value[p.key] !== p.value)){ - didSelectObject = true - if (!obj.checker.check(checker,value,lt)) localQuit = true - } - }) - - //do local quit or check custom function - if (!didSelectObject){ - checker.createMessage("opendiscord:object-switch-invalid-type","error",`This object needs to be one of the following types: ${this.options.objects.map((obj) => obj.name).join(", ")}!`,lt,null,[this.options.objects.map((obj) => obj.name).join(", ")],this.id,(this.options.docs ?? null)) - return false - }else if (localQuit){ - return false - }else return super.check(checker,value,locationTrace) - }else return super.check(checker,value,locationTrace) - } -} - -/**## ODCheckerEnabledObjectStructureOptions `interface` - * This interface has the options for `ODCheckerEnabledObjectStructure`! - */ -export interface ODCheckerEnabledObjectStructureOptions extends ODCheckerStructureOptions { - /**The name of the property to match the `enabledValue`. */ - property:string, - /**The value of the property to be enabled. (e.g. `true`) */ - enabledValue:boolean|string|number, - /**The object checker to use once the property has been matched. */ - checker:ODCheckerObjectStructure -} - -/**## ODCheckerEnabledObjectStructure `class` - * This is an Open Ticket config checker structure. - * - * This class will enable an object checker based on a variable match in the object, customise it in the settings! - */ -export class ODCheckerEnabledObjectStructure extends ODCheckerStructure { - declare options: ODCheckerEnabledObjectStructureOptions - - constructor(id:ODValidId, options:ODCheckerEnabledObjectStructureOptions){ - super(id,options) - } - - check(checker:ODChecker, value:object, locationTrace:ODCheckerLocationTrace): boolean { - const lt = checker.locationTraceDeref(locationTrace) - - if (typeof value != "object"){ - //value isn't an object - checker.createMessage("opendiscord:invalid-type","error","This property needs to be the type: object!",lt,null,["object"],this.id,(this.options.docs ?? null)) - return false - - }else if (this.options.property && typeof value[this.options.property] == "undefined"){ - //property doesn't exist - checker.createMessage("opendiscord:property-missing","error",`The property "${this.options.property}" is mising from this object!`,lt,null,[`"${this.options.property}"`],this.id,(this.options.docs ?? null)) - return false - - }else if (this.options.property && value[this.options.property] === (typeof this.options.enabledValue == "undefined" ? true : this.options.enabledValue)){ - //this object is enabled - if (this.options.checker) return this.options.checker.check(checker,value,lt) - else return super.check(checker,value,locationTrace) - - }else{ - //this object is disabled - if (this.options.property) checker.createMessage("opendiscord:object-disabled","info",`This object is disabled, enable it using "${this.options.property}"!`,lt,null,[`"${this.options.property}"`],this.id,(this.options.docs ?? null)) - return super.check(checker,value,locationTrace) - } - } -} - -/**## ODCheckerCustomStructure_DiscordId `class` - * This is an Open Ticket custom checker structure. - * - * This class extends a primitive config checker & adds another layer of checking in the `custom` function. - * You can compare it to a blueprint for a specific checker. - * - * **This custom checker is made for discord ids (channel, user, role, ...)** - */ -export class ODCheckerCustomStructure_DiscordId extends ODCheckerStringStructure { - /**The type of id (used in rendering) */ - readonly type: ODDiscordIdType - /**Is this id allowed to be empty */ - readonly emptyAllowed: boolean - /**Extra matches (value will also be valid when one of these options match) */ - readonly extraOptions: string[] - - constructor(id:ODValidId, type:ODDiscordIdType, emptyAllowed:boolean, extraOptions:string[], options?:ODCheckerStringStructureOptions){ - //add premade custom structure checker - const newOptions = options ?? {} - newOptions.custom = (checker,value,locationTrace,locationId,locationDocs) => { - const lt = checker.locationTraceDeref(locationTrace) - - if (typeof value != "string") return false - else if ((!emptyAllowed && value.length < 15) || value.length > 50 || !/^[0-9]*$/.test(value)){ - if (!(extraOptions.length > 0 && extraOptions.some((opt) => opt == value))){ - //value is not an id & not one of the extra options - if (extraOptions.length > 0) checker.createMessage("opendiscord:discord-invalid-id-options","error",`This is an invalid discord ${type} id! You can also use one of these: ${extraOptions.join(", ")}!`,lt,null,[type,extraOptions.join(", ")],this.id,(this.options.docs ?? null)) - else checker.createMessage("opendiscord:discord-invalid-id","error",`This is an invalid discord ${type} id!`,lt,null,[type],this.id,(this.options.docs ?? null)) - return false - }else return true - } - return true - } - super(id,newOptions) - this.type = type - this.emptyAllowed = emptyAllowed - this.extraOptions = extraOptions - } -} - -/**## ODCheckerCustomStructure_DiscordIdArray `class` - * This is an Open Ticket custom checker structure. - * - * This class extends a primitive config checker & adds another layer of checking in the `custom` function. - * You can compare it to a blueprint for a specific checker. - * - * **This custom checker is made for discord id arrays (channel, user, role, ...)** - */ -export class ODCheckerCustomStructure_DiscordIdArray extends ODCheckerArrayStructure { - /**The type of id (used in rendering) */ - readonly type: ODDiscordIdType - /**Extra matches (value will also be valid when one of these options match) */ - readonly extraOptions: string[] - - constructor(id:ODValidId, type:ODDiscordIdType, extraOptions:string[], options?:ODCheckerArrayStructureOptions, idOptions?:ODCheckerStringStructureOptions){ - //add premade custom structure checker - const newOptions = options ?? {} - newOptions.propertyChecker = new ODCheckerCustomStructure_DiscordId(id,type,false,extraOptions,idOptions) - super(id,newOptions) - this.type = type - this.extraOptions = extraOptions - } -} - -/**## ODCheckerCustomStructure_DiscordToken `class` - * This is an Open Ticket custom checker structure. - * - * This class extends a primitive config checker & adds another layer of checking in the `custom` function. - * You can compare it to a blueprint for a specific checker. - * - * **This custom checker is made for a discord (auth) token** - */ -export class ODCheckerCustomStructure_DiscordToken extends ODCheckerStringStructure { - constructor(id:ODValidId, options?:ODCheckerStringStructureOptions){ - //add premade custom structure checker - const newOptions = options ?? {} - newOptions.custom = (checker,value,locationTrace,locationId,locationDocs) => { - const lt = checker.locationTraceDeref(locationTrace) - - if (typeof value != "string" || !/^[A-Za-z0-9-_\.]+$/.test(value)){ - checker.createMessage("opendiscord:discord-invalid-token","error","This is an invalid discord token (syntactically)!",lt,null,[],this.id,(this.options.docs ?? null)) - return false - } - return true - } - super(id,newOptions) - } -} - -/**## ODCheckerCustomStructure_DiscordToken `class` - * This is an Open Ticket custom checker structure. - * - * This class extends a primitive config checker & adds another layer of checking in the `custom` function. - * You can compare it to a blueprint for a specific checker. - * - * **This custom checker is made for a hex color** - */ -export class ODCheckerCustomStructure_HexColor extends ODCheckerStringStructure { - /**When enabled, you are also allowed to use `#fff` instead of `#ffffff` */ - readonly allowShortForm: boolean - /**Allow this hex color to be empty. */ - readonly emptyAllowed: boolean - - constructor(id:ODValidId, allowShortForm:boolean, emptyAllowed:boolean, options?:ODCheckerStringStructureOptions){ - //add premade custom structure checker - const newOptions = options ?? {} - newOptions.custom = (checker,value,locationTrace,locationId,locationDocs) => { - const lt = checker.locationTraceDeref(locationTrace) - - if (typeof value != "string") return false - else if (emptyAllowed && value.length == 0){ - return true - }else if ((!allowShortForm && !/^#[a-fA-F0-9]{6}$/.test(value)) || (allowShortForm && !/^#[a-fA-F0-9]{6}$/.test(value) && !/^#[a-fA-F0-9]{3}$/.test(value))){ - checker.createMessage("opendiscord:color-invalid","error","This is an invalid hex color!",lt,null,[],this.id,(this.options.docs ?? null)) - return false - }else return true - } - super(id,newOptions) - this.allowShortForm = allowShortForm - this.emptyAllowed = emptyAllowed - } -} - -/**## ODCheckerCustomStructure_EmojiString `class` - * This is an Open Ticket custom checker structure. - * - * This class extends a primitive config checker & adds another layer of checking in the `custom` function. - * You can compare it to a blueprint for a specific checker. - * - * **This custom checker is made for an emoji (string)** - */ -export class ODCheckerCustomStructure_EmojiString extends ODCheckerStringStructure { - /**The minimum amount of emojis required (0 to allow empty) */ - readonly minLength: number - /**The maximum amount of emojis allowed */ - readonly maxLength: number - /**Allow custom discord emoji ids (`<:12345678910:emoji_name>`) */ - readonly allowCustomDiscordEmoji: boolean - - constructor(id:ODValidId, minLength:number, maxLength:number, allowCustomDiscordEmoji:boolean, options?:ODCheckerStringStructureOptions){ - //add premade custom structure checker - const newOptions = options ?? {} - newOptions.custom = (checker,value,locationTrace,locationId,locationDocs) => { - const lt = checker.locationTraceDeref(locationTrace) - if (typeof value != "string") return false - - const discordEmojiSplitter = /(?:)/g - const splitted = value.split(discordEmojiSplitter) - const discordEmojiAmount = splitted.length-1 - const unicodeEmojiAmount = [...new Intl.Segmenter().segment(splitted.join(""))].length - const emojiAmount = discordEmojiAmount+unicodeEmojiAmount - - if (emojiAmount < minLength){ - checker.createMessage("opendiscord:emoji-too-short","error",`This string needs to have at least ${minLength} emoji's!`,lt,null,[maxLength.toString()],this.id,(this.options.docs ?? null)) - return false - }else if (emojiAmount > maxLength){ - checker.createMessage("opendiscord:emoji-too-long","error",`This string needs to have at most ${maxLength} emoji's!`,lt,null,[maxLength.toString()],this.id,(this.options.docs ?? null)) - return false - }else if (!allowCustomDiscordEmoji && //.test(value)){ - checker.createMessage("opendiscord:emoji-custom","error",`This emoji can't be a custom discord emoji!`,lt,null,[],this.id,(this.options.docs ?? null)) - return false - }else if (!/^(?:\p{Emoji}|\p{Emoji_Component}|(?:))*$/u.test(value)){ - checker.createMessage("opendiscord:emoji-invalid","error","This is an invalid emoji!",lt,null,[],this.id,(this.options.docs ?? null)) - return false - } - return true - } - super(id,newOptions) - this.minLength = minLength - this.maxLength = maxLength - this.allowCustomDiscordEmoji = allowCustomDiscordEmoji - } -} - -/**## ODCheckerCustomStructureOptions_UrlString `interface` - * This interface has the options for `ODCheckerCustomStructure_UrlString`! - */ -export interface ODCheckerCustomStructureOptions_UrlString { - /**Allow urls with `http://` instead of `https://` */ - allowHttp?:boolean - /**Allowed hostnames (string or regex) => will match domain + subdomain */ - allowedHostnames?: (string|RegExp)[] - /**Allowed extentions (string) => will match the end of the url (`.png`,`.svg`,...) */ - allowedExtensions?: string[] - /**Allowed paths (string or regex) => will match path + extension (not domain + subdomain) */ - allowedPaths?: (string|RegExp)[], - /**A regex that will be executed on the entire url (including search params, protcol, domain, ...) */ - regex?:RegExp -} - -/**## ODCheckerCustomStructure_UrlString `class` - * This is an Open Ticket custom checker structure. - * - * This class extends a primitive config checker & adds another layer of checking in the `custom` function. - * You can compare it to a blueprint for a specific checker. - * - * **This custom checker is made for a URL (string)** - */ -export class ODCheckerCustomStructure_UrlString extends ODCheckerStringStructure { - /**The settings for this url */ - readonly urlSettings: ODCheckerCustomStructureOptions_UrlString - /**Is this url allowed to be empty? */ - readonly emptyAllowed: boolean - - constructor(id:ODValidId, emptyAllowed:boolean, urlSettings:ODCheckerCustomStructureOptions_UrlString, options?:ODCheckerStringStructureOptions){ - //add premade custom structure checker - const newOptions = options ?? {} - newOptions.custom = (checker,value,locationTrace,locationId,locationDocs) => { - const lt = checker.locationTraceDeref(locationTrace) - - if (typeof value != "string") return false - else if (emptyAllowed && value.length == 0){ - return true - }else if (!this.#urlIsValid(value)){ - checker.createMessage("opendiscord:url-invalid","error","This url is invalid!",lt,null,[],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.urlSettings.allowHttp != "undefined" && !this.urlSettings.allowHttp && !/^(https:\/\/)/.test(value)){ - checker.createMessage("opendiscord:url-invalid-http","error","This url can only use the https:// protocol!",lt,null,[],this.id,(this.options.docs ?? null)) - return false - }else if (!/^(http(s)?:\/\/)/.test(value)){ - checker.createMessage("opendiscord:url-invalid-protocol","error","This url can only use the http:// & https:// protocols!",lt,null,[],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.urlSettings.allowedHostnames != "undefined" && !this.#urlHasValidHostname(value,this.urlSettings.allowedHostnames)){ - checker.createMessage("opendiscord:url-invalid-hostname","error","This url has a disallowed hostname!",lt,null,[],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.urlSettings.allowedExtensions != "undefined" && !this.#urlHasValidExtension(value,this.urlSettings.allowedExtensions)){ - checker.createMessage("opendiscord:url-invalid-extension","error",`This url has an invalid extension! Choose between: ${this.urlSettings.allowedExtensions.join(", ")}!"`,lt,null,[this.urlSettings.allowedExtensions.join(", ")],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.urlSettings.allowedPaths != "undefined" && !this.#urlHasValidPath(value,this.urlSettings.allowedPaths)){ - checker.createMessage("opendiscord:url-invalid-path","error","This url has an invalid path!",lt,null,[],this.id,(this.options.docs ?? null)) - return false - }else if (typeof this.urlSettings.regex != "undefined" && !this.urlSettings.regex.test(value)){ - checker.createMessage("opendiscord:url-invalid","error","This url is invalid!",lt,null,[],this.id,(this.options.docs ?? null)) - return false - }else return true - } - super(id,newOptions) - this.urlSettings = urlSettings - this.emptyAllowed = emptyAllowed - } - - /**Check for the hostname */ - #urlHasValidHostname(url:string,hostnames:(string|RegExp)[]): boolean { - try { - const hostname = new URL(url).hostname - return hostnames.some((rule) => { - if (typeof rule == "string"){ - return rule == hostname - }else{ - return rule.test(hostname) - } - }) - - }catch{ - return false - } - } - /**Check for the extension */ - #urlHasValidExtension(url:string,extensions:string[]): boolean { - try { - const path = new URL(url).pathname - return extensions.some((rule) => { - return path.endsWith(rule) - }) - }catch{ - return false - } - } - /**Check for the path */ - #urlHasValidPath(url:string,paths:(string|RegExp)[]): boolean { - try { - const path = new URL(url).pathname - return paths.some((rule) => { - if (typeof rule == "string"){ - return rule == path - }else{ - return rule.test(path) - } - }) - }catch{ - return false - } - } - /**Do general syntax check on url */ - #urlIsValid(url:string){ - try { - new URL(url) - return true - }catch{ - return false - } - } -} - -/**## ODCheckerCustomStructure_UniqueId `class` - * This is an Open Ticket custom checker structure. - * - * This class extends a primitive config checker & adds another layer of checking in the `custom` function. - * You can compare it to a blueprint for a specific checker. - * - * **This custom checker is made for a unique id (per source & scope)** - */ -export class ODCheckerCustomStructure_UniqueId extends ODCheckerStringStructure { - /**The source of this unique id (generally the plugin name or `openticket`) */ - readonly source: string - /**The scope of this unique id (id needs to be unique in this scope) */ - readonly scope: string - - constructor(id:ODValidId, source:string, scope:string, options?:ODCheckerStringStructureOptions){ - //add premade custom structure checker - const newOptions = options ?? {} - newOptions.custom = (checker,value,locationTrace,locationId,locationDocs) => { - const lt = checker.locationTraceDeref(locationTrace) - - if (typeof value != "string") return false - const uniqueArray: string[] = (checker.storage.get(source,scope) === null) ? [] : checker.storage.get(source,scope) - if (uniqueArray.includes(value)){ - //unique id already exists => throw error - checker.createMessage("opendiscord:id-not-unique","error","This id isn't unique, use another id instead!",lt,null,[],this.id,(this.options.docs ?? null)) - return false - }else{ - //unique id doesn't exists => add to list - uniqueArray.push(value) - checker.storage.set(source,scope,uniqueArray) - return true - } - } - super(id,newOptions) - this.source = source - this.scope = scope - } -} - -/**## ODCheckerCustomStructure_UniqueIdArray `class` - * This is an Open Ticket custom checker structure. - * - * This class extends a primitive config checker & adds another layer of checking in the `custom` function. - * You can compare it to a blueprint for a specific checker. - * - * **This custom checker is made for a unique id array (per source & scope)** - */ -export class ODCheckerCustomStructure_UniqueIdArray extends ODCheckerArrayStructure { - /**The source to read unique ids (generally the plugin name or `openticket`) */ - readonly source: string - /**The scope to read unique ids (id needs to be unique in this scope) */ - readonly scope: string - /**The scope to push unique ids when used in this array! */ - readonly usedScope: string|null - - constructor(id:ODValidId, source:string, scope:string, usedScope?:string, options?:ODCheckerArrayStructureOptions, idOptions?:Omit){ - //add premade custom structure checker - const newOptions = options ?? {} - newOptions.propertyChecker = new ODCheckerStringStructure("opendiscord:unique-id",{...(idOptions ?? {}),minLength:1,custom:(checker,value,locationTrace,locationId,locationDocs) => { - if (typeof value != "string") return false - const localLt = checker.locationTraceDeref(locationTrace) - localLt.pop() - - const uniqueArray: string[] = checker.storage.get(source,scope) ?? [] - if (uniqueArray.includes(value)){ - //exists - if (usedScope){ - const current: string[] = checker.storage.get(source,usedScope) ?? [] - current.push(value) - checker.storage.set(source,usedScope,current) - } - return true - }else{ - //doesn't exist - checker.createMessage("opendiscord:id-non-existent","error",`The id "${value}" doesn't exist!`,localLt,null,[`"${value}"`],locationId,locationDocs) - return false - } - }}) - super(id,newOptions) - this.source = source - this.scope = scope - this.usedScope = usedScope ?? null - } -} - -/*TEMPLATE!!!! -export interface ODCheckerTemplateStructureOptions extends ODCheckerStructureOptions { - -} -export class ODCheckerTemplateStructure extends ODCheckerStructure { - declare options: ODCheckerTemplateStructureOptions - - constructor(id:ODValidId, options:ODCheckerTemplateStructureOptions){ - super(id,options) - } - - check(checker:ODChecker, value:any, locationTrace:ODCheckerLocationTrace): boolean { - const lt = checker.locationTraceDeref(locationTrace) - - return super.check(checker,value,locationTrace) - } -} -*/ -/*CUSTOM TEMPLATE!!!! -export class ODCheckerCustomStructure_Template extends ODCheckerTemplateStructure { - idk: string - - constructor(id:ODValidId, idk:string, options?:ODCheckerStringStructureOptions){ - //add premade custom structure checker - const newOptions = options ?? {} - newOptions.custom = (checker,value,locationTrace,locationId,locationDocs) => { - const lt = checker.locationTraceDeref(locationTrace) - - //do custom check & push error message. Return true if correct - return boolean - } - super(id,newOptions) - this.idk = idk - } -} -*/ diff --git a/src/core/api/modules/client.ts b/src/core/api/modules/client.ts deleted file mode 100644 index 5638a99..0000000 --- a/src/core/api/modules/client.ts +++ /dev/null @@ -1,2247 +0,0 @@ -/////////////////////////////////////// -//DISCORD CLIENT MODULE -/////////////////////////////////////// -import { ODId, ODManager, ODManagerData, ODSystemError, ODValidId } from "./base" -import * as discord from "discord.js" -import {REST} from "@discordjs/rest" -import { ODConsoleWarningMessage, ODDebugger } from "./console" -import { ODMessageBuildResult, ODMessageBuildSentResult } from "./builder" -import { ODManualProgressBar } from "./progressbar" - -/**## ODClientIntents `type` - * A list of intents required when inviting the bot. - */ -export type ODClientIntents = ("Guilds"|"GuildMembers"|"GuildModeration"|"GuildEmojisAndStickers"|"GuildIntegrations"|"GuildWebhooks"|"GuildInvites"|"GuildVoiceStates"|"GuildPresences"|"GuildMessages"|"GuildMessageReactions"|"GuildMessageTyping"|"DirectMessages"|"DirectMessageReactions"|"DirectMessageTyping"|"MessageContent"|"GuildScheduledEvents"|"AutoModerationConfiguration"|"AutoModerationExecution") -/**## ODClientPriviligedIntents `type` - * A list of priviliged intents required to be enabled in the developer portal. - */ -export type ODClientPriviligedIntents = ("GuildMembers"|"MessageContent"|"Presence") -/**## ODClientPartials `type` - * A list of partials required for the bot to work. (`Message` & `Channel` are for receiving DM messages from uncached channels) - */ -export type ODClientPartials = ("User"|"Channel"|"GuildMember"|"Message"|"Reaction"|"GuildScheduledEvent"|"ThreadMember") -/**## ODClientPermissions `type` - * A list of permissions required in the server that the bot is active in. - */ -export type ODClientPermissions = ("CreateInstantInvite"|"KickMembers"|"BanMembers"|"Administrator"|"ManageChannels"|"ManageGuild"|"AddReactions"|"ViewAuditLog"|"PrioritySpeaker"|"Stream"|"ViewChannel"|"SendMessages"|"SendTTSMessages"|"ManageMessages"|"EmbedLinks"|"AttachFiles"|"ReadMessageHistory"|"MentionEveryone"|"UseExternalEmojis"|"ViewGuildInsights"|"Connect"|"Speak"|"MuteMembers"|"DeafenMembers"|"MoveMembers"|"UseVAD"|"ChangeNickname"|"ManageNicknames"|"ManageRoles"|"ManageWebhooks"|"ManageGuildExpressions"|"UseApplicationCommands"|"RequestToSpeak"|"ManageEvents"|"ManageThreads"|"CreatePublicThreads"|"CreatePrivateThreads"|"UseExternalStickers"|"SendMessagesInThreads"|"UseEmbeddedActivities"|"ModerateMembers"|"ViewCreatorMonetizationAnalytics"|"UseSoundboard"|"UseExternalSounds"|"SendVoiceMessages") - -/**## ODClientManager `class` - * This is an Open Ticket client manager. - * - * It is responsible for managing the discord.js client. Here, you can set the status, register slash commands and much more! - * - * If you want, you can also listen for custom events on the `ODClientManager.client` variable (`discord.Client`) - */ -export class ODClientManager { - /**Alias to Open Ticket debugger. */ - #debug: ODDebugger - - /**List of required bot intents. Add intents to this list using the `onClientLoad` event. */ - intents: ODClientIntents[] = [] - /**List of required bot privileged intents. Add intents to this list using the `onClientLoad` event. */ - privileges: ODClientPriviligedIntents[] = [] - /**List of required bot partials. Add intents to this list using the `onClientLoad` event. **❌ Only use when neccessery!** */ - partials: ODClientPartials[] = [] - /**List of required bot permissions. Add permissions to this list using the `onClientLoad` event. */ - permissions: ODClientPermissions[] = [] - /**The discord bot token, empty by default. */ - set token(value:string){ - this.#token = value - this.rest.setToken(value) - } - get token(){ - return this.#token - } - /**The discord bot token. **DON'T USE THIS!!!** (use `ODClientManager.token` instead) */ - #token: string = "" - - /**The discord.js `discord.Client`. Only use it when initiated! */ - client: discord.Client = new discord.Client({intents:[]}) //temporary client - /**The discord.js REST client. Used for stuff that discord.js can't handle :) */ - rest: discord.REST = new REST({version:"10"}) - /**Is the bot initiated? */ - initiated: boolean = false - /**Is the bot logged in? */ - loggedIn: boolean = false - /**Is the bot ready? */ - ready: boolean = false - - /**The main server of the bot. Provided by serverId in the config */ - mainServer: discord.Guild|null = null - /**(❌ DO NOT OVERWRITE ❌) Internal Open Ticket function to continue the startup when the client is ready! */ - readyListener: (() => Promise)|null = null - /**The status manager is responsible for setting the bot status. */ - activity: ODClientActivityManager - /**The slash command manager is responsible for all slash commands & their events inside the bot. */ - slashCommands: ODSlashCommandManager - /**The text command manager is responsible for all text commands & their events inside the bot. */ - textCommands: ODTextCommandManager - /**The context menu manager is responsible for all context menus & their events inside the bot. */ - contextMenus: ODContextMenuManager - /**The autocomplete manager is responsible for all autocomplete events inside the bot. */ - autocompletes: ODAutocompleteManager - - constructor(debug:ODDebugger){ - this.#debug = debug - this.activity = new ODClientActivityManager(this.#debug,this) - this.slashCommands = new ODSlashCommandManager(this.#debug,this) - this.textCommands = new ODTextCommandManager(this.#debug,this) - this.contextMenus = new ODContextMenuManager(this.#debug,this) - this.autocompletes = new ODAutocompleteManager(this.#debug,this) - } - - /**Initiate the `client` variable & add the intents & partials to the bot. */ - initClient(){ - if (!this.intents.every((value) => typeof discord.GatewayIntentBits[value] != "undefined")) throw new ODSystemError("Client has non-existing intents!") - if (!this.privileges.every((value) => typeof {GuildMembers:true,MessageContent:true,Presence:true}[value] != "undefined")) throw new ODSystemError("Client has non-existing privileged intents!") - if (!this.partials.every((value) => typeof discord.Partials[value] != "undefined")) throw new ODSystemError("Client has non-existing partials!") - if (!this.permissions.every((value) => typeof discord.PermissionFlagsBits[value] != "undefined")) throw new ODSystemError("Client has non-existing partials!") - - const intents = this.intents.map((value) => discord.GatewayIntentBits[value]) - const partials = this.partials.map((value) => discord.Partials[value]) - - const oldClient = this.client - this.client = new discord.Client({intents,partials}) - - //@ts-ignore - oldClient.eventNames().forEach((event:keyof discord.ClientEvents) => { - //@ts-ignore - const callbacks = oldClient.rawListeners(event) - callbacks.forEach((cb:() => void) => { - this.client.on(event,cb) - }) - }) - - this.initiated = true - - this.#debug.debug("Created client with intents: "+this.intents.join(", ")) - this.#debug.debug("Created client with privileged intents: "+this.privileges.join(", ")) - this.#debug.debug("Created client with partials: "+this.partials.join(", ")) - this.#debug.debug("Created client with permissions: "+this.permissions.join(", ")) - } - /**Get all servers the bot is part of. */ - async getGuilds(): Promise { - if (!this.initiated) throw new ODSystemError("Client isn't initiated yet!") - if (!this.ready) throw new ODSystemError("Client isn't ready yet!") - - return this.client.guilds.cache.map((guild) => guild) - } - /**Check if the bot is in a specific guild */ - checkBotInGuild(guild:discord.Guild){ - return (guild.members.me) ? true : false - } - /**Check if a specific guild has all required permissions (or `Administrator`) */ - checkGuildPerms(guild:discord.Guild){ - if (!guild.members.me) throw new ODSystemError("Client isn't a member in this server!") - const perms = guild.members.me.permissions - if (perms.has("Administrator")) return true - else{ - return this.permissions.every((perm) => { - return perms.has(perm) - }) - } - } - /**Log-in with a discord auth token. Rejects returns `false` using 'softErrors' on failure. */ - login(softErrors?:boolean): Promise { - return new Promise(async (resolve,reject) => { - if (!this.initiated) reject("Client isn't initiated yet!") - if (!this.token) reject("Client doesn't have a token!") - - try { - this.client.once("clientReady",async () => { - this.ready = true - - //set slashCommandManager & contextMenuManager to client applicationCommandManager - if (!this.client.application) throw new ODSystemError("Couldn't get client application for slashCommand & contextMenu managers!") - this.slashCommands.commandManager = this.client.application.commands - this.contextMenus.commandManager = this.client.application.commands - this.autocompletes.commandManager = this.client.application.commands - - if (this.readyListener) await this.readyListener() - resolve(true) - }) - - this.#debug.debug("Actual discord.js client.login()") - await this.client.login(this.token) - this.#debug.debug("Finished discord.js client.login()") - this.loggedIn = true - }catch(err){ - if (softErrors) return resolve(false) - else if (err.message.toLowerCase().includes("used disallowed intents")){ - process.emit("uncaughtException",new ODSystemError("Used disallowed intents")) - }else if (err.message.toLowerCase().includes("tokeninvalid") || err.message.toLowerCase().includes("an invalid token was provided")){ - process.emit("uncaughtException",new ODSystemError("Invalid discord bot token provided")) - }else reject("OT Login Error: "+err) - } - }) - } - /**A simplified shortcut to get a `discord.User` :) */ - async fetchUser(id:string): Promise { - if (!this.initiated) throw new ODSystemError("Client isn't initiated yet!") - if (!this.ready) throw new ODSystemError("Client isn't ready yet!") - - try{ - return await this.client.users.fetch(id) - }catch{ - return null - } - } - /**A simplified shortcut to get a `discord.Guild` :) */ - async fetchGuild(id:string): Promise { - if (!this.initiated) throw new ODSystemError("Client isn't initiated yet!") - if (!this.ready) throw new ODSystemError("Client isn't ready yet!") - - try{ - return await this.client.guilds.fetch(id) - }catch{ - return null - } - } - /**A simplified shortcut to get a `discord.Channel` :) */ - async fetchChannel(id:string): Promise { - if (!this.initiated) throw new ODSystemError("Client isn't initiated yet!") - if (!this.ready) throw new ODSystemError("Client isn't ready yet!") - - try{ - return await this.client.channels.fetch(id) - }catch{ - return null - } - } - /**A simplified shortcut to get a `discord.GuildBasedChannel` :) */ - async fetchGuildChannel(guildId:string|discord.Guild, id:string): Promise { - if (!this.initiated) throw new ODSystemError("Client isn't initiated yet!") - if (!this.ready) throw new ODSystemError("Client isn't ready yet!") - - try{ - const guild = (guildId instanceof discord.Guild) ? guildId : await this.fetchGuild(guildId) - if (!guild) return null - const channel = await guild.channels.fetch(id) - return channel - }catch{ - return null - } - } - /**A simplified shortcut to get a `discord.TextChannel` :) */ - async fetchGuildTextChannel(guildId:string|discord.Guild, id:string): Promise { - if (!this.initiated) throw new ODSystemError("Client isn't initiated yet!") - if (!this.ready) throw new ODSystemError("Client isn't ready yet!") - - try{ - const guild = (guildId instanceof discord.Guild) ? guildId : await this.fetchGuild(guildId) - if (!guild) return null - const channel = await guild.channels.fetch(id) - if (!channel || channel.type != discord.ChannelType.GuildText) return null - return channel - }catch{ - return null - } - } - /**A simplified shortcut to get a `discord.CategoryChannel` :) */ - async fetchGuildCategoryChannel(guildId:string|discord.Guild, id:string): Promise { - if (!this.initiated) throw new ODSystemError("Client isn't initiated yet!") - if (!this.ready) throw new ODSystemError("Client isn't ready yet!") - - try{ - const guild = (guildId instanceof discord.Guild) ? guildId : await this.fetchGuild(guildId) - if (!guild) return null - const channel = await guild.channels.fetch(id) - if (!channel || channel.type != discord.ChannelType.GuildCategory) return null - return channel - }catch{ - return null - } - } - /**A simplified shortcut to get a `discord.GuildMember` :) */ - async fetchGuildMember(guildId:string|discord.Guild, id:string): Promise { - if (!this.initiated) throw new ODSystemError("Client isn't initiated yet!") - if (!this.ready) throw new ODSystemError("Client isn't ready yet!") - if (typeof id != "string") throw new ODSystemError("TEMP ERROR => ODClientManager.fetchGuildMember() => id param isn't string") - - try{ - const guild = (guildId instanceof discord.Guild) ? guildId : await this.fetchGuild(guildId) - if (!guild) return null - return await guild.members.fetch(id) - }catch{ - return null - } - } - /**A simplified shortcut to get a `discord.Role` :) */ - async fetchGuildRole(guildId:string|discord.Guild, id:string): Promise { - if (!this.initiated) throw new ODSystemError("Client isn't initiated yet!") - if (!this.ready) throw new ODSystemError("Client isn't ready yet!") - if (typeof id != "string") throw new ODSystemError("TEMP ERROR => ODClientManager.fetchGuildRole() => id param isn't string") - - try{ - const guild = (guildId instanceof discord.Guild) ? guildId : await this.fetchGuild(guildId) - if (!guild) return null - return await guild.roles.fetch(id) - }catch{ - return null - } - } - /**A simplified shortcut to get a `discord.Message` :) */ - async fetchGuildChannelMessage(guildId:string|discord.Guild, channelId:string|discord.TextChannel, id:string): Promise|null> - async fetchGuildChannelMessage(channelId:discord.TextChannel, id:string): Promise|null> - async fetchGuildChannelMessage(guildId:string|discord.Guild|discord.TextChannel, channelId:string|discord.TextChannel|string, id?:string): Promise|null> { - if (!this.initiated) throw new ODSystemError("Client isn't initiated yet!") - if (!this.ready) throw new ODSystemError("Client isn't ready yet!") - - try{ - if (guildId instanceof discord.TextChannel && typeof channelId == "string"){ - const channel = guildId - return await channel.messages.fetch(channelId) - }else if (!(guildId instanceof discord.TextChannel) && id){ - const channel = (channelId instanceof discord.TextChannel) ? channelId : await this.fetchGuildTextChannel(guildId,channelId) - if (!channel) return null - return await channel.messages.fetch(id) - }else return null - }catch{ - return null - } - } - /**A simplified shortcut to send a DM to a user :) */ - async sendUserDm(user:string|discord.User, message:ODMessageBuildResult): Promise> { - if (!this.initiated) throw new ODSystemError("Client isn't initiated yet!") - if (!this.ready) throw new ODSystemError("Client isn't ready yet!") - - try{ - if (user instanceof discord.User){ - if (user.bot) return {success:false,message:null} - const channel = await user.createDM() - const msg = await channel.send(message.message) - return {success:true,message:msg} - }else{ - const newUser = await this.fetchUser(user) - if (!newUser) throw new Error() - if (newUser.bot) return {success:false,message:null} - const channel = await newUser.createDM() - const msg = await channel.send(message.message) - return {success:true,message:msg} - } - }catch{ - try{ - this.#debug.console.log("Failed to send DM to user! ","warning",[ - {key:"id",value:(user instanceof discord.User ? user.id : user)}, - {key:"message",value:message.id.value} - ]) - }catch{} - return {success:false,message:null} - } - } -} - -/**## ODClientActivityType `type` - * Possible activity types for the bot. - */ -export type ODClientActivityType = ("playing"|"listening"|"watching"|"custom"|false) -/**## ODClientActivityMode `type` - * Possible activity statuses for the bot. - */ -export type ODClientActivityMode = ("online"|"invisible"|"idle"|"dnd") - - -/**## ODClientActivityManager `class` - * This is an Open Ticket client activity manager. - * - * It's responsible for managing the client status. Here, you can set the activity & status of the bot. - * - * It also has a built-in refresh function, so the status will refresh every 10 minutes to keep it visible. - */ -export class ODClientActivityManager { - /**Alias to Open Ticket debugger. */ - #debug: ODDebugger - - /**Copy of discord.js client */ - manager: ODClientManager - /**The current status type */ - type: ODClientActivityType = false - /**The current status text */ - text: string = "" - /**The current status mode */ - mode: ODClientActivityMode = "online" - /**Additional state text */ - state: string = "" - - /**The timer responsible for refreshing the status. Stop it using `clearInterval(interval)` */ - interval?: NodeJS.Timeout - /**status refresh interval in seconds (5 minutes by default)*/ - refreshInterval: number = 600 - /**Is the status already initiated? */ - initiated: boolean = false - - constructor(debug:ODDebugger, manager:ODClientManager){ - this.#debug = debug - this.manager = manager - } - - /**Update the status. When already initiated, it can take up to 10min to see the updated status in discord. */ - setStatus(type:ODClientActivityType, text:string, mode:ODClientActivityMode, state:string, forceUpdate?:boolean){ - this.type = type - this.text = text - this.mode = mode - this.state = state - if (forceUpdate) this.#updateClientActivity(this.type,this.text) - } - - /**When initiating the status, the bot starts updating the status using `discord.js`. Returns `true` when successfull. */ - initStatus(): boolean { - if (this.initiated || !this.manager.ready) return false - this.#updateClientActivity(this.type,this.text) - this.interval = setInterval(() => { - this.#updateClientActivity(this.type,this.text) - this.#debug.debug("Client status update cycle") - },this.refreshInterval*1000) - this.initiated = true - this.#debug.debug("Client status initiated") - return true - } - - /**Update the client status */ - #updateClientActivity(type:ODClientActivityType,text:string){ - if (!this.manager.client.user) throw new ODSystemError("Couldn't set client status: client.user == undefined") - if (type == false){ - this.manager.client.user.setActivity() - return - } - this.manager.client.user.setPresence({ - activities:[{ - type:this.#getStatusTypeEnum(type), - state:this.state ? this.state : undefined, - name:text, - }], - status:this.mode - }) - } - /**Get the enum that links to the correct type */ - #getStatusTypeEnum(type:Exclude){ - if (type == "playing") return discord.ActivityType.Playing - else if (type == "listening") return discord.ActivityType.Listening - else if (type == "watching") return discord.ActivityType.Watching - else if (type == "custom") return discord.ActivityType.Custom - else return discord.ActivityType.Listening - } - /**Get the status type (for displaying the status) */ - getStatusType(): "listening "|"playing "|"watching "|"" { - if (this.type == "listening" || this.type == "playing" || this.type == "watching") return this.type+" " as "listening "|"playing "|"watching "|"" - else return "" - } -} - -/**## ODSlashCommandUniversalTranslation `interface` - * A universal template for a slash command translation. (used in names & descriptions) - * - * Why universal? Both **existing slash commands** & **unregistered templates** can be converted to this type. - */ -export interface ODSlashCommandUniversalTranslation { - /**The language code or locale of this language. */ - language:`${discord.Locale}`, - /**The translation of the name in this language. */ - value:string -} - -/**## ODSlashCommandUniversalOptionChoice `interface` - * A universal template for a slash command option choice. (used in `string` options) - * - * Why universal? Both **existing slash commands** & **unregistered templates** can be converted to this type. - */ -export interface ODSlashCommandUniversalOptionChoice { - /**The name of this choice. */ - name:string, - /**All localized names of this choice. */ - nameLocalizations:readonly ODSlashCommandUniversalTranslation[], - /**The value of this choice. */ - value:string -} - -/**## ODSlashCommandUniversalOption `interface` - * A universal template for a slash command option. - * - * Why universal? Both **existing slash commands** & **unregistered templates** can be converted to this type. - */ -export interface ODSlashCommandUniversalOption { - /**The type of this option. */ - type:discord.ApplicationCommandOptionType, - /**The name of this option. */ - name:string, - /**All localized names of this option. */ - nameLocalizations:readonly ODSlashCommandUniversalTranslation[], - /**The description of this option. */ - description:string, - /**All localized descriptions of this option. */ - descriptionLocalizations:readonly ODSlashCommandUniversalTranslation[], - /**Is this option required? */ - required:boolean, - - /**Is autocomplete enabled in this option? */ - autocomplete:boolean|null, - /**Choices for this option (only when type is `string`) */ - choices:ODSlashCommandUniversalOptionChoice[], - /**A list of sub-options for this option (only when type is `subCommand` or `subCommandGroup`) */ - options:readonly ODSlashCommandUniversalOption[], - /**A list of allowed channel types for this option (only when type is `channel`) */ - channelTypes:readonly discord.ChannelType[], - /**The minimum amount required for this option (only when type is `number` or `integer`) */ - minValue:number|null, - /**The maximum amount required for this option (only when type is `number` or `integer`) */ - maxValue:number|null, - /**The minimum length required for this option (only when type is `string`) */ - minLength:number|null, - /**The maximum length required for this option (only when type is `string`) */ - maxLength:number|null -} - -/**## ODSlashCommandUniversalCommand `interface` - * A universal template for a slash command. - * - * Why universal? Both **existing slash commands** & **unregistered templates** can be converted to this type. - */ -export interface ODSlashCommandUniversalCommand { - /**The type of this command. (required => `ChatInput`) */ - type:discord.ApplicationCommandType.ChatInput, - /**The name of this command. */ - name:string, - /**All localized names of this command. */ - nameLocalizations:readonly ODSlashCommandUniversalTranslation[], - /**The description of this command. */ - description:string, - /**All localized descriptions of this command. */ - descriptionLocalizations:readonly ODSlashCommandUniversalTranslation[], - /**The id of the guild this command is registered in. */ - guildId:string|null, - /**Is this command for 18+ users only? */ - nsfw:boolean, - /**A list of options for this command. */ - options:readonly ODSlashCommandUniversalOption[], - /**A bitfield of the user permissions required to use this command. */ - defaultMemberPermissions:bigint, - /**Is this command available in DM? */ - dmPermission:boolean, - /**A list of contexts where you can install this command. */ - integrationTypes:readonly discord.ApplicationIntegrationType[], - /**A list of contexts where you can use this command. */ - contexts:readonly discord.InteractionContextType[] -} - -/**## ODSlashCommandBuilder `interface` - * The builder for slash commands. Here you can add options to the command. - */ -export interface ODSlashCommandBuilder extends discord.ChatInputApplicationCommandData { - /**This field is required in Open Ticket for future compatibility. */ - integrationTypes:discord.ApplicationIntegrationType[], - /**This field is required in Open Ticket for future compatibility. */ - contexts:discord.InteractionContextType[] -} - -/**## ODSlashCommandComparator `class` - * A utility class to compare existing slash commands with newly registered ones. - */ -export class ODSlashCommandComparator { - /**Convert a `discord.ApplicationCommandOptionChoiceData` to a universal Open Ticket slash command option choice object for comparison. */ - #convertOptionChoice(choice:discord.ApplicationCommandOptionChoiceData): ODSlashCommandUniversalOptionChoice { - const nameLoc = choice.nameLocalizations ?? {} - return { - name:choice.name, - nameLocalizations:Object.keys(nameLoc).map((key) => {return {language:key as `${discord.Locale}`,value:nameLoc[key]}}), - value:choice.value - } - } - /**Convert a `discord.ApplicationCommandOptionData` to a universal Open Ticket slash command option object for comparison. */ - #convertBuilderOption(option:discord.ApplicationCommandOptionData): ODSlashCommandUniversalOption { - const nameLoc = option.nameLocalizations ?? {} - const descLoc = option.descriptionLocalizations ?? {} - return { - type:option.type, - name:option.name, - nameLocalizations:Object.keys(nameLoc).map((key) => {return {language:key as `${discord.Locale}`,value:nameLoc[key]}}), - description:option.description, - descriptionLocalizations:Object.keys(descLoc).map((key) => {return {language:key as `${discord.Locale}`,value:descLoc[key]}}), - required:(option.type != discord.ApplicationCommandOptionType.SubcommandGroup && option.type != discord.ApplicationCommandOptionType.Subcommand && option.required) ? true : false, - - autocomplete:option.autocomplete ?? false, - choices:(option.type == discord.ApplicationCommandOptionType.String && !option.autocomplete && option.choices) ? option.choices.map((choice) => this.#convertOptionChoice(choice)) : [], - options:((option.type == discord.ApplicationCommandOptionType.SubcommandGroup || option.type == discord.ApplicationCommandOptionType.Subcommand) && option.options) ? option.options.map((opt) => this.#convertBuilderOption(opt)) : [], - channelTypes:(option.type == discord.ApplicationCommandOptionType.Channel && option.channelTypes) ? option.channelTypes : [], - minValue:(option.type == discord.ApplicationCommandOptionType.Number && option.minValue) ? option.minValue : null, - maxValue:(option.type == discord.ApplicationCommandOptionType.Number && option.maxValue) ? option.maxValue : null, - minLength:(option.type == discord.ApplicationCommandOptionType.String && option.minLength) ? option.minLength : null, - maxLength:(option.type == discord.ApplicationCommandOptionType.String && option.maxLength) ? option.maxLength : null - } - } - /**Convert a `discord.ApplicationCommandOption` to a universal Open Ticket slash command option object for comparison. */ - #convertCommandOption(option:discord.ApplicationCommandOption): ODSlashCommandUniversalOption { - const nameLoc = option.nameLocalizations ?? {} - const descLoc = option.descriptionLocalizations ?? {} - - return { - type:option.type, - name:option.name, - nameLocalizations:Object.keys(nameLoc).map((key) => {return {language:key as `${discord.Locale}`,value:nameLoc[key]}}), - description:option.description, - descriptionLocalizations:Object.keys(descLoc).map((key) => {return {language:key as `${discord.Locale}`,value:descLoc[key]}}), - required:(option.type != discord.ApplicationCommandOptionType.SubcommandGroup && option.type != discord.ApplicationCommandOptionType.Subcommand && option.required) ? true : false, - - autocomplete:option.autocomplete ?? false, - choices:(option.type == discord.ApplicationCommandOptionType.String && !option.autocomplete && option.choices) ? option.choices.map((choice) => this.#convertOptionChoice(choice)) : [], - options:((option.type == discord.ApplicationCommandOptionType.SubcommandGroup || option.type == discord.ApplicationCommandOptionType.Subcommand) && option.options) ? option.options.map((opt) => this.#convertBuilderOption(opt)) : [], - channelTypes:(option.type == discord.ApplicationCommandOptionType.Channel && option.channelTypes) ? option.channelTypes : [], - minValue:(option.type == discord.ApplicationCommandOptionType.Number && option.minValue) ? option.minValue : null, - maxValue:(option.type == discord.ApplicationCommandOptionType.Number && option.maxValue) ? option.maxValue : null, - minLength:(option.type == discord.ApplicationCommandOptionType.String && option.minLength) ? option.minLength : null, - maxLength:(option.type == discord.ApplicationCommandOptionType.String && option.maxLength) ? option.maxLength : null - } - } - /**Convert a `ODSlashCommandBuilder` to a universal Open Ticket slash command object for comparison. */ - convertBuilder(builder:ODSlashCommandBuilder,guildId:string|null): ODSlashCommandUniversalCommand|null { - if (builder.type != discord.ApplicationCommandType.ChatInput) return null //throw new ODSystemError("ODSlashCommandComparator:convertBuilder() is not supported for other types than 'ChatInput'!") - const nameLoc = builder.nameLocalizations ?? {} - const descLoc = builder.descriptionLocalizations ?? {} - return { - type:1, - name:builder.name, - nameLocalizations:Object.keys(nameLoc).map((key) => {return {language:key as `${discord.Locale}`,value:nameLoc[key]}}), - description:builder.description, - descriptionLocalizations:Object.keys(descLoc).map((key) => {return {language:key as `${discord.Locale}`,value:descLoc[key]}}), - guildId:guildId, - nsfw:builder.nsfw ?? false, - options:builder.options ? builder.options.map((opt) => this.#convertBuilderOption(opt)) : [], - defaultMemberPermissions:discord.PermissionsBitField.resolve(builder.defaultMemberPermissions ?? ["ViewChannel"]), - dmPermission:(builder.contexts && builder.contexts.includes(discord.InteractionContextType.BotDM)) ?? false, - integrationTypes:builder.integrationTypes ?? [discord.ApplicationIntegrationType.GuildInstall], - contexts:builder.contexts ?? [] - } - } - /**Convert a `discord.ApplicationCommand` to a universal Open Ticket slash command object for comparison. */ - convertCommand(cmd:discord.ApplicationCommand): ODSlashCommandUniversalCommand|null { - if (cmd.type != discord.ApplicationCommandType.ChatInput) return null //throw new ODSystemError("ODSlashCommandComparator:convertCommand() is not supported for other types than 'ChatInput'!") - const nameLoc = cmd.nameLocalizations ?? {} - const descLoc = cmd.descriptionLocalizations ?? {} - return { - type:1, - name:cmd.name, - nameLocalizations:Object.keys(nameLoc).map((key) => {return {language:key as `${discord.Locale}`,value:nameLoc[key]}}), - description:cmd.description, - descriptionLocalizations:Object.keys(descLoc).map((key) => {return {language:key as `${discord.Locale}`,value:descLoc[key]}}), - guildId:cmd.guildId, - nsfw:cmd.nsfw, - options:cmd.options ? cmd.options.map((opt) => this.#convertCommandOption(opt)) : [], - defaultMemberPermissions:discord.PermissionsBitField.resolve(cmd.defaultMemberPermissions ?? ["ViewChannel"]), - dmPermission:(cmd.contexts && cmd.contexts.includes(discord.InteractionContextType.BotDM)) ? true : false, - integrationTypes:cmd.integrationTypes ?? [discord.ApplicationIntegrationType.GuildInstall], - contexts:cmd.contexts ?? [] - } - } - /**Returns `true` when the 2 slash command options are the same. */ - compareOption(optA:ODSlashCommandUniversalOption,optB:ODSlashCommandUniversalOption): boolean { - if (optA.name != optB.name) return false - if (optA.description != optB.description) return false - if (optA.type != optB.type) return false - if (optA.required != optB.required) return false - if (optA.autocomplete != optB.autocomplete) return false - if (optA.minValue != optB.minValue) return false - if (optA.maxValue != optB.maxValue) return false - if (optA.minLength != optB.minLength) return false - if (optA.maxLength != optB.maxLength) return false - - //nameLocalizations - if (optA.nameLocalizations.length != optB.nameLocalizations.length) return false - if (!optA.nameLocalizations.every((nameA) => { - const nameB = optB.nameLocalizations.find((nameB) => nameB.language == nameA.language) - if (!nameB || nameA.value != nameB.value) return false - else return true - })) return false - - //descriptionLocalizations - if (optA.descriptionLocalizations.length != optB.descriptionLocalizations.length) return false - if (!optA.descriptionLocalizations.every((descA) => { - const descB = optB.descriptionLocalizations.find((descB) => descB.language == descA.language) - if (!descB || descA.value != descB.value) return false - else return true - })) return false - - //choices - if (optA.choices.length != optB.choices.length) return false - if (!optA.choices.every((choiceA,index) => { - const choiceB = optB.choices[index] - if (choiceA.name != choiceB.name) return false - if (choiceA.value != choiceB.value) return false - - //nameLocalizations - if (choiceA.nameLocalizations.length != choiceB.nameLocalizations.length) return false - if (!choiceA.nameLocalizations.every((nameA) => { - const nameB = choiceB.nameLocalizations.find((nameB) => nameB.language == nameA.language) - if (!nameB || nameA.value != nameB.value) return false - else return true - })) return false - - return true - })) return false - - //channelTypes - if (optA.channelTypes.length != optB.channelTypes.length) return false - if (!optA.channelTypes.every((typeA) => { - return optB.channelTypes.includes(typeA) - })) return false - - //options - if (optA.options.length != optB.options.length) return false - if (!optA.options.every((subOptA,index) => { - return this.compareOption(subOptA,optB.options[index]) - })) return false - - return true - } - /**Returns `true` when the 2 slash commands are the same. */ - compare(cmdA:ODSlashCommandUniversalCommand,cmdB:ODSlashCommandUniversalCommand): boolean { - if (cmdA.name != cmdB.name) return false - if (cmdA.description != cmdB.description) return false - if (cmdA.type != cmdB.type) return false - if (cmdA.nsfw != cmdB.nsfw) return false - if (cmdA.guildId != cmdB.guildId) return false - if (cmdA.dmPermission != cmdB.dmPermission) return false - if (cmdA.defaultMemberPermissions != cmdB.defaultMemberPermissions) return false - - //nameLocalizations - if (cmdA.nameLocalizations.length != cmdB.nameLocalizations.length) return false - if (!cmdA.nameLocalizations.every((nameA) => { - const nameB = cmdB.nameLocalizations.find((nameB) => nameB.language == nameA.language) - if (!nameB || nameA.value != nameB.value) return false - else return true - })) return false - - //descriptionLocalizations - if (cmdA.descriptionLocalizations.length != cmdB.descriptionLocalizations.length) return false - if (!cmdA.descriptionLocalizations.every((descA) => { - const descB = cmdB.descriptionLocalizations.find((descB) => descB.language == descA.language) - if (!descB || descA.value != descB.value) return false - else return true - })) return false - - //contexts - if (cmdA.contexts.length != cmdB.contexts.length) return false - if (!cmdA.contexts.every((contextA) => { - return cmdB.contexts.includes(contextA) - })) return false - - //integrationTypes - if (cmdA.integrationTypes.length != cmdB.integrationTypes.length) return false - if (!cmdA.integrationTypes.every((integrationA) => { - return cmdB.integrationTypes.includes(integrationA) - })) return false - - //options - if (cmdA.options.length != cmdB.options.length) return false - if (!cmdA.options.every((optA,index) => { - return this.compareOption(optA,cmdB.options[index]) - })) return false - - return true - } -} - -/**## ODSlashCommandInteractionCallback `type` - * Callback for the slash command interaction listener. - */ -export type ODSlashCommandInteractionCallback = (interaction:discord.ChatInputCommandInteraction,cmd:ODSlashCommand) => void - -/**## ODSlashCommandRegisteredResult `type` - * The result which will be returned when getting all (un)registered slash commands from the manager. - */ -export type ODSlashCommandRegisteredResult = { - /**A list of all registered commands. */ - registered:{ - /**The instance (`ODSlashCommand`) from this command. */ - instance:ODSlashCommand, - /**The (universal) slash command object/template of this command. */ - cmd:ODSlashCommandUniversalCommand, - /**Does this command require an update? */ - requiresUpdate:boolean - }[], - /**A list of all unregistered commands. */ - unregistered:{ - /**The instance (`ODSlashCommand`) from this command. */ - instance:ODSlashCommand, - /**The (universal) slash command object/template of this command. */ - cmd:null, - /**Does this command require an update? */ - requiresUpdate:true - }[], - /**A list of all unused commands (not found in `ODSlashCommandManager`). */ - unused:{ - /**The instance (`ODSlashCommand`) from this command. */ - instance:null, - /**The (universal) slash command object/template of this command. */ - cmd:ODSlashCommandUniversalCommand, - /**Does this command require an update? */ - requiresUpdate:false - }[] -} - -/**## ODSlashCommandManager `class` - * This is an Open Ticket client slash manager. - * - * It's responsible for managing all the slash commands from the client. - * - * Here, you can add & remove slash commands & the bot will do the (de)registering. - */ -export class ODSlashCommandManager extends ODManager { - /**Alias to Open Ticket debugger. */ - #debug: ODDebugger - - /**Refrerence to discord.js client. */ - manager: ODClientManager - /**Discord.js application commands manager. */ - commandManager: discord.ApplicationCommandManager|null - /**Collection of all interaction listeners. */ - #interactionListeners: {name:string|RegExp, callback:ODSlashCommandInteractionCallback}[] = [] - /**Set the soft limit for maximum amount of listeners. A warning will be shown when there are more listeners than this limit. */ - listenerLimit: number = 100 - /**A utility class used to compare 2 slash commands with each other. */ - comparator: ODSlashCommandComparator = new ODSlashCommandComparator() - - constructor(debug:ODDebugger, manager:ODClientManager){ - super(debug,"slash command") - this.#debug = debug - this.manager = manager - this.commandManager = (manager.client.application) ? manager.client.application.commands : null - } - - /**Get all registered & unregistered slash commands. */ - async getAllRegisteredCommands(guildId?:string): Promise { - if (!this.commandManager) throw new ODSystemError("Couldn't get client application to register slash commands!") - - const cmds = (await this.commandManager.fetch({guildId})).toJSON() - const registered: {instance:ODSlashCommand, cmd:ODSlashCommandUniversalCommand, requiresUpdate:boolean}[] = [] - const unregistered: {instance:ODSlashCommand, cmd:null, requiresUpdate:true}[] = [] - const unused: {instance:null, cmd:ODSlashCommandUniversalCommand, requiresUpdate:false}[] = [] - - await this.loopAll((instance) => { - if (guildId && instance.guildId != guildId) return - - const index = cmds.findIndex((cmd) => cmd.name == instance.name) - const cmd = cmds[index] - cmds.splice(index,1) - if (cmd){ - //command is registered (and may need to be updated) - const universalBuilder = this.comparator.convertBuilder(instance.builder,instance.guildId) - const universalCmd = this.comparator.convertCommand(cmd) - - //command is not of the type 'chatinput' - if (!universalBuilder || !universalCmd) return - - const didChange = !this.comparator.compare(universalBuilder,universalCmd) - const requiresUpdate = didChange || (instance.requiresUpdate ? instance.requiresUpdate(universalCmd) : false) - registered.push({instance,cmd:universalCmd,requiresUpdate}) - - //command is not registered - }else unregistered.push({instance,cmd:null,requiresUpdate:true}) - }) - - cmds.forEach((cmd) => { - //command does not exist in the manager (only append to unused when type == 'chatinput') - const universalCmd = this.comparator.convertCommand(cmd) - if (!universalCmd) return - unused.push({instance:null,cmd:universalCmd,requiresUpdate:false}) - }) - - return {registered,unregistered,unused} - } - /**Create all commands that are not registered yet.*/ - async createNewCommands(instances:ODSlashCommand[],progress?:ODManualProgressBar){ - if (!this.manager.ready) throw new ODSystemError("Client isn't ready yet! Unable to register slash commands!") - if (instances.length > 0 && progress){ - progress.max = instances.length - progress.start() - } - - for (const instance of instances){ - await this.createCmd(instance) - this.#debug.debug("Created new slash command",[ - {key:"id",value:instance.id.value}, - {key:"name",value:instance.name} - ]) - if (progress) progress.increase(1) - } - } - /**Update all commands that are already registered. */ - async updateExistingCommands(instances:ODSlashCommand[],progress?:ODManualProgressBar){ - if (!this.manager.ready) throw new ODSystemError("Client isn't ready yet! Unable to register slash commands!") - if (instances.length > 0 && progress){ - progress.max = instances.length - progress.start() - } - - for (const instance of instances){ - await this.createCmd(instance) - this.#debug.debug("Updated existing slash command",[{key:"id",value:instance.id.value},{key:"name",value:instance.name}]) - if (progress) progress.increase(1) - } - } - /**Remove all commands that are registered but unused by Open Ticket. */ - async removeUnusedCommands(instances:ODSlashCommandUniversalCommand[],guildId?:string,progress?:ODManualProgressBar){ - if (!this.manager.ready) throw new ODSystemError("Client isn't ready yet! Unable to register slash commands!") - if (!this.commandManager) throw new ODSystemError("Couldn't get client application to register slash commands!") - if (instances.length > 0 && progress){ - progress.max = instances.length - progress.start() - } - - const cmds = await this.commandManager.fetch({guildId}) - - for (const instance of instances){ - const cmd = cmds.find((cmd) => cmd.name == instance.name) - if (cmd){ - try { - await cmd.delete() - this.#debug.debug("Removed existing slash command",[{key:"name",value:cmd.name},{key:"guildId",value:guildId ?? "/"}]) - }catch(err){ - process.emit("uncaughtException",err) - throw new ODSystemError("Failed to delete slash command '/"+cmd.name+"'!") - } - } - if (progress) progress.increase(1) - } - } - /**Create a slash command. **(SYSTEM ONLY)** => Use `ODSlashCommandManager` for registering commands the default way! */ - async createCmd(cmd:ODSlashCommand){ - if (!this.commandManager) throw new ODSystemError("Couldn't get client application to register slash commands!") - try { - await this.commandManager.create(cmd.builder,(cmd.guildId ?? undefined)) - }catch(err){ - process.emit("uncaughtException",err) - throw new ODSystemError("Failed to register slash command '/"+cmd.name+"'!") - } - } - /**Start listening to the discord.js client `interactionCreate` event. */ - startListeningToInteractions(){ - this.manager.client.on("interactionCreate",(interaction) => { - //return when not in main server or DM - if (!this.manager.mainServer || (interaction.guild && interaction.guild.id != this.manager.mainServer.id)) return - - if (!interaction.isChatInputCommand()) return - const cmd = this.getFiltered((cmd) => cmd.name == interaction.commandName)[0] - if (!cmd) return - - this.#interactionListeners.forEach((listener) => { - if (typeof listener.name == "string" && (interaction.commandName != listener.name)) return - else if (listener.name instanceof RegExp && !listener.name.test(interaction.commandName)) return - - //this is a valid listener - listener.callback(interaction,cmd) - }) - }) - } - /**Callback on interaction from one or multiple slash commands. */ - onInteraction(commandName:string|RegExp, callback:ODSlashCommandInteractionCallback){ - this.#interactionListeners.push({ - name:commandName, - callback - }) - - if (this.#interactionListeners.length > this.listenerLimit){ - this.#debug.console.log(new ODConsoleWarningMessage("Possible slash command interaction memory leak detected!",[ - {key:"listeners",value:this.#interactionListeners.length.toString()} - ])) - } - } -} - -/**## ODSlashCommandUpdateFunction `type` - * The function responsible for updating slash commands when they already exist. - */ -export type ODSlashCommandUpdateFunction = (command:ODSlashCommandUniversalCommand) => boolean - -/**## ODSlashCommand `class` - * This is an Open Ticket slash command. - * - * When registered, you can listen for this command using the `ODCommandResponder`. The advantages of using this class for creating a slash command are: - * - automatic option parsing (even for channels, users, roles & mentions)! - * - automatic registration in discord.js - * - error reporting to the user when the bot fails to respond - * - plugins can extend this command - * - the bot won't re-register the command when it already exists (except when requested)! - * - * And more! - */ -export class ODSlashCommand extends ODManagerData { - /**The discord.js builder for this slash command. */ - builder: ODSlashCommandBuilder - /**The id of the guild this command is for. Null when not set. */ - guildId: string|null - /**Function to check if the slash command requires to be updated (when it already exists). */ - requiresUpdate: ODSlashCommandUpdateFunction|null = null - - constructor(id:ODValidId, builder:ODSlashCommandBuilder, requiresUpdate?:ODSlashCommandUpdateFunction, guildId?:string){ - super(id) - if (builder.type != discord.ApplicationCommandType.ChatInput) throw new ODSystemError("ApplicationCommandData is required to be the 'ChatInput' type!") - - this.builder = builder - this.guildId = guildId ?? null - this.requiresUpdate = requiresUpdate ?? null - } - - /**The name of this slash command. */ - get name(): string { - return this.builder.name - } - set name(name:string){ - this.builder.name = name - } -} - -/**## ODTextCommandBuilderBaseOptionType `type` - * The types available in the text command option builder. - */ -export type ODTextCommandBuilderBaseOptionType = "string"|"number"|"boolean"|"user"|"guildmember"|"role"|"mentionable"|"channel" - -/**## ODTextCommandBuilderBaseOption `interface` - * The default option builder for text commands. - */ -export interface ODTextCommandBuilderBaseOption { - /**The name of this option */ - name:string, - /**The type of this option */ - type:ODTextCommandBuilderBaseOptionType, - /**Is this option required? (optional options can only exist at the end of the command!) */ - required?:boolean -} - -/**## ODTextCommandBuilderStringOption `interface` - * The string option builder for text commands. - */ -export interface ODTextCommandBuilderStringOption extends ODTextCommandBuilderBaseOption { - type:"string", - /**Set the maximum length of this string */ - maxLength?:number, - /**Set the minimum length of this string */ - minLength?:number, - /**The string needs to match this regex or it will be invalid */ - regex?:RegExp, - /**The string needs to match one of these choices or it will be invalid */ - choices?:string[], - /**When this is the last option, allow this string to contain spaces */ - allowSpaces?:boolean -} - -/**## ODTextCommandBuilderNumberOption `interface` - * The number option builder for text commands. - */ -export interface ODTextCommandBuilderNumberOption extends ODTextCommandBuilderBaseOption { - type:"number", - /**The number can't be higher than this value */ - max?:number, - /**The number can't be lower than this value */ - min?:number, - /**Allow the number to be negative */ - allowNegative?:boolean, - /**Allow the number to be positive */ - allowPositive?:boolean, - /**Allow the number to be zero */ - allowZero?:boolean, - /**Allow a number with decimal */ - allowDecimal?:boolean -} - -/**## ODTextCommandBuilderBooleanOption `interface` - * The boolean option builder for text commands. - */ -export interface ODTextCommandBuilderBooleanOption extends ODTextCommandBuilderBaseOption { - type:"boolean", - /**The value when `true` */ - trueValue?:string, - /**The value when `false` */ - falseValue?:string -} - -/**## ODTextCommandBuilderChannelOption `interface` - * The channel option builder for text commands. - */ -export interface ODTextCommandBuilderChannelOption extends ODTextCommandBuilderBaseOption { - type:"channel", - /**When specified, only allow the following channel types */ - channelTypes?:discord.GuildChannelType[] -} - -/**## ODTextCommandBuilderRoleOption `interface` - * The role option builder for text commands. - */ -export interface ODTextCommandBuilderRoleOption extends ODTextCommandBuilderBaseOption { - type:"role" -} - -/**## ODTextCommandBuilderUserOption `interface` - * The user option builder for text commands. - */ -export interface ODTextCommandBuilderUserOption extends ODTextCommandBuilderBaseOption { - type:"user" -} - -/**## ODTextCommandBuilderGuildMemberOption `interface` - * The guild member option builder for text commands. - */ -export interface ODTextCommandBuilderGuildMemberOption extends ODTextCommandBuilderBaseOption { - type:"guildmember" -} - -/**## ODTextCommandBuilderMentionableOption `interface` - * The mentionable option builder for text commands. - */ -export interface ODTextCommandBuilderMentionableOption extends ODTextCommandBuilderBaseOption { - type:"mentionable" -} - -/**## ODTextCommandBuilderOption `type` - * The option builder for text commands. - */ -export type ODTextCommandBuilderOption = ( - ODTextCommandBuilderStringOption| - ODTextCommandBuilderBooleanOption| - ODTextCommandBuilderNumberOption| - ODTextCommandBuilderChannelOption| - ODTextCommandBuilderRoleOption| - ODTextCommandBuilderUserOption| - ODTextCommandBuilderGuildMemberOption| - ODTextCommandBuilderMentionableOption -) - -/**## ODTextCommandBuilder `interface` - * The builder for text commands. Here you can add options to the command. - */ -export interface ODTextCommandBuilder { - /**The prefix of this command */ - prefix:string, - /**The name of this command (can include spaces for subcommands) */ - name:string, - /**Is this command allowed in dm? */ - dmPermission?:boolean, - /**Is this command allowed in guilds? */ - guildPermission?:boolean, - /**When specified, only allow this command to be executed in the following guilds */ - allowedGuildIds?:string[], - /**Are bots allowed to execute this command? */ - allowBots?:boolean - /**The options for this text command (like slash commands) */ - options?:ODTextCommandBuilderOption[] -} - -/**## ODTextCommand `class` - * This is an Open Ticket text command. - * - * When registered, you can listen for this command using the `ODCommandResponder`. The advantages of using this class for creating a text command are: - * - automatic option parsing (even for channels, users, roles & mentions)! - * - automatic errors on invalid parameters - * - error reporting to the user when the bot fails to respond - * - plugins can extend this command - * - * And more! - */ -export class ODTextCommand extends ODManagerData { - /**The builder for this slash command. */ - builder: ODTextCommandBuilder - /**The name of this slash command. */ - name: string - - constructor(id:ODValidId, builder:ODTextCommandBuilder){ - super(id) - this.builder = builder - this.name = builder.name - } -} - -/**## ODTextCommandInteractionOptionBase `interface` - * The object returned for options from a text command interaction. - */ -export interface ODTextCommandInteractionOptionBase { - /**The name of this option */ - name:string, - /**The type of this option */ - type:Name, - /**The value of this option */ - value:Type -} - -/**## ODTextCommandInteractionOption `type` - * A list of types returned for options from a text command interaction. - */ -export type ODTextCommandInteractionOption = ( - ODTextCommandInteractionOptionBase<"string",string>| - ODTextCommandInteractionOptionBase<"number",number>| - ODTextCommandInteractionOptionBase<"boolean",boolean>| - ODTextCommandInteractionOptionBase<"channel",discord.GuildBasedChannel>| - ODTextCommandInteractionOptionBase<"role",discord.Role>| - ODTextCommandInteractionOptionBase<"user",discord.User>| - ODTextCommandInteractionOptionBase<"guildmember",discord.GuildMember>| - ODTextCommandInteractionOptionBase<"mentionable",discord.Role|discord.User> -) - -/**## ODTextCommandInteractionCallback `type` - * Callback for the text command interaction listener. - */ -export type ODTextCommandInteractionCallback = (msg:discord.Message, cmd:ODTextCommand, options:ODTextCommandInteractionOption[]) => void - -/**## ODTextCommandErrorBase `interface` - * The object returned from a text command error callback. - */ -export interface ODTextCommandErrorBase { - /**The type of text command error */ - type:"unknown_prefix"|"unknown_command"|"invalid_option"|"missing_option", - /**The message this error originates from */ - msg:discord.Message -} - -/**## ODTextCommandErrorUnknownPrefix `interface` - * The object returned from a text command unknown prefix error callback. - */ -export interface ODTextCommandErrorUnknownPrefix extends ODTextCommandErrorBase { - type:"unknown_prefix" -} - -/**## ODTextCommandErrorUnknownCommand `interface` - * The object returned from a text command unknown command error callback. - */ -export interface ODTextCommandErrorUnknownCommand extends ODTextCommandErrorBase { - type:"unknown_command" -} - -/**## ODTextCommandErrorInvalidOptionReason `type` - * A list of reasons for the invalid_option error to be thrown. - */ -export type ODTextCommandErrorInvalidOptionReason = ( - "boolean"| - "number_max"| - "number_min"| - "number_decimal"| - "number_negative"| - "number_positive"| - "number_zero"| - "number_invalid"| - "string_max_length"| - "string_min_length"| - "string_regex"| - "string_choice"| - "not_in_guild"| - "channel_not_found"| - "channel_type"| - "user_not_found"| - "member_not_found"| - "role_not_found"| - "mentionable_not_found" -) - -/**## ODTextCommandErrorInvalidOption `interface` - * The object returned from a text command invalid option error callback. - */ -export interface ODTextCommandErrorInvalidOption extends ODTextCommandErrorBase { - type:"invalid_option", - /**The command this error originates from */ - command:ODTextCommand, - /**The command prefix this error originates from */ - prefix:string, - /**The command name this error originates from (can include spaces for subcommands) */ - name:string, - /**The option that this error originates from */ - option:ODTextCommandBuilderOption - /**The location that this option was found */ - location:number, - /**The current value of this invalid option */ - value:string, - /**The reason for this invalid option */ - reason:ODTextCommandErrorInvalidOptionReason -} - -/**## ODTextCommandErrorMissingOption `interface` - * The object returned from a text command missing option error callback. - */ -export interface ODTextCommandErrorMissingOption extends ODTextCommandErrorBase { - type:"missing_option", - /**The command this error originates from */ - command:ODTextCommand, - /**The command prefix this error originates from */ - prefix:string, - /**The command name this error originates from (can include spaces for subcommands) */ - name:string, - /**The option that this error originates from */ - option:ODTextCommandBuilderOption - /**The location that this option was found */ - location:number -} - -/**## ODTextCommandError `type` - * A list of types returned for errors from a text command interaction. - */ -export type ODTextCommandError = ( - ODTextCommandErrorUnknownPrefix| - ODTextCommandErrorUnknownCommand| - ODTextCommandErrorInvalidOption| - ODTextCommandErrorMissingOption -) - -/**## ODTextCommandErrorCallback `type` - * Callback for the text command error listener. - */ -export type ODTextCommandErrorCallback = (error:ODTextCommandError) => void - -/**## ODTextCommandManager `class` - * This is an Open Ticket client text manager. - * - * It's responsible for managing all the text commands from the client. - * - * Here, you can add & remove text commands & the bot will do the (de)registering. - */ -export class ODTextCommandManager extends ODManager { - /**Alias to Open Ticket debugger. */ - #debug: ODDebugger - /**Copy of discord.js client. */ - manager: ODClientManager - /**Collection of all interaction listeners. */ - #interactionListeners: {prefix:string, name:string|RegExp, callback:ODTextCommandInteractionCallback}[] = [] - /**Collection of all error listeners. */ - #errorListeners: ODTextCommandErrorCallback[] = [] - /**Set the soft limit for maximum amount of listeners. A warning will be shown when there are more listeners than this limit. */ - listenerLimit: number = 100 - - constructor(debug:ODDebugger, manager:ODClientManager){ - super(debug,"text command") - this.#debug = debug - this.manager = manager - } - - /*Check if a message is a registered command. */ - async #checkMessage(msg:discord.Message){ - if (this.manager.client.user && msg.author.id == this.manager.client.user.id) return false - - //filter commands for correct prefix - const validPrefixCommands: {cmd:ODTextCommand,newContent:string}[] = [] - await this.loopAll((cmd) => { - if (msg.content.startsWith(cmd.builder.prefix)) validPrefixCommands.push({ - cmd:cmd, - newContent:msg.content.substring(cmd.builder.prefix.length) - }) - }) - - //return when no command with prefix - if (validPrefixCommands.length == 0){ - this.#errorListeners.forEach((cb) => cb({ - type:"unknown_prefix", - msg:msg - })) - return false - } - - //filter commands for correct name - const validNameCommands: {cmd:ODTextCommand,newContent:string}[] = [] - validPrefixCommands.forEach((cmd) => { - if (cmd.newContent.startsWith(cmd.cmd.builder.name+" ") || cmd.newContent == cmd.cmd.builder.name) validNameCommands.push({ - cmd:cmd.cmd, - newContent:cmd.newContent.substring(cmd.cmd.builder.name.length+1) //+1 because of space after command name - }) - }) - - //return when no command with name - if (validNameCommands.length == 0){ - this.#errorListeners.forEach((cb) => cb({ - type:"unknown_command", - msg:msg - })) - return false - } - - //the final command - const command = validNameCommands[0] - const builder = command.cmd.builder - - //check additional options - if (typeof builder.allowBots != "undefined" && !builder.allowBots && msg.author.bot) return false - else if (typeof builder.dmPermission != "undefined" && !builder.dmPermission && msg.channel.type == discord.ChannelType.DM) return false - else if (typeof builder.guildPermission != "undefined" && !builder.guildPermission && msg.guild) return false - else if (typeof builder.allowedGuildIds != "undefined" && msg.guild && !builder.allowedGuildIds.includes(msg.guild.id)) return false - - //check all command options & return when incorrect - const options = await this.#checkOptions(command.cmd,command.newContent,msg) - if (!options.valid) return false - - //a command matched this message => emit event - this.#interactionListeners.forEach((listener) => { - if (typeof listener.prefix == "string" && (command.cmd.builder.prefix != listener.prefix)) return - if (typeof listener.name == "string" && (command.cmd.name.split(" ")[0] != listener.name)) return - else if (listener.name instanceof RegExp && !listener.name.test(command.cmd.name.split(" ")[0])) return - - //this is a valid listener - listener.callback(msg,command.cmd,options.data) - }) - return true - } - /**Check if all options of a command are correct. */ - async #checkOptions(cmd:ODTextCommand, newContent:string, msg:discord.Message){ - const options = cmd.builder.options - if (!options) return {valid:true,data:[]} - - let tempContent = newContent - let optionInvalid = false - const optionData: ODTextCommandInteractionOption[] = [] - - const optionError = (type:"invalid_option"|"missing_option", option:ODTextCommandBuilderOption, location:number, value?:string, reason?:ODTextCommandErrorInvalidOptionReason) => { - //ERROR INVALID - if (type == "invalid_option" && value && reason){ - this.#errorListeners.forEach((cb) => cb({ - type:"invalid_option", - msg:msg, - prefix:cmd.builder.prefix, - command:cmd, - name:cmd.builder.name, - option, - location, - value, - reason - })) - }else if (type == "missing_option"){ - this.#errorListeners.forEach((cb) => cb({ - type:"missing_option", - msg:msg, - prefix:cmd.builder.prefix, - command:cmd, - name:cmd.builder.name, - option, - location - })) - } - optionInvalid = true - } - - for (let location = 0;location < options.length;location++){ - const option = options[location] - if (optionInvalid) break - - //CHECK BOOLEAN - if (option.type == "boolean"){ - const falseValue = option.falseValue ?? "false" - const trueValue = option.trueValue ?? "true" - - if (tempContent.startsWith(falseValue+" ")){ - //FALSE VALUE - optionData.push({ - name:option.name, - type:"boolean", - value:false - }) - tempContent = tempContent.substring(falseValue.length+1) - - }else if (tempContent.startsWith(trueValue+" ")){ - //TRUE VALUE - optionData.push({ - name:option.name, - type:"boolean", - value:true - }) - tempContent = tempContent.substring(trueValue.length+1) - - }else if (option.required){ - //REQUIRED => ERROR IF NOT EXISTING - const invalidregex = /^[^ ]+/ - const invalidRes = invalidregex.exec(tempContent) - if (invalidRes) optionError("invalid_option",option,location,invalidRes[0],"boolean") - else optionError("missing_option",option,location) - } - - //CHECK NUMBER - }else if (option.type == "number"){ - const numRegex = /^[0-9\.\,]+/ - const res = numRegex.exec(tempContent) - if (res){ - const value = res[0].replace(/\,/g,".") - tempContent = tempContent.substring(value.length+1) - const numValue = Number(value) - - if (isNaN(numValue)){ - optionError("invalid_option",option,location,value,"number_invalid") - - }else if (typeof option.allowDecimal == "boolean" && !option.allowDecimal && (numValue % 1) !== 0){ - optionError("invalid_option",option,location,value,"number_decimal") - - }else if (typeof option.allowNegative == "boolean" && !option.allowNegative && numValue < 0){ - optionError("invalid_option",option,location,value,"number_negative") - - }else if (typeof option.allowPositive == "boolean" && !option.allowPositive && numValue > 0){ - optionError("invalid_option",option,location,value,"number_positive") - - }else if (typeof option.allowZero == "boolean" && !option.allowZero && numValue == 0){ - optionError("invalid_option",option,location,value,"number_zero") - - }else if (typeof option.max == "number" && numValue > option.max){ - optionError("invalid_option",option,location,value,"number_max") - - }else if (typeof option.min == "number" && numValue < option.min){ - optionError("invalid_option",option,location,value,"number_min") - - }else{ - //VALID NUMBER - optionData.push({ - name:option.name, - type:"number", - value:numValue - }) - } - }else if (option.required){ - //REQUIRED => ERROR IF NOT EXISTING - const invalidRegex = /^[^ ]+/ - const invalidRes = invalidRegex.exec(tempContent) - if (invalidRes) optionError("invalid_option",option,location,invalidRes[0],"number_invalid") - else optionError("missing_option",option,location) - } - //CHECK STRING - }else if (option.type == "string"){ - if (option.allowSpaces){ - //STRING WITH SPACES - const value = tempContent - tempContent = "" - - if (typeof option.minLength == "number" && value.length < option.minLength){ - optionError("invalid_option",option,location,value,"string_min_length") - - }else if (typeof option.maxLength == "number" && value.length > option.maxLength){ - optionError("invalid_option",option,location,value,"string_max_length") - - }else if (option.regex && !option.regex.test(value)){ - optionError("invalid_option",option,location,value,"string_regex") - - }else if (option.choices && !option.choices.includes(value)){ - optionError("invalid_option",option,location,value,"string_choice") - - }else if (option.required && value === ""){ - //REQUIRED => ERROR IF NOT EXISTING - optionError("missing_option",option,location) - - }else{ - //VALID STRING - optionData.push({ - name:option.name, - type:"string", - value - }) - } - }else{ - //STRING WITHOUT SPACES - const stringRegex = /^[^ ]+/ - const res = stringRegex.exec(tempContent) - if (res){ - const value = res[0] - tempContent = tempContent.substring(value.length+1) - - if (typeof option.minLength == "number" && value.length < option.minLength){ - optionError("invalid_option",option,location,value,"string_min_length") - - }else if (typeof option.maxLength == "number" && value.length > option.maxLength){ - optionError("invalid_option",option,location,value,"string_max_length") - - }else if (option.regex && !option.regex.test(value)){ - optionError("invalid_option",option,location,value,"string_regex") - - }else if (option.choices && !option.choices.includes(value)){ - optionError("invalid_option",option,location,value,"string_choice") - - }else{ - //VALID STRING - optionData.push({ - name:option.name, - type:"string", - value - }) - } - }else if (option.required){ - //REQUIRED => ERROR IF NOT EXISTING - optionError("missing_option",option,location) - } - } - //CHECK CHANNEL - }else if (option.type == "channel"){ - const channelRegex = /^(?:<#)?([0-9]+)>?/ - const res = channelRegex.exec(tempContent) - if (res){ - const value = res[0] - tempContent = tempContent.substring(value.length+1) - const channelId = res[1] - - if (!msg.guild){ - optionError("invalid_option",option,location,value,"not_in_guild") - }else{ - try{ - const channel = await msg.guild.channels.fetch(channelId) - if (!channel){ - optionError("invalid_option",option,location,value,"channel_not_found") - - }else if (option.channelTypes && !option.channelTypes.includes(channel.type)){ - optionError("invalid_option",option,location,value,"channel_type") - - }else{ - //VALID CHANNEL - optionData.push({ - name:option.name, - type:"channel", - value:channel - }) - } - }catch{ - optionError("invalid_option",option,location,value,"channel_not_found") - } - } - }else if (option.required){ - //REQUIRED => ERROR IF NOT EXISTING - const invalidRegex = /^[^ ]+/ - const invalidRes = invalidRegex.exec(tempContent) - if (invalidRes) optionError("invalid_option",option,location,invalidRes[0],"channel_not_found") - else optionError("missing_option",option,location) - } - //CHECK ROLE - }else if (option.type == "role"){ - const roleRegex = /^(?:<@&)?([0-9]+)>?/ - const res = roleRegex.exec(tempContent) - if (res){ - const value = res[0] - tempContent = tempContent.substring(value.length+1) - const roleId = res[1] - - if (!msg.guild){ - optionError("invalid_option",option,location,value,"not_in_guild") - }else{ - try{ - const role = await msg.guild.roles.fetch(roleId) - if (!role){ - optionError("invalid_option",option,location,value,"role_not_found") - }else{ - //VALID ROLE - optionData.push({ - name:option.name, - type:"role", - value:role - }) - } - }catch{ - optionError("invalid_option",option,location,value,"role_not_found") - } - } - }else if (option.required){ - //REQUIRED => ERROR IF NOT EXISTING - const invalidRegex = /^[^ ]+/ - const invalidRes = invalidRegex.exec(tempContent) - if (invalidRes) optionError("invalid_option",option,location,invalidRes[0],"role_not_found") - else optionError("missing_option",option,location) - } - //CHECK GUILD MEMBER - }else if (option.type == "guildmember"){ - const memberRegex = /^(?:<@)?([0-9]+)>?/ - const res = memberRegex.exec(tempContent) - if (res){ - const value = res[0] - tempContent = tempContent.substring(value.length+1) - const memberId = res[1] - - if (!msg.guild){ - optionError("invalid_option",option,location,value,"not_in_guild") - }else{ - try{ - const member = await msg.guild.members.fetch(memberId) - if (!member){ - optionError("invalid_option",option,location,value,"member_not_found") - }else{ - //VALID GUILD MEMBER - optionData.push({ - name:option.name, - type:"guildmember", - value:member - }) - } - }catch{ - optionError("invalid_option",option,location,value,"member_not_found") - } - } - }else if (option.required){ - //REQUIRED => ERROR IF NOT EXISTING - const invalidRegex = /^[^ ]+/ - const invalidRes = invalidRegex.exec(tempContent) - if (invalidRes) optionError("invalid_option",option,location,invalidRes[0],"member_not_found") - else optionError("missing_option",option,location) - } - //CHECK USER - }else if (option.type == "user"){ - const userRegex = /^(?:<@)?([0-9]+)>?/ - const res = userRegex.exec(tempContent) - if (res){ - const value = res[0] - tempContent = tempContent.substring(value.length+1) - const userId = res[1] - - try{ - const user = await this.manager.client.users.fetch(userId) - if (!user){ - optionError("invalid_option",option,location,value,"user_not_found") - }else{ - //VALID USER - optionData.push({ - name:option.name, - type:"user", - value:user - }) - } - }catch{ - optionError("invalid_option",option,location,value,"user_not_found") - } - }else if (option.required){ - //REQUIRED => ERROR IF NOT EXISTING - const invalidRegex = /^[^ ]+/ - const invalidRes = invalidRegex.exec(tempContent) - if (invalidRes) optionError("invalid_option",option,location,invalidRes[0],"user_not_found") - else optionError("missing_option",option,location) - } - //CHECK MENTIONABLE - }else if (option.type == "mentionable"){ - const mentionableRegex = /^<(@&?)([0-9]+)>/ - const res = mentionableRegex.exec(tempContent) - if (res){ - const value = res[0] - const type = (res[1] == "@&") ? "role" : "user" - tempContent = tempContent.substring(value.length+1) - const mentionableId = res[2] - - if (!msg.guild){ - optionError("invalid_option",option,location,value,"not_in_guild") - }else if (type == "role"){ - try { - const role = await msg.guild.roles.fetch(mentionableId) - if (!role){ - optionError("invalid_option",option,location,value,"mentionable_not_found") - }else{ - //VALID ROLE - optionData.push({ - name:option.name, - type:"mentionable", - value:role - }) - } - }catch{ - optionError("invalid_option",option,location,value,"mentionable_not_found") - } - }else if (type == "user"){ - try{ - const user = await this.manager.client.users.fetch(mentionableId) - if (!user){ - optionError("invalid_option",option,location,value,"mentionable_not_found") - }else{ - //VALID USER - optionData.push({ - name:option.name, - type:"mentionable", - value:user - }) - } - }catch{ - optionError("invalid_option",option,location,value,"mentionable_not_found") - } - } - }else if (option.required){ - //REQUIRED => ERROR IF NOT EXISTING - const invalidRegex = /^[^ ]+/ - const invalidRes = invalidRegex.exec(tempContent) - if (invalidRes) optionError("invalid_option",option,location,invalidRes[0],"mentionable_not_found") - else optionError("missing_option",option,location) - } - } - } - return {valid:!optionInvalid,data:optionData} - } - /**Start listening to the discord.js client `messageCreate` event. */ - startListeningToInteractions(){ - this.manager.client.on("messageCreate",(msg) => { - //return when not in main server or DM - if (!this.manager.mainServer || (msg.guild && msg.guild.id != this.manager.mainServer.id)) return - this.#checkMessage(msg) - }) - } - /**Check if optional values are only present at the end of the command. */ - #checkBuilderOptions(builder:ODTextCommandBuilder): {valid:boolean,reason:"required_after_optional"|"allowspaces_not_last"|null} { - let optionalVisited = false - let valid = true - let reason: "required_after_optional"|"allowspaces_not_last"|null = null - if (!builder.options) return {valid:true,reason:null} - builder.options.forEach((opt,index,list) => { - if (!opt.required) optionalVisited = true - if (optionalVisited && opt.required){ - valid = false - reason = "required_after_optional" - } - - if (opt.type == "string" && opt.allowSpaces && ((index+1) != list.length)){ - valid = false - reason = "allowspaces_not_last" - } - }) - - return {valid,reason} - } - /**Callback on interaction from one of the registered text commands */ - onInteraction(commandPrefix:string,commandName:string|RegExp, callback:ODTextCommandInteractionCallback){ - this.#interactionListeners.push({ - prefix:commandPrefix, - name:commandName, - callback - }) - - if (this.#interactionListeners.length > this.listenerLimit){ - this.#debug.console.log(new ODConsoleWarningMessage("Possible text command interaction memory leak detected!",[ - {key:"listeners",value:this.#interactionListeners.length.toString()} - ])) - } - } - /**Callback on error from all the registered text commands */ - onError(callback:ODTextCommandErrorCallback){ - this.#errorListeners.push(callback) - } - - add(data:ODTextCommand, overwrite?:boolean): boolean { - const checkResult = this.#checkBuilderOptions(data.builder) - if (!checkResult.valid && checkResult.reason == "required_after_optional") throw new ODSystemError("Invalid text command '"+data.id.value+"' => optional options are only allowed at the end of a command!") - else if (!checkResult.valid && checkResult.reason == "allowspaces_not_last") throw new ODSystemError("Invalid text command '"+data.id.value+"' => string option with 'allowSpaces' is only allowed at the end of a command!") - else return super.add(data,overwrite) - } -} - -/**## ODContextMenuUniversalMenu `interface` - * A universal template for a context menu. - * - * Why universal? Both **existing context menus** & **unregistered templates** can be converted to this type. - */ -export interface ODContextMenuUniversalMenu { - /**The type of this context menu. (required => `Message`|`User`) */ - type:discord.ApplicationCommandType.Message|discord.ApplicationCommandType.User, - /**The name of this context menu. */ - name:string, - /**All localized names of this context menu. */ - nameLocalizations:readonly ODSlashCommandUniversalTranslation[], - /**The id of the guild this context menu is registered in. */ - guildId:string|null, - /**Is this context menu for 18+ users only? */ - nsfw:boolean, - /**A bitfield of the user permissions required to use this context menu. */ - defaultMemberPermissions:bigint, - /**Is this context menu available in DM? */ - dmPermission:boolean, - /**A list of contexts where you can install this context menu. */ - integrationTypes:readonly discord.ApplicationIntegrationType[], - /**A list of contexts where you can use this context menu. */ - contexts:readonly discord.InteractionContextType[] -} - -/**## ODContextMenuBuilderMessage `interface` - * The builder for message context menus. - */ -export interface ODContextMenuBuilderMessage extends discord.MessageApplicationCommandData { - /**This field is required in Open Ticket for future compatibility. */ - integrationTypes:discord.ApplicationIntegrationType[], - /**This field is required in Open Ticket for future compatibility. */ - contexts:discord.InteractionContextType[] -} - -/**## ODContextMenuBuilderUser `interface` - * The builder for user context menus. - */ -export interface ODContextMenuBuilderUser extends discord.UserApplicationCommandData { - /**This field is required in Open Ticket for future compatibility. */ - integrationTypes:discord.ApplicationIntegrationType[], - /**This field is required in Open Ticket for future compatibility. */ - contexts:discord.InteractionContextType[] -} - -/**## ODContextMenuBuilderUser `interface` - * The builder for context menus. - */ -export type ODContextMenuBuilder = (ODContextMenuBuilderMessage|ODContextMenuBuilderUser) - -/**## ODContextMenuComparator `class` - * A utility class to compare existing context menu's with newly registered ones. - */ -export class ODContextMenuComparator { - /**Convert a `ODContextMenuBuilder` to a universal Open Ticket context menu object for comparison. */ - convertBuilder(builder:ODContextMenuBuilder,guildId:string|null): ODContextMenuUniversalMenu|null { - if (builder.type != discord.ApplicationCommandType.Message && builder.type != discord.ApplicationCommandType.User) return null - const nameLoc = builder.nameLocalizations ?? {} - - return { - type:builder.type, - name:builder.name, - nameLocalizations:Object.keys(nameLoc).map((key) => {return {language:key as `${discord.Locale}`,value:nameLoc[key]}}), - guildId:guildId, - nsfw:builder.nsfw ?? false, - defaultMemberPermissions:discord.PermissionsBitField.resolve(builder.defaultMemberPermissions ?? ["ViewChannel"]), - dmPermission:(builder.contexts && builder.contexts.includes(discord.InteractionContextType.BotDM)) ?? false, - integrationTypes:builder.integrationTypes ?? [discord.ApplicationIntegrationType.GuildInstall], - contexts:builder.contexts ?? [] - } - } - /**Convert a `discord.ApplicationCommand` to a universal Open Ticket context menu object for comparison. */ - convertMenu(cmd:discord.ApplicationCommand): ODContextMenuUniversalMenu|null { - if (cmd.type != discord.ApplicationCommandType.Message && cmd.type != discord.ApplicationCommandType.User) return null - const nameLoc = cmd.nameLocalizations ?? {} - - return { - type:cmd.type, - name:cmd.name, - nameLocalizations:Object.keys(nameLoc).map((key) => {return {language:key as `${discord.Locale}`,value:nameLoc[key]}}), - guildId:cmd.guildId, - nsfw:cmd.nsfw, - defaultMemberPermissions:discord.PermissionsBitField.resolve(cmd.defaultMemberPermissions ?? ["ViewChannel"]), - dmPermission:(cmd.contexts && cmd.contexts.includes(discord.InteractionContextType.BotDM)) ? true : false, - integrationTypes:cmd.integrationTypes ?? [discord.ApplicationIntegrationType.GuildInstall], - contexts:cmd.contexts ?? [] - } - } - /**Returns `true` when the 2 context menus are the same. */ - compare(ctxA:ODContextMenuUniversalMenu,ctxB:ODContextMenuUniversalMenu): boolean { - if (ctxA.name != ctxB.name) return false - if (ctxA.type != ctxB.type) return false - if (ctxA.nsfw != ctxB.nsfw) return false - if (ctxA.guildId != ctxB.guildId) return false - if (ctxA.dmPermission != ctxB.dmPermission) return false - if (ctxA.defaultMemberPermissions != ctxB.defaultMemberPermissions) return false - - //nameLocalizations - if (ctxA.nameLocalizations.length != ctxB.nameLocalizations.length) return false - if (!ctxA.nameLocalizations.every((nameA) => { - const nameB = ctxB.nameLocalizations.find((nameB) => nameB.language == nameA.language) - if (!nameB || nameA.value != nameB.value) return false - else return true - })) return false - - //contexts - if (ctxA.contexts.length != ctxB.contexts.length) return false - if (!ctxA.contexts.every((contextA) => { - return ctxB.contexts.includes(contextA) - })) return false - - //integrationTypes - if (ctxA.integrationTypes.length != ctxB.integrationTypes.length) return false - if (!ctxA.integrationTypes.every((integrationA) => { - return ctxB.integrationTypes.includes(integrationA) - })) return false - - return true - } -} - -/**## ODContextMenuInteractionCallback `type` - * Callback for the context menu interaction listener. - */ -export type ODContextMenuInteractionCallback = (interaction:discord.ContextMenuCommandInteraction,cmd:ODContextMenu) => void - -/**## ODContextMenuRegisteredResult `type` - * The result which will be returned when getting all (un)registered user context menu's from the manager. - */ -export type ODContextMenuRegisteredResult = { - /**A list of all registered context menus. */ - registered:{ - /**The instance (`ODContextMenu`) from this context menu. */ - instance:ODContextMenu, - /**The universal object/template/builder of this context menu. */ - menu:ODContextMenuUniversalMenu, - /**Does this context menu require an update? */ - requiresUpdate:boolean - }[], - /**A list of all unregistered context menus. */ - unregistered:{ - /**The instance (`ODContextMenu`) from this context menu. */ - instance:ODContextMenu, - /**The universal object/template/builder of this context menu. */ - menu:null, - /**Does this context menu require an update? */ - requiresUpdate:true - }[], - /**A list of all unused context menus (not found in `ODContextMenuManager`). */ - unused:{ - /**The instance (`ODContextMenu`) from this context menu. */ - instance:null, - /**The universal object/template/builder of this context menu. */ - menu:ODContextMenuUniversalMenu, - /**Does this context menu require an update? */ - requiresUpdate:false - }[] -} - -/**## ODContextMenuManager `class` - * This is an Open Ticket client context menu manager. - * - * It's responsible for managing all the context interactions from the client. - * - * Here, you can add & remove context interactions & the bot will do the (de)registering. - */ -export class ODContextMenuManager extends ODManager { - /**Alias to Open Ticket debugger. */ - #debug: ODDebugger - - /**Refrerence to discord.js client. */ - manager: ODClientManager - /**Discord.js application commands manager. */ - commandManager: discord.ApplicationCommandManager|null - /**Collection of all interaction listeners. */ - #interactionListeners: {name:string|RegExp, callback:ODContextMenuInteractionCallback}[] = [] - /**Set the soft limit for maximum amount of listeners. A warning will be shown when there are more listeners than this limit. */ - listenerLimit: number = 100 - /**A utility class used to compare 2 context menus with each other. */ - comparator: ODContextMenuComparator = new ODContextMenuComparator() - - constructor(debug:ODDebugger, manager:ODClientManager){ - super(debug,"context menu") - this.#debug = debug - this.manager = manager - this.commandManager = (manager.client.application) ? manager.client.application.commands : null - } - - /**Get all registered & unregistered message context menu commands. */ - async getAllRegisteredMenus(guildId?:string): Promise { - if (!this.commandManager) throw new ODSystemError("Couldn't get client application to register message context menus!") - - const menus = (await this.commandManager.fetch({guildId})).toJSON() - const registered: {instance:ODContextMenu, menu:ODContextMenuUniversalMenu, requiresUpdate:boolean}[] = [] - const unregistered: {instance:ODContextMenu, menu:null, requiresUpdate:true}[] = [] - const unused: {instance:null, menu:ODContextMenuUniversalMenu, requiresUpdate:false}[] = [] - - await this.loopAll((instance) => { - if (guildId && instance.guildId != guildId) return - - const index = menus.findIndex((menu) => menu.name == instance.name) - const menu = menus[index] - menus.splice(index,1) - if (menu){ - //menu is registered (and may need to be updated) - const universalBuilder = this.comparator.convertBuilder(instance.builder,instance.guildId) - const universalMenu = this.comparator.convertMenu(menu) - - //menu is not of the type 'message'|'user' - if (!universalBuilder || !universalMenu) return - - const didChange = !this.comparator.compare(universalBuilder,universalMenu) - const requiresUpdate = didChange || (instance.requiresUpdate ? instance.requiresUpdate(universalMenu) : false) - registered.push({instance,menu:universalMenu,requiresUpdate}) - - //menu is not registered - }else unregistered.push({instance,menu:null,requiresUpdate:true}) - }) - - menus.forEach((menu) => { - //menu does not exist in the manager (only append to unused when type == 'message'|'user') - const universalCmd = this.comparator.convertMenu(menu) - if (!universalCmd) return - unused.push({instance:null,menu:universalCmd,requiresUpdate:false}) - }) - - return {registered,unregistered,unused} - } - /**Create all context menus that are not registered yet.*/ - async createNewMenus(instances:ODContextMenu[],progress?:ODManualProgressBar){ - if (!this.manager.ready) throw new ODSystemError("Client isn't ready yet! Unable to register context menus!") - if (instances.length > 0 && progress){ - progress.max = instances.length - progress.start() - } - - for (const instance of instances){ - await this.createMenu(instance) - this.#debug.debug("Created new context menu",[ - {key:"id",value:instance.id.value}, - {key:"name",value:instance.name}, - {key:"type",value:(instance.builder.type == discord.ApplicationCommandType.Message) ? "message-context" : "user-context"} - ]) - if (progress) progress.increase(1) - } - } - /**Update all context menus that are already registered. */ - async updateExistingMenus(instances:ODContextMenu[],progress?:ODManualProgressBar){ - if (!this.manager.ready) throw new ODSystemError("Client isn't ready yet! Unable to register context menus!") - if (instances.length > 0 && progress){ - progress.max = instances.length - progress.start() - } - - for (const instance of instances){ - await this.createMenu(instance) - this.#debug.debug("Updated existing context menu",[ - {key:"id",value:instance.id.value}, - {key:"name",value:instance.name}, - {key:"type",value:(instance.builder.type == discord.ApplicationCommandType.Message) ? "message-context" : "user-context"} - ]) - if (progress) progress.increase(1) - } - } - /**Remove all context menus that are registered but unused by Open Ticket. */ - async removeUnusedMenus(instances:ODContextMenuUniversalMenu[],guildId?:string,progress?:ODManualProgressBar){ - if (!this.manager.ready) throw new ODSystemError("Client isn't ready yet! Unable to register context menus!") - if (!this.commandManager) throw new ODSystemError("Couldn't get client application to register context menus!") - if (instances.length > 0 && progress){ - progress.max = instances.length - progress.start() - } - - const menus = await this.commandManager.fetch({guildId}) - - for (const instance of instances){ - const menu = menus.find((menu) => menu.name == instance.name) - if (menu){ - try { - await menu.delete() - this.#debug.debug("Removed existing context menu",[ - {key:"name",value:menu.name}, - {key:"guildId",value:guildId ?? "/"}, - {key:"type",value:(instance.type == discord.ApplicationCommandType.Message) ? "message-context" : "user-context"} - ]) - }catch(err){ - process.emit("uncaughtException",err) - throw new ODSystemError("Failed to delete context menu '"+menu.name+"'!") - } - } - if (progress) progress.increase(1) - } - } - /**Create a context menu. **(SYSTEM ONLY)** => Use `ODContextMenuManager` for registering context menu's the default way! */ - async createMenu(menu:ODContextMenu){ - if (!this.commandManager) throw new ODSystemError("Couldn't get client application to register context menu's!") - try { - await this.commandManager.create(menu.builder,(menu.guildId ?? undefined)) - }catch(err){ - process.emit("uncaughtException",err) - throw new ODSystemError("Failed to register context menu '"+menu.name+"'!") - } - } - /**Start listening to the discord.js client `interactionCreate` event. */ - startListeningToInteractions(){ - this.manager.client.on("interactionCreate",(interaction) => { - //return when not in main server or DM - if (!this.manager.mainServer || (interaction.guild && interaction.guild.id != this.manager.mainServer.id)) return - - if (!interaction.isContextMenuCommand()) return - const menu = this.getFiltered((menu) => menu.name == interaction.commandName)[0] - if (!menu) return - - this.#interactionListeners.forEach((listener) => { - if (typeof listener.name == "string" && (interaction.commandName != listener.name)) return - else if (listener.name instanceof RegExp && !listener.name.test(interaction.commandName)) return - - //this is a valid listener - listener.callback(interaction,menu) - }) - }) - } - /**Callback on interaction from one or multiple context menu's. */ - onInteraction(menuName:string|RegExp, callback:ODContextMenuInteractionCallback){ - this.#interactionListeners.push({ - name:menuName, - callback - }) - - if (this.#interactionListeners.length > this.listenerLimit){ - this.#debug.console.log("Possible context menu interaction memory leak detected!","warning",[ - {key:"listeners",value:this.#interactionListeners.length.toString()} - ]) - } - } -} - -/**## ODContextMenuUpdateFunction `type` - * The function responsible for updating context menu's when they already exist. - */ -export type ODContextMenuUpdateFunction = (menu:ODContextMenuUniversalMenu) => boolean - -/**## ODContextMenu `class` - * This is an Open Ticket context menu. - * - * When registered, you can listen for this context menu using the `ODContextResponder`. The advantages of using this class for creating a context menu are: - * - automatic registration in discord.js - * - error reporting to the user when the bot fails to respond - * - plugins can extend this context menu - * - the bot won't re-register the context menu when it already exists (except when requested)! - * - * And more! - */ -export class ODContextMenu extends ODManagerData { - /**The discord.js builder for this context menu. */ - builder: ODContextMenuBuilder - /**The id of the guild this context menu is for. `null` when not set. */ - guildId: string|null - /**Function to check if the context menu requires to be updated (when it already exists). */ - requiresUpdate: ODContextMenuUpdateFunction|null = null - - constructor(id:ODValidId, builder:ODContextMenuBuilder, requiresUpdate?:ODContextMenuUpdateFunction, guildId?:string){ - super(id) - if (builder.type != discord.ApplicationCommandType.Message && builder.type != discord.ApplicationCommandType.User) throw new ODSystemError("ApplicationCommandData is required to be the 'Message'|'User' type!") - - this.builder = builder - this.guildId = guildId ?? null - this.requiresUpdate = requiresUpdate ?? null - } - - /**The name of this context menu. */ - get name(): string { - return this.builder.name - } - set name(name:string){ - this.builder.name = name - } -} - -/**## ODAutocompleteInteractionCallback `type` - * Callback for the autocomplete interaction listener. - */ -export type ODAutocompleteInteractionCallback = (interaction:discord.AutocompleteInteraction) => void - -/**## ODAutocompleteManager `class` - * This is an Open Ticket client autocomplete interaction manager. - * - * It's responsible for managing all the autocomplete interactions from the client. - */ -export class ODAutocompleteManager { - /**Alias to Open Ticket debugger. */ - #debug: ODDebugger - - /**Refrerence to discord.js client. */ - manager: ODClientManager - /**Discord.js application commands manager. */ - commandManager: discord.ApplicationCommandManager|null - /**Collection of all interaction listeners. */ - #interactionListeners: {cmdName:string|RegExp, optName:string|RegExp, callback:ODAutocompleteInteractionCallback}[] = [] - /**Set the soft limit for maximum amount of listeners. A warning will be shown when there are more listeners than this limit. */ - listenerLimit: number = 100 - - constructor(debug:ODDebugger, manager:ODClientManager){ - this.#debug = debug - this.manager = manager - this.commandManager = (manager.client.application) ? manager.client.application.commands : null - } - - /**Start listening to the discord.js client `interactionCreate` event. */ - startListeningToInteractions(){ - this.manager.client.on("interactionCreate",(interaction) => { - //return when not in main server or DM - if (!this.manager.mainServer || (interaction.guild && interaction.guild.id != this.manager.mainServer.id)) return - - if (!interaction.isAutocomplete()) return - this.#interactionListeners.forEach((listener) => { - - if (typeof listener.cmdName == "string" && (interaction.commandName != listener.cmdName)) return - else if (listener.cmdName instanceof RegExp && !listener.cmdName.test(interaction.commandName)) return - if (typeof listener.optName == "string" && (interaction.options.getFocused(true).name != listener.optName)) return - else if (listener.optName instanceof RegExp && !listener.optName.test(interaction.options.getFocused(true).name)) return - - //this is a valid listener - listener.callback(interaction) - }) - }) - } - /**Callback on interaction from one or multiple autocompletes. */ - onInteraction(cmdName:string|RegExp,optName:string|RegExp,callback:ODAutocompleteInteractionCallback){ - this.#interactionListeners.push({ - cmdName,optName,callback - }) - - if (this.#interactionListeners.length > this.listenerLimit){ - this.#debug.console.log("Possible autocomplete interaction memory leak detected!","warning",[ - {key:"listeners",value:this.#interactionListeners.length.toString()} - ]) - } - } -} \ No newline at end of file diff --git a/src/core/api/modules/code.ts b/src/core/api/modules/code.ts deleted file mode 100644 index a655b46..0000000 --- a/src/core/api/modules/code.ts +++ /dev/null @@ -1,58 +0,0 @@ -/////////////////////////////////////// -//CODE MODULE -/////////////////////////////////////// -import { ODId, ODManager, ODManagerData, ODValidId } from "./base" -import { ODDebugger } from "./console" - - -/**## ODCode `class` - * This is an Open Ticket code runner. - * - * Using this, you're able to execute a function just before the startup screen. (90% of the code is already loaded) - * You can also specify a priority to change the execution order. - * In Open Ticket, this is used for the following processes: - * - Autoclose/delete - * - Database syncronisation (with tickets, stats & used options) - * - Panel auto-update - * - Database Garbage Collection (removing tickets that don't exist anymore) - * - And more! - */ -export class ODCode extends ODManagerData { - /**The priority of this code */ - priority: number - /**The main function of this code */ - func: () => void|Promise - - constructor(id:ODValidId, priority:number, func:() => void|Promise){ - super(id) - this.priority = priority - this.func = func - } -} - -/**## ODCodeManager `class` - * This is an Open Ticket code manager. - * - * It manages & executes `ODCode`'s in the correct order. - * - * Use this to register a function/code which executes just before the startup screen. (90% is already loaded) - */ -export class ODCodeManager extends ODManager { - constructor(debug:ODDebugger){ - super(debug,"code") - } - - /**Execute all `ODCode` functions in order of their priority (high to low). */ - async execute(){ - const derefArray = [...this.getAll()] - const workers = derefArray.sort((a,b) => b.priority-a.priority) - - for (const worker of workers){ - try { - await worker.func() - }catch(err){ - process.emit("uncaughtException",err) - } - } - } -} \ No newline at end of file diff --git a/src/core/api/modules/config.ts b/src/core/api/modules/config.ts deleted file mode 100644 index c59b11a..0000000 --- a/src/core/api/modules/config.ts +++ /dev/null @@ -1,159 +0,0 @@ -/////////////////////////////////////// -//CONFIG MODULE -/////////////////////////////////////// -import { ODId, ODManager, ODManagerData, ODPromiseVoid, ODSystemError, ODValidId } from "./base" -import nodepath from "path" -import { ODDebugger } from "./console" -import fs from "fs" -import * as fjs from "formatted-json-stringify" - -/**## ODConfigManager `class` - * This is an Open Ticket config manager. - * - * It manages all config files in the bot and allows plugins to access config files from Open Ticket & other plugins! - * - * You can use this class to get/change/add a config file (`ODConfig`) in your plugin! - */ -export class ODConfigManager extends ODManager { - /**Alias to Open Ticket debugger. */ - #debug: ODDebugger - - constructor(debug:ODDebugger){ - super(debug,"config") - this.#debug = debug - } - add(data:ODConfig|ODConfig[],overwrite?:boolean): boolean { - if (Array.isArray(data)) data.forEach((d) => d.useDebug(this.#debug)) - else data.useDebug(this.#debug) - return super.add(data,overwrite) - } - /**Init all config files. */ - async init(){ - for (const config of this.getAll()){ - try{ - await config.init() - }catch(err){ - process.emit("uncaughtException",new ODSystemError(err)) - } - } - } -} - -/**## ODConfig `class` - * This is an Open Ticket config helper. - * This class doesn't do anything at all, it just gives a template & basic methods for a config. Use `ODJsonConfig` instead! - * - * You can use this class if you want to create your own config implementation (e.g. `yml`, `xml`,...)! - */ -export class ODConfig extends ODManagerData { - /**The name of the file with extension. */ - file: string = "" - /**The path to the file relative to the main directory. */ - path: string = "" - /**An object/array of the entire config file! Variables inside it can be edited while the bot is running! */ - data: any - /**Is this config already initiated? */ - initiated: boolean = false - /**An array of listeners to run when the config gets reloaded. These are not executed on the initial loading. */ - protected reloadListeners: Function[] = [] - /**Alias to Open Ticket debugger. */ - protected debug: ODDebugger|null = null - - constructor(id:ODValidId, data:any){ - super(id) - this.data = data - } - - /**Use the Open Ticket debugger for logs. */ - useDebug(debug:ODDebugger|null){ - this.debug = debug - } - /**Init the config. */ - init(): ODPromiseVoid { - this.initiated = true - if (this.debug) this.debug.debug("Initiated config '"+this.file+"' in ODConfigManager.",[{key:"id",value:this.id.value}]) - //please implement this feature in your own config extension & extend this function. - } - /**Reload the config. Be aware that this doesn't update the config data everywhere in the bot! */ - reload(): ODPromiseVoid { - if (this.debug) this.debug.debug("Reloaded config '"+this.file+"' in ODConfigManager.",[{key:"id",value:this.id.value}]) - //please implement this feature in your own config extension & extend this function. - } - /**Save the edited config to the filesystem. This is used by the Interactive Setup CLI. It's not recommended to use this while the bot is running. */ - save(): ODPromiseVoid { - if (this.debug) this.debug.debug("Saved config '"+this.file+"' in ODConfigManager.",[{key:"id",value:this.id.value}]) - //please implement this feature in your own config extension & extend this function. - } - /**Listen for a reload of this JSON file! */ - onReload(cb:Function){ - this.reloadListeners.push(cb) - } - /**Remove all reload listeners. Not recommended! */ - removeAllReloadListeners(){ - this.reloadListeners = [] - } -} - -/**## ODJsonConfig `class` - * This is an Open Ticket JSON config. - * You can use this class to get & edit variables from the config files or to create your own JSON config! - * @example - * //create a config from: ./config/test.json with the id "some-config" - * const config = new api.ODJsonConfig("some-config","test.json") - * - * //create a config with custom dir: ./plugins/testplugin/test.json - * const config = new api.ODJsonConfig("plugin-config","test.json","./plugins/testplugin/") - */ -export class ODJsonConfig extends ODConfig { - formatter: fjs.custom.BaseFormatter - - constructor(id:ODValidId, file:string, customPath?:string, formatter?:fjs.custom.BaseFormatter){ - super(id,{}) - this.file = (file.endsWith(".json")) ? file : file+".json" - this.path = customPath ? nodepath.join("./",customPath,this.file) : nodepath.join("./config/",this.file) - this.formatter = formatter ?? new fjs.DefaultFormatter(null,true," ") - } - - /**Init the config. */ - init(): ODPromiseVoid { - if (!fs.existsSync(this.path)) throw new ODSystemError("Unable to parse config \""+nodepath.join("./",this.path)+"\", the file doesn't exist!") - try{ - this.data = JSON.parse(fs.readFileSync(this.path).toString()) - super.init() - }catch(err){ - process.emit("uncaughtException",err) - throw new ODSystemError("Unable to parse config \""+nodepath.join("./",this.path)+"\"!") - } - } - /**Reload the config. Be aware that this doesn't update the config data everywhere in the bot! */ - reload(){ - if (!this.initiated) throw new ODSystemError("Unable to reload config \""+nodepath.join("./",this.path)+"\", the file hasn't been initiated yet!") - if (!fs.existsSync(this.path)) throw new ODSystemError("Unable to reload config \""+nodepath.join("./",this.path)+"\", the file doesn't exist!") - try{ - this.data = JSON.parse(fs.readFileSync(this.path).toString()) - super.reload() - this.reloadListeners.forEach((cb) => { - try{ - cb() - }catch(err){ - process.emit("uncaughtException",err) - } - }) - }catch(err){ - process.emit("uncaughtException",err) - throw new ODSystemError("Unable to reload config \""+nodepath.join("./",this.path)+"\"!") - } - } - /**Save the edited config to the filesystem. This is used by the Interactive Setup CLI. It's not recommended to use this while the bot is running. */ - save(): ODPromiseVoid { - if (!this.initiated) throw new ODSystemError("Unable to save config \""+nodepath.join("./",this.path)+"\", the file hasn't been initiated yet!") - try{ - const contents = this.formatter.stringify(this.data) - fs.writeFileSync(this.path,contents) - super.save() - }catch(err){ - process.emit("uncaughtException",err) - throw new ODSystemError("Unable to save config \""+nodepath.join("./",this.path)+"\"!") - } - } -} \ No newline at end of file diff --git a/src/core/api/modules/console.ts b/src/core/api/modules/console.ts deleted file mode 100644 index f34399c..0000000 --- a/src/core/api/modules/console.ts +++ /dev/null @@ -1,665 +0,0 @@ -/////////////////////////////////////// -//CONSOLE MODULE -/////////////////////////////////////// -import { ODHTTPGetRequest, ODVersion, ODSystemError, ODPluginError, ODManager, ODManagerData, ODValidId } from "./base" -import { ODMain } from "../main" -import nodepath from "path" -import fs from "fs" -import ansis from "ansis" - -/**## ODValidConsoleColor `type` - * This is a collection of all the supported console colors within Open Ticket. - */ -export type ODValidConsoleColor = "white"|"red"|"yellow"|"green"|"blue"|"gray"|"cyan"|"magenta" - -/**## ODConsoleMessageParam `type` - * This interface contains all data required for a console log parameter within Open Ticket. - */ -export interface ODConsoleMessageParam { - /**The key of this parameter. */ - key:string, - /**The value of this parameter. */ - value:string, - /**When enabled, this parameter will only be shown in the debug file. */ - hidden?:boolean -} - -/**## ODConsoleMessage `class` - * This is an Open Ticket console message. - * - * It is used to create beautiful & styled logs in the console with a prefix, message & parameters. - * It also has full color support using `ansis` and parameters are parsed for you! - */ -export class ODConsoleMessage { - /**The main message sent in the console */ - message: string - /**An array of all the parameters in this message */ - params: ODConsoleMessageParam[] - /**The prefix of this message (!uppercase recommended!) */ - prefix: string - /**The color of the prefix of this message */ - color: ODValidConsoleColor - - constructor(message:string, prefix:string, color:ODValidConsoleColor, params?:ODConsoleMessageParam[]){ - this.message = message - this.params = params ? params : [] - this.prefix = prefix - - if (["white","red","yellow","green","blue","gray","cyan","magenta"].includes(color)){ - this.color = color - }else{ - this.color = "white" - } - } - /**Render this message to the console using `console.log`! Returns `false` when something went wrong. */ - render(){ - try { - const prefixcolor = ansis[this.color] - - const paramsstring = " "+this.createParamsString("gray") - const message = prefixcolor("["+this.prefix+"] ")+this.message - - console.log(message+paramsstring) - return true - }catch{ - return false - } - } - /**Create a more-detailed, non-colored version of this message to store it in the `otdebug.txt` file! */ - toDebugString(){ - const pstrings: string[] = [] - this.params.forEach((p) => { - pstrings.push(p.key+": "+p.value) - }) - const pstring = (pstrings.length > 0) ? " ("+pstrings.join(", ")+")" : "" - const date = new Date() - const dstring = `${date.getDate()}/${date.getMonth()+1}/${date.getFullYear()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}` - return `[${dstring} ${this.prefix}] ${this.message}${pstring}` - } - /**Render the parameters of this message in a specific color. */ - createParamsString(color:ODValidConsoleColor){ - let validcolor: ODValidConsoleColor = "white" - if (["white","red","yellow","green","blue","gray","cyan","magenta"].includes(color)){ - validcolor = color - } - - const pstrings: string[] = [] - this.params.forEach((p) => { - if (!p.hidden) pstrings.push(p.key+": "+p.value) - }) - - return (pstrings.length > 0) ? ansis[validcolor](" ("+pstrings.join(", ")+")") : "" - } - /**Set the message */ - setMessage(message:string){ - this.message = message - return this - } - /**Set the params */ - setParams(params:ODConsoleMessageParam[]){ - this.params = params - return this - } - /**Set the prefix */ - setPrefix(prefix:string){ - this.prefix = prefix - return this - } - /**Set the prefix color */ - setColor(color:ODValidConsoleColor){ - if (["white","red","yellow","green","blue","gray","cyan","magenta"].includes(color)){ - this.color = color - }else{ - this.color = "white" - } - return this - } -} - -/**## ODConsoleInfoMessage `class` - * This is an Open Ticket console info message. - * - * It is the same as a normal `ODConsoleMessage`, but it has a predefined prefix & color scheme for the "INFO" messages! - */ -export class ODConsoleInfoMessage extends ODConsoleMessage { - constructor(message:string,params?:ODConsoleMessageParam[]){ - super(message,"INFO","blue",params) - } -} - -/**## ODConsoleSystemMessage `class` - * This is an Open Ticket console system message. - * - * It is the same as a normal `ODConsoleMessage`, but it has a predefined prefix & color scheme for the "SYSTEM" messages! - */ -export class ODConsoleSystemMessage extends ODConsoleMessage { - constructor(message:string,params?:ODConsoleMessageParam[]){ - super(message,"SYSTEM","green",params) - } -} - -/**## ODConsolePluginMessage `class` - * This is an Open Ticket console plugin message. - * - * It is the same as a normal `ODConsoleMessage`, but it has a predefined prefix & color scheme for the "PLUGIN" messages! - */ -export class ODConsolePluginMessage extends ODConsoleMessage { - constructor(message:string,params?:ODConsoleMessageParam[]){ - super(message,"PLUGIN","magenta",params) - } -} - -/**## ODConsoleDebugMessage `class` - * This is an Open Ticket console debug message. - * - * It is the same as a normal `ODConsoleMessage`, but it has a predefined prefix & color scheme for the "DEBUG" messages! - */ -export class ODConsoleDebugMessage extends ODConsoleMessage { - constructor(message:string,params?:ODConsoleMessageParam[]){ - super(message,"DEBUG","cyan",params) - } -} - -/**## ODConsoleWarningMessage `class` - * This is an Open Ticket console warning message. - * - * It is the same as a normal `ODConsoleMessage`, but it has a predefined prefix & color scheme for the "WARNING" messages! - */ -export class ODConsoleWarningMessage extends ODConsoleMessage { - constructor(message:string,params?:ODConsoleMessageParam[]){ - super(message,"WARNING","yellow",params) - } -} - -/**## ODConsoleErrorMessage `class` - * This is an Open Ticket console error message. - * - * It is the same as a normal `ODConsoleMessage`, but it has a predefined prefix & color scheme for the "ERROR" messages! - */ -export class ODConsoleErrorMessage extends ODConsoleMessage { - constructor(message:string,params?:ODConsoleMessageParam[]){ - super(message,"ERROR","red",params) - } -} - -/**## ODError `class` - * This is an Open Ticket error. - * - * It is used to render and log Node.js errors & crashes in a styled way to the console & `otdebug.txt` file! - */ -export class ODError { - /**The original error that this class wraps around */ - error: Error|ODSystemError|ODPluginError - /**The origin of the original error */ - origin: NodeJS.UncaughtExceptionOrigin - - constructor(error:Error|ODSystemError|ODPluginError, origin:NodeJS.UncaughtExceptionOrigin){ - this.error = error - this.origin = origin - } - - /**Render this error to the console using `console.log`! Returns `false` when something went wrong. */ - render(){ - try { - let prefix = (this.error["_ODErrorType"] == "plugin") ? "PLUGIN ERROR" : ((this.error["_ODErrorType"] == "system") ? "OPENTICKET ERROR" : "UNKNOWN ERROR") - //title - console.log(ansis.red("["+prefix+"]: ")+this.error.message+" | origin: "+this.origin) - //stack trace - if (this.error.stack) console.log(ansis.gray(this.error.stack)) - //additional message - if (this.error["_ODErrorType"] == "plugin") console.log(ansis.red.bold("\nPlease report this error to the plugin developer and help us create a more stable plugin!")) - else console.log(ansis.red.bold("\nPlease report this error to our discord server and help us create a more stable ticket bot!")) - console.log(ansis.red("Also send the "+ansis.cyan.bold("otdebug.txt")+" file! It would help a lot!\n")) - return true - }catch{ - return false - } - } - /**Create a more-detailed, non-colored version of this error to store it in the `otdebug.txt` file! */ - toDebugString(){ - return "[UNKNOWN OD ERROR]: "+this.error.message+" | origin: "+this.origin+"\n"+this.error.stack - } -} - -/**## ODConsoleMessageTypes `type` - * This is a collection of all the default console message types within Open Ticket. - */ -export type ODConsoleMessageTypes = "info"|"system"|"plugin"|"debug"|"warning"|"error" - -/**## ODConsoleManager `class` - * This is the Open Ticket console manager. - * - * It handles the entire console system of Open Ticket. It's also the place where you need to log `ODConsoleMessage`'s. - * This manager keeps a short history of messages sent to the console which is configurable by plugins. - * - * The debug file (`otdebug.txt`) is handled in a sub-manager! - */ -export class ODConsoleManager { - /**The history of `ODConsoleMessage`'s and `ODError`'s since startup */ - history: (ODConsoleMessage|ODError)[] = [] - /**The max length of the history. The oldest messages will be removed when over the limit */ - historylength = 100 - /**An alias to the debugfile manager. (`otdebug.txt`) */ - debugfile: ODDebugFileManager - /**Is silent mode enabled? */ - silent: boolean = false - - constructor(historylength:number, debugfile:ODDebugFileManager){ - this.historylength = historylength - this.debugfile = debugfile - } - - /**Log a message to the console ... But in the Open Ticket way :) */ - log(message:ODConsoleMessage): void - log(message:ODError): void - log(message:string, type?:ODConsoleMessageTypes, params?:ODConsoleMessageParam[]): void - log(message:ODConsoleMessage|ODError|string, type?:ODConsoleMessageTypes, params?:ODConsoleMessageParam[]){ - if (message instanceof ODConsoleMessage){ - if (!this.silent) message.render() - if (this.debugfile) this.debugfile.writeConsoleMessage(message) - this.history.push(message) - - }else if (message instanceof ODError){ - if (!this.silent) message.render() - if (this.debugfile) this.debugfile.writeErrorMessage(message) - this.history.push(message) - - }else if (["string","number","boolean","object"].includes(typeof message)){ - let newMessage: ODConsoleMessage - if (type == "info") newMessage = new ODConsoleInfoMessage(message,params) - else if (type == "system") newMessage = new ODConsoleSystemMessage(message,params) - else if (type == "plugin") newMessage = new ODConsolePluginMessage(message,params) - else if (type == "debug") newMessage = new ODConsoleDebugMessage(message,params) - else if (type == "warning") newMessage = new ODConsoleWarningMessage(message,params) - else if (type == "error") newMessage = new ODConsoleErrorMessage(message,params) - else newMessage = new ODConsoleSystemMessage(message,params) - - if (!this.silent) newMessage.render() - if (this.debugfile) this.debugfile.writeConsoleMessage(newMessage) - this.history.push(newMessage) - } - this.#purgeHistory() - } - /**Shorten the history when it exceeds the max history length! */ - #purgeHistory(){ - if (this.history.length > this.historylength) this.history.shift() - } -} - -/**## ODDebugFileManager `class` - * This is the Open Ticket debug file manager. - * - * It manages the Open Ticket debug file (`otdebug.txt`) which keeps a history of all system logs. - * There are even internal logs that aren't logged to the console which are available in this file! - * - * Using this class, you can change the max length of this file and some other cool things! - */ -export class ODDebugFileManager { - /**The path to the debugfile (`./otdebug.txt` by default) */ - path: string - /**The filename of the debugfile (`otdebug.txt` by default) */ - filename: string - /**The current version of the bot used in the debug file. */ - version: ODVersion - /**The max length of the debug file. */ - maxlines: number - - constructor(path:string, filename:string, maxlines:number, version:ODVersion){ - this.path = nodepath.join(path,filename) - this.filename = filename - this.version = version - this.maxlines = maxlines - - this.#writeStartupStats() - } - - /**Check if the debug file exists */ - #existsDebugFile(){ - return fs.existsSync(this.path) - } - /**Read from the debug file */ - #readDebugFile(){ - if (this.#existsDebugFile()){ - try { - return fs.readFileSync(this.path).toString() - }catch{ - return false - } - }else{ - return false - } - } - /**Write to the debug file and shorten it when needed. */ - #writeDebugFile(text:string){ - const currenttext = this.#readDebugFile() - if (currenttext){ - const splitted = currenttext.split("\n") - - if (splitted.length+text.split("\n").length > this.maxlines){ - splitted.splice(7,(text.split("\n").length)) - } - - splitted.push(text) - fs.writeFileSync(this.path,splitted.join("\n")) - }else{ - //write new file: - const newtext = this.#createStatsText()+text - fs.writeFileSync(this.path,newtext) - } - } - /**Generate the stats/header of the debug file (containing the version) */ - #createStatsText(){ - const date = new Date() - const dstring = `${date.getDate()}/${date.getMonth()+1}/${date.getFullYear()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}` - return [ - "=========================", - "OPEN TICKET DEBUG FILE:", - "version: "+this.version.toString(), - "last startup: "+dstring, - "=========================\n\n" - ].join("\n") - } - /**Write the stats/header to the debug file on startup */ - #writeStartupStats(){ - const currenttext = this.#readDebugFile() - if (currenttext){ - //edit previous file: - const splitted = currenttext.split("\n") - splitted.splice(0,7) - - if (splitted.length+11 > this.maxlines){ - splitted.splice(0,((splitted.length+11) - this.maxlines)) - } - - splitted.unshift(this.#createStatsText()) - splitted.push("\n---------------------------------------------------------------------\n---------------------------------------------------------------------\n") - - fs.writeFileSync(this.path,splitted.join("\n")) - }else{ - //write new file: - const newtext = this.#createStatsText() - fs.writeFileSync(this.path,newtext) - } - } - /**Write an `ODConsoleMessage` to the debug file */ - writeConsoleMessage(message:ODConsoleMessage){ - this.#writeDebugFile(message.toDebugString()) - } - /**Write an `ODError` to the debug file */ - writeErrorMessage(error:ODError){ - this.#writeDebugFile(error.toDebugString()) - } - /**Write custom text to the debug file */ - writeText(text:string){ - this.#writeDebugFile(text) - } - /**Write a custom note to the debug file (starting with `[NOTE]:`) */ - writeNote(text:string){ - this.#writeDebugFile("[NOTE]: "+text) - } -} - -/**## ODDebugger `class` - * This is the Open Ticket debugger. - * - * It is a simple wrapper around the `ODConsoleManager` to handle debugging (primarily for `ODManagers`). - * Messages created using this debugger are only logged to the debug file unless specified otherwise. - * - * You will probably notice this class being used in the `ODManager` constructor. - * - * Using this system, all additions & removals inside a manager are logged to the debug file. This makes searching for errors a lot easier! - */ -export class ODDebugger { - /**An alias to the Open Ticket console manager. */ - console: ODConsoleManager - /**When enabled, debug logs are also shown in the console. */ - visible: boolean = false - - constructor(console:ODConsoleManager){ - this.console = console - } - - /**Create a debug message. This will always be logged to `otdebug.txt` & sometimes to the console (when enabled). Returns `true` when visible */ - debug(message:string, params?:{key:string,value:string}[]): boolean { - if (this.visible){ - this.console.log(new ODConsoleDebugMessage(message,params)) - return true - }else{ - this.console.debugfile.writeConsoleMessage(new ODConsoleDebugMessage(message,params)) - return false - } - } -} - -/**## ODLivestatusColor `type` - * This is a collection of all the colors available within the LiveStatus system. - */ -export type ODLiveStatusColor = "normal"|"red"|"green"|"blue"|"yellow"|"white"|"gray"|"magenta"|"cyan" - -/**## ODLiveStatusSourceData `interface` - * This is an interface containing all raw data received from the LiveStatus system. - */ -export interface ODLiveStatusSourceData { - /**The message to display */ - message:{ - /**The title of the message to display */ - title:string, - /**The title color of the message to display */ - titleColor:ODLiveStatusColor, - /**The description of the message to display */ - description:string, - /**The description color of the message to display */ - descriptionColor:ODLiveStatusColor - }, - /**The message will only be shown when the bot matches all statements */ - active:{ - /**A list of versions to match */ - versions:string[], - /**A list of languages to match */ - languages:string[], - /**All languages should match */ - allLanguages:boolean, - /**Match when the bot is using plugins */ - usingPlugins:boolean, - /**Match when the bot is not using plugins */ - notUsingPlugins:boolean, - /**Match when the bot is using slash commands */ - usingSlashCommands:boolean, - /**Match when the bot is not using slash commands */ - notUsingSlashCommands:boolean, - /**Match when the bot is not using transcripts */ - notUsingTranscripts:boolean, - /**Match when the bot is using text transcripts */ - usingTextTranscripts:boolean, - /**Match when the bot is using html transcripts */ - usingHtmlTranscripts:boolean - } -} - -/**## ODLiveStatusSource `class` - * This is the Open Ticket livestatus source. - * - * It is an empty template for a livestatus source. - * By default, you should use `ODLiveStatusUrlSource` or `ODLiveStatusFileSource`, - * unless you want to create one on your own! - * - * This class doesn't do anything on it's own! It's just a template! - */ -export class ODLiveStatusSource extends ODManagerData { - /**The raw data of this source */ - data: ODLiveStatusSourceData[] - - constructor(id:ODValidId, data:ODLiveStatusSourceData[]){ - super(id) - this.data = data - } - - /**Change the current data using this method! */ - setData(data:ODLiveStatusSourceData[]){ - this.data = data - } - /**Get all messages relevant to the bot based on some parameters. */ - async getMessages(main:ODMain): Promise { - const validMessages: ODLiveStatusSourceData[] = [] - - //parse data from ODMain - const currentVersion: string = main.versions.get("opendiscord:version").toString(true) - const usingSlashCommands: boolean = main.configs.get("opendiscord:general").data.slashCommands - const usingTranscripts: false|"text"|"html" = false as false|"text"|"html" //TODO - const currentLanguage: string = main.languages.getCurrentLanguageId() - const usingPlugins: boolean = (main.plugins.getLength() > 0) - - //check data for each message - this.data.forEach((msg) => { - const {active} = msg - - const correctVersion = active.versions.includes(currentVersion) - const correctSlashMode = (usingSlashCommands && active.usingSlashCommands) || (!usingSlashCommands && active.notUsingSlashCommands) - const correctTranscriptMode = (usingTranscripts == "text" && active.usingTextTranscripts) || (usingTranscripts == "html" && active.usingHtmlTranscripts) || (!usingTranscripts && active.notUsingTranscripts) - const correctLanguage = active.languages.includes(currentLanguage) || active.allLanguages - const correctPlugins = (usingPlugins && active.usingPlugins) || (!usingPlugins && active.notUsingPlugins) - - if (correctVersion && correctLanguage && correctPlugins && correctSlashMode && correctTranscriptMode) validMessages.push(msg) - }) - - //return the valid messages - return validMessages - } -} - -/**## ODLiveStatusFileSource `class` - * This is the Open Ticket livestatus file source. - * - * It is a LiveStatus source that will read the data from a local file. - * - * This can be used for testing/extending the LiveStatus system! - */ -export class ODLiveStatusFileSource extends ODLiveStatusSource { - /**The path to the source file */ - path: string - - constructor(id:ODValidId, path:string){ - if (fs.existsSync(path)){ - super(id,JSON.parse(fs.readFileSync(path).toString())) - }else throw new ODSystemError("LiveStatus source file doesn't exist!") - this.path = path - } -} - -/**## ODLiveStatusUrlSource `class` - * This is the Open Ticket livestatus url source. - * - * It is a LiveStatus source that will read the data from a http URL (json file). - * - * This is the default way of receiving LiveStatus messages! - */ -export class ODLiveStatusUrlSource extends ODLiveStatusSource { - /**The url used in the request */ - url: string - /**The `ODHTTPGetRequest` helper to fetch the url! */ - request: ODHTTPGetRequest - - constructor(id:ODValidId, url:string){ - super(id,[]) - this.url = url - this.request = new ODHTTPGetRequest(url,false) - } - async getMessages(main:ODMain): Promise { - //additional setup - this.request.url = this.url - const rawRes = await this.request.run() - if (rawRes.status != 200) throw new ODSystemError("ODLiveStatusUrlSource => Request Failed!") - try{ - this.setData(JSON.parse(rawRes.body)) - }catch{ - throw new ODSystemError("ODLiveStatusUrlSource => Request Failed!") - } - - //default - return super.getMessages(main) - } -} - -/**## ODLiveStatusManager `class` - * This is the Open Ticket livestatus manager. - * - * It manages all LiveStatus sources and has the renderer for all LiveStatus messages. - * - * You can use this to customise or add stuff to the LiveStatus system. - * Access it in the global `opendiscord.startscreen.livestatus` variable! - */ -export class ODLiveStatusManager extends ODManager { - /**The class responsible for rendering the livestatus messages. */ - renderer: ODLiveStatusRenderer - /**A reference to the ODMain or "openticket" global variable */ - #main: ODMain - - constructor(debug:ODDebugger, main:ODMain){ - super(debug,"livestatus source") - this.renderer = new ODLiveStatusRenderer(main.console) - this.#main = main - } - - /**Get the messages from all sources combined! */ - async getAllMessages(): Promise { - const messages: ODLiveStatusSourceData[] = [] - for (const source of this.getAll()){ - try { - messages.push(...(await source.getMessages(this.#main))) - }catch{} - } - return messages - } -} - -/**## ODLiveStatusRenderer `class` - * This is the Open Ticket livestatus renderer. - * - * It's responsible for rendering all LiveStatus messages to the console. - */ -export class ODLiveStatusRenderer { - /**A reference to the ODConsoleManager or "opendiscord.console" global variable */ - #console: ODConsoleManager - - constructor(console:ODConsoleManager){ - this.#console = console - } - - /**Render all messages */ - render(messages:ODLiveStatusSourceData[]): string { - try { - //process data - const final: string[] = [] - messages.forEach((msg) => { - const titleColor = msg.message.titleColor - const title = "["+msg.message.title+"] " - - const descriptionColor = msg.message.descriptionColor - const description = msg.message.description.split("\n").map((text,row) => { - //first row row doesn't need prefix - if (row < 1) return text - //other rows do need a prefix - let text2 = text - for (const i of title){ - text2 = " "+text2 - } - return text2 - }).join("\n") - - - if (!["red","yellow","green","blue","gray","magenta","cyan"].includes(titleColor)) var finalTitle = ansis.white(title) - else var finalTitle = ansis[titleColor](title) - if (!["red","yellow","green","blue","gray","magenta","cyan"].includes(descriptionColor)) var finalDescription = ansis.white(description) - else var finalDescription = ansis[descriptionColor](description) - - final.push(finalTitle+finalDescription) - }) - - //return all messages - return final.join("\n") - }catch{ - this.#console.log("Failed to render LiveStatus messages!","error") - return "" - } - } -} \ No newline at end of file diff --git a/src/core/api/modules/cooldown.ts b/src/core/api/modules/cooldown.ts deleted file mode 100644 index ad5abfe..0000000 --- a/src/core/api/modules/cooldown.ts +++ /dev/null @@ -1,348 +0,0 @@ -/////////////////////////////////////// -//COOLDOWN MODULE -/////////////////////////////////////// -import { ODId, ODValidId, ODManager, ODSystemError, ODManagerData } from "./base" -import { ODDebugger } from "./console" - -/**## ODCooldownManager `class` - * This is an Open Ticket cooldown manager. - * - * It is responsible for managing all cooldowns in Open Ticket. An example of this is the ticket creation cooldown. - * - * There are many types of cooldowns available, but you can also create your own! - */ -export class ODCooldownManager extends ODManager> { - constructor(debug:ODDebugger){ - super(debug,"cooldown") - } - /**Initiate all cooldowns in this manager. */ - async init(){ - for (const cooldown of this.getAll()){ - await cooldown.init() - } - } -} - -/**## ODCooldownData `class` - * This is Open Ticket cooldown data. - * - * It contains the instance of an active cooldown (e.g. for a user). It is handled by the cooldown itself. - */ -export class ODCooldownData extends ODManagerData { - /**Is this cooldown active? */ - active: boolean - /**Additional data of this cooldown instance. (different for each cooldown type) */ - data: Data - - constructor(id:ODValidId,active:boolean,data:Data){ - super(id) - this.active = active - this.data = data - } -} - -/**## ODCooldown `class` - * This is an Open Ticket cooldown. - * - * It doesn't do anything on it's own, but it provides the methods that are used to interact with a cooldown. - * This class can be extended from to create a working cooldown. - * - * There are also premade cooldowns available in the bot! - */ -export class ODCooldown extends ODManagerData { - data: ODManager> = new ODManager() - /**Is this cooldown already initialized? */ - ready: boolean = false - - constructor(id:ODValidId){ - super(id) - } - - /**Check this id and start cooldown when it exeeds the limit! Returns `true` when on cooldown! */ - use(id:string): boolean { - throw new ODSystemError("Tried to use an unimplemented ODCooldown!") - } - /**Check this id without starting or updating the cooldown. Returns `true` when on cooldown! */ - check(id:string): boolean { - throw new ODSystemError("Tried to use an unimplemented ODCooldown!") - } - /**Remove the cooldown for an id when available.*/ - delete(id:string){ - throw new ODSystemError("Tried to use an unimplemented ODCooldown!") - } - /**Initialize the internal systems of this cooldown. */ - async init(){ - throw new ODSystemError("Tried to use an unimplemented ODCooldown!") - } -} - -/**## ODCounterCooldown `class` - * This is an Open Ticket counter cooldown. - * - * It is is a cooldown based on a counter. When the number exceeds the limit, the cooldown is activated. - * The number will automatically be decreased with a set amount & interval. - */ -export class ODCounterCooldown extends ODCooldown<{value:number}> { - /**The cooldown will activate when exceeding this limit. */ - activeLimit: number - /**The cooldown will deactivate when below this limit. */ - cancelLimit: number - /**The amount to increase the counter with everytime the cooldown is triggered/updated. */ - increment: number - /**The amount to decrease the counter over time. */ - decrement: number - /**The interval between decrements in milliseconds. */ - invervalMs: number - - constructor(id:ODValidId, activeLimit:number, cancelLimit:number, increment:number, decrement:number, intervalMs:number){ - super(id) - this.activeLimit = activeLimit - this.cancelLimit = cancelLimit - this.increment = increment - this.decrement = decrement - this.invervalMs = intervalMs - } - - use(id:string): boolean { - const cooldown = this.data.get(id) - if (cooldown){ - //cooldown for this id already exists - if (cooldown.active){ - return true - - }else if (cooldown.data.value < this.activeLimit){ - cooldown.data.value = cooldown.data.value + this.increment - return false - - }else{ - cooldown.active = true - return false - } - }else{ - //cooldown for this id doesn't exist - this.data.add(new ODCooldownData(id,(this.increment >= this.activeLimit),{ - value:this.increment - })) - return false - } - } - check(id:string): boolean { - const cooldown = this.data.get(id) - if (cooldown){ - //cooldown for this id already exists - return cooldown.active - }else return false - } - delete(id:string): void { - this.data.remove(id) - } - async init(){ - if (this.ready) return - setInterval(async () => { - await this.data.loopAll((cooldown) => { - cooldown.data.value = cooldown.data.value - this.decrement - if (cooldown.data.value <= this.cancelLimit){ - cooldown.active = false - } - if (cooldown.data.value <= 0){ - this.data.remove(cooldown.id) - } - }) - },this.invervalMs) - this.ready = true - } -} - -/**## ODIncrementalCounterCooldown `class` - * This is an Open Ticket incremental counter cooldown. - * - * It is is a cooldown based on an incremental counter. It is exactly the same as the normal counter, - * with the only difference being that it still increments when the limit is already exeeded. - */ -export class ODIncrementalCounterCooldown extends ODCooldown<{value:number}> { - /**The cooldown will activate when exceeding this limit. */ - activeLimit: number - /**The cooldown will deactivate when below this limit. */ - cancelLimit: number - /**The amount to increase the counter with everytime the cooldown is triggered/updated. */ - increment: number - /**The amount to decrease the counter over time. */ - decrement: number - /**The interval between decrements in milliseconds. */ - invervalMs: number - - constructor(id:ODValidId, activeLimit:number, cancelLimit:number, increment:number, decrement:number, intervalMs:number){ - super(id) - this.activeLimit = activeLimit - this.cancelLimit = cancelLimit - this.increment = increment - this.decrement = decrement - this.invervalMs = intervalMs - } - - use(id:string): boolean { - const cooldown = this.data.get(id) - if (cooldown){ - //cooldown for this id already exists - if (cooldown.active){ - cooldown.data.value = cooldown.data.value + this.increment - return true - - }else if (cooldown.data.value < this.activeLimit){ - cooldown.data.value = cooldown.data.value + this.increment - return false - - }else{ - cooldown.active = true - return false - } - }else{ - //cooldown for this id doesn't exist - this.data.add(new ODCooldownData(id,(this.increment >= this.activeLimit),{ - value:this.increment - })) - return false - } - } - check(id:string): boolean { - const cooldown = this.data.get(id) - if (cooldown){ - //cooldown for this id already exists - return cooldown.active - }else return false - } - delete(id:string): void { - this.data.remove(id) - } - async init(){ - if (this.ready) return - setInterval(async () => { - await this.data.loopAll((cooldown) => { - cooldown.data.value = cooldown.data.value - this.decrement - if (cooldown.data.value <= this.cancelLimit){ - cooldown.active = false - } - if (cooldown.data.value <= 0){ - this.data.remove(cooldown.id) - } - }) - },this.invervalMs) - this.ready = true - } -} - -/**## ODTimeoutCooldown `class` - * This is an Open Ticket timeout cooldown. - * - * It is a cooldown based on a timer. When triggered/updated, the cooldown is activated for the set amount of time. - * After the timer has timed out, the cooldown will be deleted. - */ -export class ODTimeoutCooldown extends ODCooldown<{date:number}> { - /**The amount of milliseconds before the cooldown times-out */ - timeoutMs: number - - constructor(id:ODValidId, timeoutMs:number){ - super(id) - this.timeoutMs = timeoutMs - } - - use(id:string): boolean { - const cooldown = this.data.get(id) - if (cooldown){ - //cooldown for this id already exists - if ((new Date().getTime() - cooldown.data.date) > this.timeoutMs){ - this.data.remove(id) - return false - }else{ - return true - } - }else{ - //cooldown for this id doesn't exist - this.data.add(new ODCooldownData(id,true,{ - date:new Date().getTime() - })) - return false - } - } - check(id:string): boolean { - const cooldown = this.data.get(id) - if (cooldown){ - //cooldown for this id already exists - return true - }else return false - } - delete(id:string): void { - this.data.remove(id) - } - /**Get the remaining amount of milliseconds before the timeout stops. */ - remaining(id:string): number|null { - const cooldown = this.data.get(id) - if (!cooldown) return null - const rawResult = this.timeoutMs - (new Date().getTime() - cooldown.data.date) - return (rawResult > 0) ? rawResult : 0 - } - async init(){ - if (this.ready) return - this.ready = true - } -} - -/**## ODIncrementalTimeoutCooldown `class` - * This is an Open Ticket incremental timeout cooldown. - * - * It is is a cooldown based on an incremental timer. It is exactly the same as the normal timer, - * with the only difference being that it adds additional time when triggered/updated while the cooldown is already active. - */ -export class ODIncrementalTimeoutCooldown extends ODCooldown<{date:number}> { - /**The amount of milliseconds before the cooldown times-out */ - timeoutMs: number - /**The amount of milliseconds to add when triggered/updated while the cooldown is already active. */ - incrementMs: number - - constructor(id:ODValidId, timeoutMs:number, incrementMs:number){ - super(id) - this.timeoutMs = timeoutMs - this.incrementMs = incrementMs - } - - use(id:string): boolean { - const cooldown = this.data.get(id) - if (cooldown){ - //cooldown for this id already exists - if ((new Date().getTime() - cooldown.data.date) > this.timeoutMs){ - this.data.remove(id) - return false - }else{ - cooldown.data.date = cooldown.data.date + this.incrementMs - return true - } - }else{ - //cooldown for this id doesn't exist - this.data.add(new ODCooldownData(id,true,{ - date:new Date().getTime() - })) - return false - } - } - check(id:string): boolean { - const cooldown = this.data.get(id) - if (cooldown){ - //cooldown for this id already exists - return true - }else return false - } - delete(id:string): void { - this.data.remove(id) - } - /**Get the remaining amount of milliseconds before the timeout stops. */ - remaining(id:string): number|null { - const cooldown = this.data.get(id) - if (!cooldown) return null - const rawResult = this.timeoutMs - (new Date().getTime() - cooldown.data.date) - return (rawResult > 0) ? rawResult : 0 - } - async init(){ - if (this.ready) return - this.ready = true - } -} \ No newline at end of file diff --git a/src/core/api/modules/database.ts b/src/core/api/modules/database.ts deleted file mode 100644 index ab6d601..0000000 --- a/src/core/api/modules/database.ts +++ /dev/null @@ -1,278 +0,0 @@ -/////////////////////////////////////// -//DATABASE MODULE -/////////////////////////////////////// -import { ODId, ODManager, ODManagerData, ODOptionalPromise, ODPromiseVoid, ODSystemError, ODValidId, ODValidJsonType } from "./base" -import fs from "fs" -import nodepath from "path" -import { ODDebugger } from "./console" -import * as fjs from "formatted-json-stringify" - -/**## ODDatabaseManager `class` - * This is an Open Ticket database manager. - * - * It manages all databases in the bot and allows to permanently store data from the bot! - * - * You can use this class to get/add a database (`ODDatabase`) in your plugin! - */ -export class ODDatabaseManager extends ODManager { - constructor(debug:ODDebugger){ - super(debug,"database") - } - - /**Init all database files. */ - async init(){ - for (const database of this.getAll()){ - try{ - await database.init() - }catch(err){ - process.emit("uncaughtException",new ODSystemError(err)) - } - } - } -} - -/**## ODDatabase `class` - * This is an Open Ticket database template. - * This class doesn't do anything at all, it just gives a template & basic methods for a database. Use `ODJsonDatabase` instead! - * - * You can use this class if you want to create your own database implementation (e.g. `mongodb`, `mysql`,...)! - */ -export class ODDatabase extends ODManagerData { - /**The name of the file with extension. */ - file: string = "" - /**The path to the file relative to the main directory. */ - path: string = "" - - /**Init the database. */ - init(): ODPromiseVoid { - //nothing - } - /**Add/Overwrite a specific category & key in the database. Returns `true` when overwritten. */ - set(category:string, key:string, value:ODValidJsonType): ODOptionalPromise { - return false - } - /**Get a specific category & key in the database */ - get(category:string, key:string): ODOptionalPromise { - return undefined - } - /**Delete a specific category & key in the database */ - delete(category:string, key:string): ODOptionalPromise { - return false - } - /**Check if a specific category & key exists in the database */ - exists(category:string, key:string): ODOptionalPromise { - return false - } - /**Get a specific category in the database */ - getCategory(category:string): ODOptionalPromise<{key:string, value:ODValidJsonType}[]|undefined> { - return undefined - } - /**Get all values in the database */ - getAll(): ODOptionalPromise { - return [] - } -} - -/**## ODJsonDatabaseStructure `type` - * This is the structure of how a JSON database file! - */ -export type ODJsonDatabaseStructure = {category:string, key:string, value:ODValidJsonType}[] - -/**## ODJsonDatabase `class` - * This is an Open Ticket JSON database. - * It stores data in a `json` file as a large `Array` using the `category`, `key`, `value` strategy. - * You can store the following types: `string`, `number`, `boolean`, `array`, `object` & `null`! - * - * You can use this class if you want to add your own database or to use an existing one! - */ -export class ODJsonDatabase extends ODDatabase { - constructor(id:ODValidId, file:string, customPath?:string){ - super(id) - this.file = (file.endsWith(".json")) ? file : file+".json" - this.path = customPath ? nodepath.join("./",customPath,this.file) : nodepath.join("./database/",this.file) - } - - /**Init the database. */ - init(): ODPromiseVoid { - this.#system.getData() - } - /**Set/overwrite the value of `category` & `key`. Returns `true` when overwritten! - * @example - * const didOverwrite = database.setData("category","key","value") //value can be any of the valid types - * //You need an ODJsonDatabase class named "database" for this example to work! - */ - set(category:string, key:string, value:ODValidJsonType): ODOptionalPromise { - const currentList = this.#system.getData() - const currentData = currentList.find((d) => (d.category === category) && (d.key === key)) - - //overwrite when already present - if (currentData){ - currentList[currentList.indexOf(currentData)].value = value - }else{ - currentList.push({category,key,value}) - } - - this.#system.setData(currentList) - return currentData ? true : false - } - /**Get the value of `category` & `key`. Returns `undefined` when non-existent! - * @example - * const data = database.getData("category","key") //data will be the value - * //You need an ODJsonDatabase class named "database" for this example to work! - */ - get(category:string, key:string): ODOptionalPromise { - const currentList = this.#system.getData() - const tempresult = currentList.find((d) => (d.category === category) && (d.key === key)) - return tempresult ? tempresult.value : undefined - } - /**Remove the value of `category` & `key`. Returns `undefined` when non-existent! - * @example - * const didExist = database.deleteData("category","key") //delete this value - * //You need an ODJsonDatabase class named "database" for this example to work! - */ - delete(category:string, key:string): ODOptionalPromise { - const currentList = this.#system.getData() - const currentData = currentList.find((d) => (d.category === category) && (d.key === key)) - if (currentData) currentList.splice(currentList.indexOf(currentData),1) - - this.#system.setData(currentList) - return currentData ? true : false - } - /**Check if a value of `category` & `key` exists. Returns `false` when non-existent! */ - exists(category:string, key:string): ODOptionalPromise { - const currentList = this.#system.getData() - const tempresult = currentList.find((d) => (d.category === category) && (d.key === key)) - return tempresult ? true : false - } - /**Get all values in `category`. Returns `undefined` when non-existent! */ - getCategory(category:string): ODOptionalPromise<{key:string, value:ODValidJsonType}[]|undefined> { - const currentList = this.#system.getData() - const tempresult = currentList.filter((d) => (d.category === category)) - return tempresult ? tempresult.map((data) => {return {key:data.key,value:data.value}}) : undefined - } - /**Get all values in `category`. */ - getAll(): ODOptionalPromise { - return this.#system.getData() - } - - #system = { - /**Read parsed data from the json file */ - getData: (): ODJsonDatabaseStructure => { - if (fs.existsSync(this.path)){ - try{ - return JSON.parse(fs.readFileSync(this.path).toString()) - }catch(err){ - process.emit("uncaughtException",err) - throw new ODSystemError("Unable to read database "+this.path+"! getData() read error. (see error above)") - } - }else{ - fs.writeFileSync(this.path,"[]") - return [] - } - }, - /**Write parsed data to the json file */ - setData: (data:ODJsonDatabaseStructure) => { - fs.writeFileSync(this.path,JSON.stringify(data,null,"\t")) - } - } -} - - -/**## ODFormattedJsonDatabase `class` - * This is an Open Ticket Formatted JSON database. - * It stores data in a `json` file as a large `Array` using the `category`, `key`, `value` strategy. - * You can store the following types: `string`, `number`, `boolean`, `array`, `object` & `null`! - * - * This one is exactly the same as `ODJsonDatabase`, but it has a formatter from the `formatted-json-stringify` package. - * This can help you organise it a little bit better! - */ -export class ODFormattedJsonDatabase extends ODDatabase { - /**The formatter to use on the database array */ - formatter: fjs.ArrayFormatter - - constructor(id:ODValidId, file:string, formatter:fjs.ArrayFormatter, customPath?:string){ - super(id) - this.file = (file.endsWith(".json")) ? file : file+".json" - this.path = customPath ? nodepath.join("./",customPath,this.file) : nodepath.join("./database/",this.file) - this.formatter = formatter - } - - /**Init the database. */ - init(): ODPromiseVoid { - this.#system.getData() - } - /**Set/overwrite the value of `category` & `key`. Returns `true` when overwritten! - * @example - * const didOverwrite = database.setData("category","key","value") //value can be any of the valid types - * //You need an ODFormattedJsonDatabase class named "database" for this example to work! - */ - set(category:string, key:string, value:ODValidJsonType): ODOptionalPromise { - const currentList = this.#system.getData() - const currentData = currentList.find((d) => (d.category === category) && (d.key === key)) - - //overwrite when already present - if (currentData){ - currentList[currentList.indexOf(currentData)].value = value - }else{ - currentList.push({category,key,value}) - } - - this.#system.setData(currentList) - return currentData ? true : false - } - /**Get the value of `category` & `key`. Returns `undefined` when non-existent! - * @example - * const data = database.getData("category","key") //data will be the value - * //You need an ODFormattedJsonDatabase class named "database" for this example to work! - */ - get(category:string, key:string): ODOptionalPromise { - const currentList = this.#system.getData() - const tempresult = currentList.find((d) => (d.category === category) && (d.key === key)) - return tempresult ? tempresult.value : undefined - } - /**Remove the value of `category` & `key`. Returns `undefined` when non-existent! - * @example - * const didExist = database.deleteData("category","key") //delete this value - * //You need an ODFormattedJsonDatabase class named "database" for this example to work! - */ - delete(category:string, key:string): ODOptionalPromise { - const currentList = this.#system.getData() - const currentData = currentList.find((d) => (d.category === category) && (d.key === key)) - if (currentData) currentList.splice(currentList.indexOf(currentData),1) - - this.#system.setData(currentList) - return currentData ? true : false - } - /**Check if a value of `category` & `key` exists. Returns `false` when non-existent! */ - exists(category:string, key:string): ODOptionalPromise { - const currentList = this.#system.getData() - const tempresult = currentList.find((d) => (d.category === category) && (d.key === key)) - return tempresult ? true : false - } - /**Get all values in `category`. Returns `undefined` when non-existent! */ - getCategory(category:string): ODOptionalPromise<{key:string, value:ODValidJsonType}[]|undefined> { - const currentList = this.#system.getData() - const tempresult = currentList.filter((d) => (d.category === category)) - return tempresult ? tempresult.map((data) => {return {key:data.key,value:data.value}}) : undefined - } - /**Get all values in `category`. */ - getAll(): ODOptionalPromise { - return this.#system.getData() - } - - #system = { - /**Read parsed data from the json file */ - getData: (): ODJsonDatabaseStructure => { - if (fs.existsSync(this.path)){ - return JSON.parse(fs.readFileSync(this.path).toString()) - }else{ - fs.writeFileSync(this.path,"[]") - return [] - } - }, - /**Write parsed data to the json file */ - setData: (data:ODJsonDatabaseStructure) => { - fs.writeFileSync(this.path,this.formatter.stringify(data)) - } - } -} \ No newline at end of file diff --git a/src/core/api/modules/defaults.ts b/src/core/api/modules/defaults.ts deleted file mode 100644 index c0b4491..0000000 --- a/src/core/api/modules/defaults.ts +++ /dev/null @@ -1,366 +0,0 @@ -/////////////////////////////////////// -//DEFAULTS MODULE -/////////////////////////////////////// - -/**## ODDefaults `interface` - * This type is a list of all defaults available in the `ODDefaultsManager` class. - * It's used to generate typescript declarations for this class. - */ -export interface ODDefaults { - /**Enable the default error handling system. */ - errorHandling:boolean, - /**Crash when there is an unknown bot error. */ - crashOnError:boolean, - /**Enable the system responsible for the `--debug` flag. */ - debugLoading:boolean, - /**Enable the system responsible for the `--silent` flag. */ - silentLoading:boolean, - /**When enabled, you're able to use the "!OPENTICKET:dump" command to send the OT debug file. This is only possible when you're the owner of the bot. */ - allowDumpCommand:boolean, - /**Enable loading all Open Ticket plugins, sadly enough is only useful for the system :) */ - pluginLoading:boolean, - /**Don't crash the bot when a plugin crashes! */ - softPluginLoading:boolean, - - /**Load the default Open Ticket plugin classes. */ - pluginClassLoading:boolean, - - /**Load the default Open Ticket flags. */ - flagLoading:boolean, - /**Enable the default initializer for Open Ticket flags. */ - flagInitiating:boolean, - /**Load the default Open Ticket progress bar renderers. */ - progressBarRendererLoading:boolean, - /**Load the default Open Ticket progress bars. */ - progressBarLoading:boolean, - /**Load the default Open Ticket configs. */ - configLoading:boolean, - /**Enable the default initializer for Open Ticket config. */ - configInitiating:boolean, - /**Load the default Open Ticket databases. */ - databaseLoading:boolean, - /**Enable the default initializer for Open Ticket database. */ - databaseInitiating:boolean, - /**Load the default Open Ticket sessions. */ - sessionLoading:boolean, - - /**Load the default Open Ticket languages. */ - languageLoading:boolean, - /**Enable the default initializer for Open Ticket languages. */ - languageInitiating:boolean, - /**Enable selecting the current language from `config/general.json`. */ - languageSelection:boolean, - /**Set the backup language when the primary language is missing a property. */ - backupLanguage:string, - /****[NOT FOR PLUGIN TRANSLATIONS]** The full list of available languages (used in the default config checker). */ - languageList:string[], - - /**Load the default Open Ticket config checker. */ - checkerLoading:boolean, - /**Load the default Open Ticket config checker functions. */ - checkerFunctionLoading:boolean, - /**Enable the default execution of the config checkers. */ - checkerExecution:boolean, - /**Load the default Open Ticket config checker translations. */ - checkerTranslationLoading:boolean, - /**Enable the default rendering of the config checkers. */ - checkerRendering:boolean, - /**Enable the default quit action when there is an error in the config checker. */ - checkerQuit:boolean, - /**Render the checker even when there are no errors & warnings. */ - checkerRenderEmpty:boolean, - - /**Load the default Open Ticket client configuration. */ - clientLoading:boolean, - /**Load the default Open Ticket client initialization. */ - clientInitiating:boolean, - /**Load the default Open Ticket client ready actions (status, commands, permissions, ...). */ - clientReady:boolean, - /**Create a warning when the bot is present in multiple guilds. */ - clientMultiGuildWarning:boolean, - /**Load the default Open Ticket client activity (from `config/general.json`). */ - clientActivityLoading:boolean, - /**Load the default Open Ticket client activity initialization (& status refresh). */ - clientActivityInitiating:boolean, - - /**Load the default Open Ticket priority levels. */ - priorityLoading:boolean, - - /**Load the default Open Ticket slash commands. */ - slashCommandLoading:boolean, - /**Load the default Open Ticket slash command registerer (register slash cmds in discord). */ - slashCommandRegistering:boolean, - /**When enabled, the bot is forced to re-register all slash commands in the server. This can be used in case of a auto-update malfunction. */ - forceSlashCommandRegistration:boolean, - /**When enabled, the bot is allowed to unregister all slash commands which aren't used in Open Ticket. Disable this if you don't want to use the Open Ticket `ODSlashCommand` classes. */ - allowSlashCommandRemoval:boolean, - /**Load the default Open Ticket context menus. */ - contextMenuLoading:boolean, - /**Load the default Open Ticket context menu registerer (register menus in discord). */ - contextMenuRegistering:boolean, - /**When enabled, the bot is forced to re-register all context menus in the server. This can be used in case of a auto-update malfunction. */ - forceContextMenuRegistration:boolean, - /**When enabled, the bot is allowed to unregister all context menus which aren't used in Open Ticket. Disable this if you don't want to use the Open Ticket `ODContextMenu` classes. */ - allowContextMenuRemoval:boolean, - /**Load the default Open Ticket text commands. */ - textCommandLoading:boolean, - - /**Load the default Open Ticket questions (from `config/questions.json`) */ - questionLoading:boolean, - /**Load the default Open Ticket options (from `config/options.json`) */ - optionLoading:boolean, - /**Load the default Open Ticket panels (from `config/panels.json`) */ - panelLoading:boolean, - /**Load the default Open Ticket tickets (from `database/tickets.json`) */ - ticketLoading:boolean, - /**Load the default Open Ticket reaction roles (from `config/options.json`) */ - roleLoading:boolean, - /**Load the default Open Ticket blacklist (from `database/users.json`) */ - blacklistLoading:boolean, - /**Load the default Open Ticket transcript compilers. */ - transcriptCompilerLoading:boolean, - /**Load the default Open Ticket transcript history (from `database/transcripts.json`) */ - transcriptHistoryLoading:boolean, - - /**Load the default Open Ticket button builders. */ - buttonBuildersLoading:boolean, - /**Load the default Open Ticket dropdown builders. */ - dropdownBuildersLoading:boolean, - /**Load the default Open Ticket file builders. */ - fileBuildersLoading:boolean, - /**Load the default Open Ticket embed builders. */ - embedBuildersLoading:boolean, - /**Load the default Open Ticket message builders. */ - messageBuildersLoading:boolean, - /**Load the default Open Ticket modal builders. */ - modalBuildersLoading:boolean, - - /**Load the default Open Ticket command responders. */ - commandRespondersLoading:boolean, - /**Load the default Open Ticket button responders. */ - buttonRespondersLoading:boolean, - /**Load the default Open Ticket dropdown responders. */ - dropdownRespondersLoading:boolean, - /**Load the default Open Ticket modal responders. */ - modalRespondersLoading:boolean, - /**Load the default Open Ticket context menu responders. */ - contextMenuRespondersLoading:boolean, - /**Load the default Open Ticket autocomplete responders. */ - autocompleteRespondersLoading:boolean, - /**Set the time (in ms) before Open Ticket sends an error message when no reply is sent in a responder. */ - responderTimeoutMs:number, - - /**Load the default Open Ticket actions. */ - actionsLoading:boolean, - - /**Load the default Open Ticket verify bars. */ - verifyBarsLoading:boolean, - /**Load the default Open Ticket permissions. */ - permissionsLoading:boolean, - /**Load the default Open Ticket posts. */ - postsLoading:boolean, - /**Initiate the default Open Ticket posts. */ - postsInitiating:boolean, - /**Load the default Open Ticket cooldowns. */ - cooldownsLoading:boolean, - /**Initiate the default Open Ticket cooldowns. */ - cooldownsInitiating:boolean, - /**Load the default Open Ticket help menu categories. */ - helpMenuCategoryLoading:boolean, - /**Load the default Open Ticket help menu components. */ - helpMenuComponentLoading:boolean, - - /**Load the default Open Ticket stat scopes. */ - statScopesLoading:boolean, - /**Load the default Open Ticket stats. */ - statLoading:boolean, - /**Initiate the default Open Ticket stats. */ - statInitiating:boolean, - - /**Load the default Open Ticket code/functions. */ - codeLoading:boolean, - /**Execute the default Open Ticket code/functions. */ - codeExecution:boolean, - - /**Load the default Open Ticket livestatus. */ - liveStatusLoading:boolean, - /**Load the default Open Ticket startscreen. */ - startScreenLoading:boolean, - /**Render the default Open Ticket startscreen. */ - startScreenRendering:boolean, - - /**Load the emoji style from the Open Ticket general config. */ - emojiTitleStyleLoading:boolean, - /**The emoji style to use in embed & message titles using `utilities.emoijTitle()` */ - emojiTitleStyle:"disabled"|"before"|"after"|"double", - /**The emoji divider to use in embed & message titles using `utilities.emoijTitle()` */ - emojiTitleDivider:string - /**The interval in milliseconds that are between autoclose timeout checkers. */ - autocloseCheckInterval:number - /**The interval in milliseconds that are between autodelete timeout checkers. */ - autodeleteCheckInterval:number -} - -/**## ODDefaultsBooleans `type` - * This type is a list of boolean defaults available in the `ODDefaultsManager` class. - * It's used to generate typescript declarations for this class. - */ -export type ODDefaultsBooleans = { - [Key in keyof ODDefaults]: ODDefaults[Key] extends boolean ? Key : never -}[keyof ODDefaults] - -/**## ODDefaultsStrings `type` - * This type is a list of string defaults available in the `ODDefaultsManager` class. - * It's used to generate typescript declarations for this class. - */ -export type ODDefaultsStrings = { - [Key in keyof ODDefaults]: ODDefaults[Key] extends string ? Key : never -}[keyof ODDefaults] - -/**## ODDefaultsNumbers `type` - * This type is a list of number defaults available in the `ODDefaultsManager` class. - * It's used to generate typescript declarations for this class. - */ -export type ODDefaultsNumbers = { - [Key in keyof ODDefaults]: ODDefaults[Key] extends number ? Key : never -}[keyof ODDefaults] - -/**## ODDefaultsStringArray `type` - * This type is a list of string[] defaults available in the `ODDefaultsManager` class. - * It's used to generate typescript declarations for this class. - */ -export type ODDefaultsStringArray = { - [Key in keyof ODDefaults]: ODDefaults[Key] extends string[] ? Key : never -}[keyof ODDefaults] - -/**## ODDefaultsManager `class` - * This is an Open Ticket defaults manager. - * - * It manages all settings in Open Ticket that are not meant to be in the config. - * Here you can disable certain default features to replace them or to specifically enable them! - * - * You are unable to add your own defaults, you can only edit Open Ticket defaults! - */ -export class ODDefaultsManager { - /**A list of all the defaults */ - #defaults: ODDefaults - - constructor(){ - this.#defaults = { - errorHandling:true, - crashOnError:false, - debugLoading:true, - silentLoading:true, - allowDumpCommand:true, - pluginLoading:true, - softPluginLoading:false, - - pluginClassLoading:true, - - flagLoading:true, - flagInitiating:true, - progressBarRendererLoading:true, - progressBarLoading:true, - configLoading:true, - configInitiating:true, - databaseLoading:true, - databaseInitiating:true, - sessionLoading:true, - - languageLoading:true, - languageInitiating:true, - languageSelection:true, - backupLanguage:"opendiscord:english", - languageList:[], - - checkerLoading:true, - checkerFunctionLoading:true, - checkerExecution:true, - checkerTranslationLoading:true, - checkerRendering:true, - checkerQuit:true, - checkerRenderEmpty:false, - - clientLoading:true, - clientInitiating:true, - clientReady:true, - clientMultiGuildWarning:true, - clientActivityLoading:true, - clientActivityInitiating:true, - - priorityLoading:true, - - slashCommandLoading:true, - slashCommandRegistering:true, - forceSlashCommandRegistration:false, - allowSlashCommandRemoval:true, - contextMenuLoading:true, - contextMenuRegistering:true, - forceContextMenuRegistration:false, - allowContextMenuRemoval:true, - textCommandLoading:true, - - questionLoading:true, - optionLoading:true, - panelLoading:true, - ticketLoading:true, - roleLoading:true, - blacklistLoading:true, - transcriptCompilerLoading:true, - transcriptHistoryLoading:true, - - buttonBuildersLoading:true, - dropdownBuildersLoading:true, - fileBuildersLoading:true, - embedBuildersLoading:true, - messageBuildersLoading:true, - modalBuildersLoading:true, - - commandRespondersLoading:true, - buttonRespondersLoading:true, - dropdownRespondersLoading:true, - modalRespondersLoading:true, - contextMenuRespondersLoading:true, - autocompleteRespondersLoading:true, - responderTimeoutMs:2500, - - actionsLoading:true, - - verifyBarsLoading:true, - permissionsLoading:true, - postsLoading:true, - postsInitiating:true, - cooldownsLoading:true, - cooldownsInitiating:true, - helpMenuCategoryLoading:true, - helpMenuComponentLoading:true, - - statScopesLoading:true, - statLoading:true, - statInitiating:true, - - codeLoading:true, - codeExecution:true, - - liveStatusLoading:true, - startScreenLoading:true, - startScreenRendering:true, - - emojiTitleStyleLoading:true, - emojiTitleStyle:"before", - emojiTitleDivider:" ", - autocloseCheckInterval:300000, //5 minutes - autodeleteCheckInterval:300000 //5 minutes - } - } - - /**Set a default to a specific value. Remember! All plugins can edit these values, so your value could be overwritten! */ - setDefault(key:DefaultName, value:ODDefaults[DefaultName]): void { - this.#defaults[key] = value - } - - /**Get a default. Remember! All plugins can edit these values, so this value could be overwritten! */ - getDefault(key:DefaultName): ODDefaults[DefaultName] { - return this.#defaults[key] - } -} \ No newline at end of file diff --git a/src/core/api/modules/event.ts b/src/core/api/modules/event.ts deleted file mode 100644 index c7a20a2..0000000 --- a/src/core/api/modules/event.ts +++ /dev/null @@ -1,99 +0,0 @@ -/////////////////////////////////////// -//EVENT MODULE -/////////////////////////////////////// -import { ODManagerData, ODManager, ODValidId } from "./base" -import { ODConsoleWarningMessage, ODDebugger } from "./console" - -/**## ODEvent `class` - * This is an Open Ticket event. - * - * This class is made to work with the `ODEventManager` to handle events. - * The function of this specific class is to manage all listeners for a specifc event! - */ -export class ODEvent extends ODManagerData { - /**Alias to Open Ticket debugger. */ - #debug?: ODDebugger - /**The list of permanent listeners. */ - listeners: Function[] = [] - /**The list of one-time listeners. List is cleared every time the event is emitted. */ - oncelisteners: Function[] = [] - /**The max listener limit before a possible memory leak will be announced */ - listenerLimit: number = 25 - - /**Use the Open Ticket debugger in this manager for logs*/ - useDebug(debug:ODDebugger|null){ - this.#debug = debug ?? undefined - } - /**Get a collection of listeners combined from both types. Also clears the one-time listeners array! */ - #getCurrentListeners(){ - const final: Function[] = [] - this.oncelisteners.forEach((l) => final.push(l)) - this.listeners.forEach((l) => final.push(l)) - - this.oncelisteners = [] - return final - } - /**Edit the listener limit */ - setListenerLimit(limit:number){ - this.listenerLimit = limit - } - /**Add a permanent callback to this event. This will stay as long as the bot is running! */ - listen(callback:Function){ - this.listeners.push(callback) - - if (this.listeners.length > this.listenerLimit){ - if (this.#debug) this.#debug.console.log(new ODConsoleWarningMessage("Possible event memory leak detected!",[ - {key:"event",value:this.id.value}, - {key:"listeners",value:this.listeners.length.toString()} - ])) - } - } - /**Add a one-time-only callback to this event. This will only trigger the callback once! */ - listenOnce(callback:Function){ - this.oncelisteners.push(callback) - } - /**Wait until this event is fired! Be carefull with it, because it could block the entire bot when wrongly used! */ - async wait(): Promise { - return new Promise((resolve,reject) => { - this.oncelisteners.push((...args:any) => {resolve(args)}) - }) - } - /**Emit this event to all listeners. You are required to provide all parameters of the event! */ - async emit(params:any[]): Promise { - for (const listener of this.#getCurrentListeners()){ - try{ - await listener(...params) - }catch(err){ - process.emit("uncaughtException",err) - } - } - } -} - -/**## ODEventManager `class` - * This is an Open Ticket event manager. - * - * This class is made to manage all events in the bot. You can compare it with the built-in node.js `EventEmitter` - * - * It's not recommended to create this class yourself. Plugin events should be registered in their `plugin.json` file instead. - * All events are available in the `opendiscord.events` global! - */ -export class ODEventManager extends ODManager { - /**Reference to the Open Ticket debugger */ - #debug: ODDebugger - - constructor(debug:ODDebugger){ - super(debug,"event") - this.#debug = debug - } - - add(data:ODEvent, overwrite?:boolean): boolean { - data.useDebug(this.#debug) - return super.add(data,overwrite) - } - remove(id:ODValidId): ODEvent|null { - const data = super.remove(id) - if (data) data.useDebug(null) - return data - } -} \ No newline at end of file diff --git a/src/core/api/modules/flag.ts b/src/core/api/modules/flag.ts deleted file mode 100644 index 3794f3a..0000000 --- a/src/core/api/modules/flag.ts +++ /dev/null @@ -1,73 +0,0 @@ -/////////////////////////////////////// -//FLAG MODULE -/////////////////////////////////////// -import { ODId, ODValidId, ODManager, ODManagerData } from "./base" -import { ODDebugger } from "./console" - -/**## ODFlag `class` - * This is an Open Ticket flag. - * - * A flag is a boolean that can be specified by a parameter in the console. - * It's useful for small settings that are only required once in a while. - * - * Flags can also be enabled manually by plugins! - */ -export class ODFlag extends ODManagerData { - /**The method that has been used to set the value of this flag. (`null` when not set) */ - method: "param"|"manual"|null = null - /**The name of this flag. Visible to the user. */ - name: string - /**The description of this flag. Visible to the user. */ - description: string - /**The name of the parameter in the console. (e.g. `--test`) */ - param: string - /**A list of aliases for the parameter in the console. */ - aliases: string[] - /**The value of this flag. */ - value: boolean = false - - constructor(id:ODValidId, name:string, description:string, param:string, aliases?:string[], initialValue?:boolean){ - super(id) - this.name = name - this.description = description - this.param = param - this.aliases = aliases ?? [] - this.value = initialValue ?? false - } - - /**Set the value of this flag. */ - setValue(value:boolean,method?:"param"|"manual"){ - this.value = value - this.method = method ?? "manual" - } - /**Detect if the process contains the param or aliases & set the value. Use `force` to overwrite a manually set value. */ - detectProcessParams(force?:boolean){ - if (force){ - const params = [this.param,...this.aliases] - this.setValue(params.some((p) => process.argv.includes(p)),"param") - - }else if (this.method != "manual"){ - const params = [this.param,...this.aliases] - this.setValue(params.some((p) => process.argv.includes(p)),"param") - } - } -} - -/**## ODFlagManager `class` - * This is an Open Ticket flag manager. - * - * This class is responsible for managing & initiating all flags of the bot. - * It also contains a shortcut for initiating all flags. - */ -export class ODFlagManager extends ODManager { - constructor(debug:ODDebugger){ - super(debug,"flag") - } - - /**Set all flags to their `process.argv` value. */ - async init(){ - await this.loopAll((flag) => { - flag.detectProcessParams(false) - }) - } -} \ No newline at end of file diff --git a/src/core/api/modules/helpmenu.ts b/src/core/api/modules/helpmenu.ts deleted file mode 100644 index 44deec2..0000000 --- a/src/core/api/modules/helpmenu.ts +++ /dev/null @@ -1,216 +0,0 @@ -/////////////////////////////////////// -//HELP MODULE -/////////////////////////////////////// -import { ODId, ODManager, ODManagerData, ODValidId } from "./base" -import { ODDebugger } from "./console" - -/**## ODHelpMenuComponentRenderer `type` - * This is the callback of the help menu component renderer. It also contains information about how & where it is rendered. - */ -export type ODHelpMenuComponentRenderer = (page:number, category:number, location:number, mode:"slash"|"text") => string|Promise - -/**## ODHelpMenuComponent `class` - * This is an Open Ticket help menu component. - * - * It can render something on the Open Ticket help menu. - */ -export class ODHelpMenuComponent extends ODManagerData { - /**The priority of this component. The higher, the earlier it will appear in the help menu. */ - priority: number - /**The render function for this component. */ - render: ODHelpMenuComponentRenderer - - constructor(id:ODValidId, priority:number, render:ODHelpMenuComponentRenderer){ - super(id) - this.priority = priority - this.render = render - } -} - -/**## ODHelpMenuTextComponent `class` - * This is an Open Ticket help menu text component. - * - * It can render a static piece of text on the Open Ticket help menu. - */ -export class ODHelpMenuTextComponent extends ODHelpMenuComponent { - constructor(id:ODValidId, priority:number, text:string){ - super(id,priority,() => { - return text - }) - } -} - -/**## ODHelpMenuCommandComponentOption `interface` - * This interface contains a command option for the `ODHelpMenuCommandComponent`. - */ -export interface ODHelpMenuCommandComponentOption { - /**The name of this option. */ - name:string, - /**Is this option optional? */ - optional:boolean -} - -/**## ODHelpMenuCommandComponentSettings `interface` - * This interface contains the settings for the `ODHelpMenuCommandComponent`. - */ -export interface ODHelpMenuCommandComponentSettings { - /**The name of this text command. */ - textName?:string, - /**The name of this slash command. */ - slashName?:string, - /**Options available in the text command. */ - textOptions?:ODHelpMenuCommandComponentOption[], - /**Options available in the slash command. */ - slashOptions?:ODHelpMenuCommandComponentOption[], - /**The description for the text command. */ - textDescription?:string, - /**The description for the slash command. */ - slashDescription?:string -} - -/**## ODHelpMenuCommandComponent `class` - * This is an Open Ticket help menu command component. - * - * It contains a useful helper to render a command in the Open Ticket help menu. - */ -export class ODHelpMenuCommandComponent extends ODHelpMenuComponent { - constructor(id:ODValidId, priority:number, settings:ODHelpMenuCommandComponentSettings){ - super(id,priority,(page,category,location,mode) => { - if (mode == "slash" && settings.slashName){ - return `\`${settings.slashName}${(settings.slashOptions) ? this.#renderOptions(settings.slashOptions) : ""}\` ➜ ${settings.slashDescription ?? ""}` - - }else if (mode == "text" && settings.textName){ - return `\`${settings.textName}${(settings.textOptions) ? this.#renderOptions(settings.textOptions) : ""}\` ➜ ${settings.textDescription ?? ""}` - - }else return "" - }) - } - - /**Utility function to render all command options. */ - #renderOptions(options:ODHelpMenuCommandComponentOption[]){ - return " "+options.map((opt) => (opt.optional) ? `[${opt.name}]` : `<${opt.name}>`).join(" ") - } -} - -/**## ODHelpMenuCategory `class` - * This is an Open Ticket help menu category. - * - * Every category in the help menu is an embed field by default. - * Try to limit the amount of components per category. - */ -export class ODHelpMenuCategory extends ODManager { - /**The id of this category. */ - id: ODId - /**The priority of this category. The higher, the earlier it will appear in the menu. */ - priority: number - /**The name of this category. (can include emoji's) */ - name: string - /**When enabled, it automatically starts this category on a new page. */ - newPage: boolean - - constructor(id:ODValidId, priority:number, name:string, newPage?:boolean){ - super() - this.id = new ODId(id) - this.priority = priority - this.name = name - this.newPage = newPage ?? false - } - - /**Render this category and it's components. */ - async render(page:number, category:number, mode:"slash"|"text"){ - //sort from high priority to low - const derefArray = [...this.getAll()] - derefArray.sort((a,b) => { - return b.priority-a.priority - }) - const result: string[] = [] - - let i = 0 - for (const component of derefArray){ - try { - result.push(await component.render(page,category,i,mode)) - }catch(err){ - process.emit("uncaughtException",err) - } - i++ - } - - //only return the non-empty components - return result.filter((component) => component !== "").join("\n\n") - } -} - -/**## ODHelpMenuRenderResult `type` - * This is the array returned when the help menu has been rendered successfully. - * - * It contains a list of pages, which contain categories by name & value (content). - */ -export type ODHelpMenuRenderResult = {name:string, value:string}[][] - -/**## ODHelpMenuManager `class` - * This is an Open Ticket help menu manager. - * - * It is responsible for rendering the entire help menu content. - * You are also able to configure the amount of categories per page here. - * - * Fewer Categories == More Clean Menu - */ -export class ODHelpMenuManager extends ODManager { - /**Alias to Open Ticket debugger. */ - #debug: ODDebugger - /**The amount of categories per-page. */ - categoriesPerPage: number = 3 - - constructor(debug:ODDebugger){ - super(debug,"help menu category") - this.#debug = debug - } - - add(data:ODHelpMenuCategory, overwrite?:boolean): boolean { - data.useDebug(this.#debug,"help menu component") - return super.add(data,overwrite) - } - - /**Render this entire help menu & return a `ODHelpMenuRenderResult`. */ - async render(mode:"slash"|"text"): Promise { - //sort from high priority to low - const derefArray = [...this.getAll()] - derefArray.sort((a,b) => { - return b.priority-a.priority - }) - const result: {name:string, value:string}[][] = [] - let currentPage: {name:string, value:string}[] = [] - - for (const category of derefArray){ - try { - const renderedCategory = await category.render(result.length,currentPage.length,mode) - - if (renderedCategory !== ""){ - //create new page when category wants to - if (currentPage.length > 0 && category.newPage){ - result.push(currentPage) - currentPage = [] - } - - currentPage.push({ - name:category.name, - value:renderedCategory - }) - - //create new page when page is full - if (currentPage.length >= this.categoriesPerPage){ - result.push(currentPage) - currentPage = [] - } - } - }catch(err){ - process.emit("uncaughtException",err) - } - } - - //push current page when not-empty - if (currentPage.length > 0) result.push(currentPage) - - return result - } -} \ No newline at end of file diff --git a/src/core/api/modules/language.ts b/src/core/api/modules/language.ts deleted file mode 100644 index 5333945..0000000 --- a/src/core/api/modules/language.ts +++ /dev/null @@ -1,201 +0,0 @@ -/////////////////////////////////////// -//LANGUAGE MODULE -/////////////////////////////////////// -import { ODId, ODManager, ODManagerData, ODPromiseVoid, ODSystemError, ODValidId } from "./base" -import nodepath from "path" -import { ODDebugger } from "./console" -import fs from "fs" - -/**## ODLanguageMetadata `interface` - * This interface contains all metadata available in the language files. - */ -export interface ODLanguageMetadata { - /**The version of Open Ticket this translation is made for. */ - otversion:string, - /**The name of the language in english (with capital letter). */ - language:string, - /**A list of translators (discord/github username) who've contributed to this language. */ - translators:string[], - /**The last date that this translation has been modified (format: DD/MM/YYYY) */ - lastedited:string, - /**When `true`, the translator made use of some sort of automation while creating the translation. (e.g. ChatGPT, Google Translate, DeepL, ...) */ - automated:boolean -} - -/**## ODLanguageManager `class` - * This is an Open Ticket language manager. - * - * It manages all languages in the bot and manages translation for you! - * Get a translation via the `getTranslation()` or `getTranslationWithParams()` methods. - * - * Add new languages using the `ODlanguage` class in your plugin! - */ -export class ODLanguageManager extends ODManager { - /**The currently selected language. */ - current: ODLanguage|null = null - /**The currently selected backup language. (used when translation missing in current language) */ - backup: ODLanguage|null = null - /**An alias to Open Ticket debugger. */ - #debug: ODDebugger - - constructor(debug:ODDebugger, presets:boolean){ - super(debug,"language") - if (presets) this.add(new ODLanguage("english","english.json")) - this.current = presets ? new ODLanguage("english","english.json") : null - this.backup = presets ? new ODLanguage("english","english.json") : null - this.#debug = debug - } - - /**Set the current language by providing the ID of a language which is registered in this manager. */ - setCurrentLanguage(id:ODValidId){ - this.current = this.get(id) - const languageId = this.current?.id.value ?? "" - const languageAutomated = this.current?.metadata?.automated.toString() ?? "" - this.#debug.debug("Selected current language",[ - {key:"id",value:languageId}, - {key:"automated",value:languageAutomated}, - ]) - } - /**Get the current language (same as `this.current`) */ - getCurrentLanguage(){ - return (this.current) ? this.current : null - } - /**Set the backup language by providing the ID of a language which is registered in this manager. */ - setBackupLanguage(id:ODValidId){ - this.backup = this.get(id) - const languageId = this.backup?.id.value ?? "" - const languageAutomated = this.backup?.metadata?.automated.toString() ?? "" - this.#debug.debug("Selected backup language",[ - {key:"id",value:languageId}, - {key:"automated",value:languageAutomated}, - ]) - } - /**Get the backup language (same as `this.backup`) */ - getBackupLanguage(){ - return (this.backup) ? this.backup : null - } - /**Get the metadata of the current/backup language. */ - getLanguageMetadata(frombackup?:boolean): ODLanguageMetadata|null { - if (frombackup) return (this.backup) ? this.backup.metadata : null - return (this.current) ? this.current.metadata : null - } - /**Get the ID (string) of the current language. (Not backup language) */ - getCurrentLanguageId(){ - return (this.current) ? this.current.id.value : "" - } - /**Get a translation string by JSON location. (e.g. `"checker.system.typeError"`) */ - getTranslation(id:string): string|null { - if (!this.current) return this.#getBackupTranslation(id) - - const splitted = id.split(".") - let currentObject = this.current.data - let result: string|false = false - splitted.forEach((id) => { - if (typeof currentObject[id] == "object"){ - currentObject = currentObject[id] - }else if (typeof currentObject[id] == "string"){ - result = currentObject[id] - } - }) - - if (typeof result == "string") return result - else return this.#getBackupTranslation(id) - } - /**Get a backup translation string by JSON location. (system only) */ - #getBackupTranslation(id:string): string|null { - if (!this.backup) return null - - const splitted = id.split(".") - let currentObject = this.backup.data - let result: string|false = false - splitted.forEach((id) => { - if (typeof currentObject[id] == "object"){ - currentObject = currentObject[id] - }else if (typeof currentObject[id] == "string"){ - result = currentObject[id] - } - }) - - if (typeof result == "string") return result - else return null - } - /**Get a backup translation string by JSON location and replace `{0}`,`{1}`,`{2}`,... with the provided parameters. */ - getTranslationWithParams(id:string, params:string[]): string|null { - let translation = this.getTranslation(id) - if (!translation) return translation - - params.forEach((value,index) => { - if (!translation) return - translation = translation.replace(`{${index}}`,value) - }) - return translation - } - - /**Init all language files. */ - async init(){ - for (const language of this.getAll()){ - try{ - await language.init() - }catch(err){ - process.emit("uncaughtException",new ODSystemError(err)) - } - } - } -} - -/**## ODLanguage `class` - * This is an Open Ticket language file. - * - * It contains metadata and all translation strings available in this language. - * Register this class to an `ODLanguageManager` to use it! - * - * JSON languages should be created using the `ODJsonLanguage` class instead! - */ -export class ODLanguage extends ODManagerData { - /**The name of the file with extension. */ - file: string = "" - /**The path to the file relative to the main directory. */ - path: string = "" - /**The raw object data of the translation. */ - data: any - /**The metadata of the language if available. */ - metadata: ODLanguageMetadata|null = null - - constructor(id:ODValidId, data:any){ - super(id) - this.data = data - } - - /**Init the language. */ - init(): ODPromiseVoid { - //nothing - } -} - -/**## ODJsonLanguage `class` - * This is an Open Ticket JSON language file. - * - * It contains metadata and all translation strings from a certain JSON file (in `./languages/`). - * Register this class to an `ODLanguageManager` to use it! - * - * Use the `ODLanguage` class to use translations from non-JSON files! - */ -export class ODJsonLanguage extends ODLanguage { - constructor(id:ODValidId, file:string, customPath?:string){ - super(id,{}) - this.file = (file.endsWith(".json")) ? file : file+".json" - this.path = customPath ? nodepath.join("./",customPath,this.file) : nodepath.join("./languages/",this.file) - } - - /**Init the langauge. */ - init(): ODPromiseVoid { - if (!fs.existsSync(this.path)) throw new ODSystemError("Unable to parse language \""+nodepath.join("./",this.path)+"\", the file doesn't exist!") - try{ - this.data = JSON.parse(fs.readFileSync(this.path).toString()) - }catch(err){ - process.emit("uncaughtException",err) - throw new ODSystemError("Unable to parse language \""+nodepath.join("./",this.path)+"\"!") - } - if (this.data["_TRANSLATION"]) this.metadata = this.data["_TRANSLATION"] - } -} \ No newline at end of file diff --git a/src/core/api/modules/permission.ts b/src/core/api/modules/permission.ts deleted file mode 100644 index 4b4f883..0000000 --- a/src/core/api/modules/permission.ts +++ /dev/null @@ -1,340 +0,0 @@ -/////////////////////////////////////// -//PERMISSION MODULE -/////////////////////////////////////// -import { ODId, ODValidId, ODManager, ODSystemError, ODManagerData } from "./base" -import * as discord from "discord.js" -import { ODDebugger } from "./console" -import { ODClientManager } from "./client" - -/**## ODPermissionType `type` - * All available permission types/levels. Can be used in the `ODPermission` class. - */ -export type ODPermissionType = "member"|"support"|"moderator"|"admin"|"owner"|"developer" - -/**## ODPermissionScope `type` - * The scope in which a certain permission is active. - */ -export type ODPermissionScope = "global-user"|"channel-user"|"global-role"|"channel-role" - -/**## ODPermissionResult `interface` - * The result returned by `ODPermissionManager.getPermissions()`. - */ -export interface ODPermissionResult { - /**The permission type. */ - type:ODPermissionType - /**The permission scope. */ - scope:ODPermissionScope|"default" - /**The highest level available for this scope. */ - level:ODPermissionLevel, - /**The permission which returned this level. */ - source:ODPermission|null -} - -/**## ODPermissionLevel `enum` - * All available permission types/levels. But as `enum` instead of `type`. Used to calculate the level. - */ -export enum ODPermissionLevel { - /**A normal member. (Default for everyone) */ - member, - /**Support team. Higher than a normal member. (Used for ticket-admins) */ - support, - /**Moderator. Higher than the support team. (Unused) */ - moderator, - /**Admin. Higher than a moderator. (Used for global-admins) */ - admin, - /**Server owner. (Able to use all commands including `/stats reset`) */ - owner, - /**Bot owner or all users from dev team. (Able to use all commands including `/stats reset`) */ - developer -} - -/**## ODPermission `class` - * This is an Open Ticket permission. - * - * It defines a single permission level for a specific scope (global/channel & user/role) - * These permissions only apply to commands & interactions. - * They are not related to channel permissions in the ticket system. - * - * Register this class to an `ODPermissionManager` to use it! - */ -export class ODPermission extends ODManagerData { - /**The scope of this permission. */ - readonly scope: ODPermissionScope - /**The type/level of this permission. */ - readonly permission: ODPermissionType - /**The user/role of this permission. */ - readonly value: discord.Role|discord.User - /**The channel that this permission applies to. (`null` when global) */ - readonly channel: discord.Channel|null - - constructor(id:ODValidId, scope:"global-user", permission:ODPermissionType, value:discord.User) - constructor(id:ODValidId, scope:"global-role", permission:ODPermissionType, value:discord.Role) - constructor(id:ODValidId, scope:"channel-user", permission:ODPermissionType, value:discord.User, channel:discord.Channel) - constructor(id:ODValidId, scope:"channel-role", permission:ODPermissionType, value:discord.Role, channel:discord.Channel) - constructor(id:ODValidId, scope:ODPermissionScope, permission:ODPermissionType, value:discord.Role|discord.User, channel?:discord.Channel){ - super(id) - this.scope = scope - this.permission = permission - this.value = value - this.channel = channel ?? null - } -} - -/**## ODPermissionSettings `interface` - * Optional settings for the `getPermissions()` method in the `ODPermissionManager`. - */ -export interface ODPermissionSettings { - /**Include permissions from the global user scope. */ - allowGlobalUserScope?:boolean, - /**Include permissions from the global role scope. */ - allowGlobalRoleScope?:boolean, - /**Include permissions from the channel user scope. */ - allowChannelUserScope?:boolean, - /**Include permissions from the channel role scope. */ - allowChannelRoleScope?:boolean, - /**Only include permissions of which the id matches this regex. */ - idRegex?:RegExp -} - -/**## ODPermissionCalculationCallback `type` - * The callback of the permission calculation. (Used in `ODPermissionManager`) - */ -export type ODPermissionCalculationCallback = (user:discord.User, channel?:discord.Channel|null, guild?:discord.Guild|null, settings?:ODPermissionSettings|null) => Promise - -/**## ODPermissionCommandResult `type` - * The result of calculating permissions for a command. - */ -export type ODPermissionCommandResult = { - /**Returns `true` when the user has valid permissions. */ - hasPerms:false, - reason:"no-perms"|"disabled"|"not-in-server" -}|{ - /**Returns `true` when the user has valid permissions. */ - hasPerms:true, - /**Is the user a server admin or a normal member? This does not decide if the user has permissions or not. */ - isAdmin:boolean -} - -/**## ODPermissionManager `class` - * This is an Open Ticket permission manager. - * - * It manages all permissions in the bot! - * Use the `getPermissions()` and `hasPermissions()` methods to get user perms. - * - * Add new permissions using the `ODPermission` class in your plugin! - */ -export class ODPermissionManager extends ODManager { - /**Alias for Open Ticket debugger. */ - #debug: ODDebugger - /**The function for calculating permissions in this manager. */ - #calculation: ODPermissionCalculationCallback|null - /**An alias to the Open Discord client manager. */ - #client: ODClientManager - /**The result which is returned when no other permissions match. (`member` by default) */ - defaultResult: ODPermissionResult = { - level:ODPermissionLevel["member"], - scope:"default", - type:"member", - source:null - } - - constructor(debug:ODDebugger, client:ODClientManager, useDefaultCalculation?:boolean){ - super(debug,"permission") - this.#debug = debug - this.#calculation = useDefaultCalculation ? this.#defaultCalculation : null - this.#client = client - } - - /**Edit the permission calculation function in this manager. */ - setCalculation(calculation:ODPermissionCalculationCallback){ - this.#calculation = calculation - } - /**Edit the result which is returned when no other permissions match. (`member` by default) */ - setDefaultResult(result:ODPermissionResult){ - this.defaultResult = result - } - /**Get an `ODPermissionResult` based on a few context factors. Use `hasPermissions()` to simplify the result. */ - getPermissions(user:discord.User, channel?:discord.Channel|null, guild?:discord.Guild|null, settings?:ODPermissionSettings|null): Promise { - try{ - if (!this.#calculation) throw new ODSystemError("ODPermissionManager:getPermissions() => missing perms calculation") - return this.#calculation(user,channel,guild,settings) - }catch(err){ - process.emit("uncaughtException",err) - throw new ODSystemError("ODPermissionManager:getPermissions() => failed perms calculation") - } - } - /**Simplifies the `ODPermissionResult` returned from `getPermissions()` and returns a boolean to check if the user matches the required permissions. */ - hasPermissions(minimum:ODPermissionType, data:ODPermissionResult){ - if (minimum == "member") return true - else if (minimum == "support") return (data.level >= ODPermissionLevel["support"]) - else if (minimum == "moderator") return (data.level >= ODPermissionLevel["moderator"]) - else if (minimum == "admin") return (data.level >= ODPermissionLevel["admin"]) - else if (minimum == "owner") return (data.level >= ODPermissionLevel["owner"]) - else if (minimum == "developer") return (data.level >= ODPermissionLevel["developer"]) - else throw new ODSystemError("Invalid minimum permission type at ODPermissionManager.hasPermissions()") - } - /**Check for permissions. (default calculation) */ - async #defaultCalculation(user:discord.User,channel?:discord.Channel|null,guild?:discord.Guild|null, settings?:ODPermissionSettings|null): Promise { - const globalCalc = await this.#defaultGlobalCalculation(user,channel,guild,settings) - const channelCalc = await this.#defaultChannelCalculation(user,channel,guild,settings) - - if (globalCalc.level > channelCalc.level) return globalCalc - else return channelCalc - } - /**Check for global permissions. Result will be compared with the channel perms in `#defaultCalculation()`. */ - async #defaultGlobalCalculation(user:discord.User,channel?:discord.Channel|null,guild?:discord.Guild|null, settings?:ODPermissionSettings|null): Promise { - const idRegex = (settings && typeof settings.idRegex != "undefined") ? settings.idRegex : null - const allowGlobalUserScope = (settings && typeof settings.allowGlobalUserScope != "undefined") ? settings.allowGlobalUserScope : true - const allowGlobalRoleScope = (settings && typeof settings.allowGlobalRoleScope != "undefined") ? settings.allowGlobalRoleScope : true - - //check for global user permissions - if (allowGlobalUserScope){ - const users = this.getFiltered((permission) => (!idRegex || (idRegex && idRegex.test(permission.id.value))) && permission.scope == "global-user" && (permission.value instanceof discord.User) && permission.value.id == user.id) - - if (users.length > 0){ - //sort all permisions from highest to lowest - users.sort((a,b) => { - const levelA = ODPermissionLevel[a.permission] - const levelB = ODPermissionLevel[b.permission] - - if (levelB > levelA) return 1 - else if (levelA > levelB) return -1 - else return 0 - }) - - return { - type:users[0].permission, - scope:"global-user", - level:ODPermissionLevel[users[0].permission], - source:users[0] ?? null - } - } - } - - //check for global role permissions - if (allowGlobalRoleScope){ - if (guild){ - const member = await this.#client.fetchGuildMember(guild,user.id) - if (member){ - const memberRoles = member.roles.cache.map((role) => role.id) - const roles = this.getFiltered((permission) => (!idRegex || (idRegex && idRegex.test(permission.id.value))) && permission.scope == "global-role" && (permission.value instanceof discord.Role) && memberRoles.includes(permission.value.id) && permission.value.guild.id == guild.id) - - if (roles.length > 0){ - //sort all permisions from highest to lowest - roles.sort((a,b) => { - const levelA = ODPermissionLevel[a.permission] - const levelB = ODPermissionLevel[b.permission] - - if (levelB > levelA) return 1 - else if (levelA > levelB) return -1 - else return 0 - }) - - return { - type:roles[0].permission, - scope:"global-role", - level:ODPermissionLevel[roles[0].permission], - source:roles[0] ?? null - } - } - } - } - } - - //spread result to prevent accidental referencing - return {...this.defaultResult} - } - /**Check for channel permissions. Result will be compared with the global perms in `#defaultCalculation()`. */ - async #defaultChannelCalculation(user:discord.User,channel?:discord.Channel|null,guild?:discord.Guild|null, settings?:ODPermissionSettings|null): Promise { - const idRegex = (settings && typeof settings.idRegex != "undefined") ? settings.idRegex : null - const allowChannelUserScope = (settings && typeof settings.allowChannelUserScope != "undefined") ? settings.allowChannelUserScope : true - const allowChannelRoleScope = (settings && typeof settings.allowChannelRoleScope != "undefined") ? settings.allowChannelRoleScope : true - - if (guild && channel && !channel.isDMBased()){ - //check for channel user permissions - if (allowChannelUserScope){ - const users = this.getFiltered((permission) => (!idRegex || (idRegex && idRegex.test(permission.id.value))) && permission.scope == "channel-user" && permission.channel && (permission.channel.id == channel.id) && (permission.value instanceof discord.User) && permission.value.id == user.id) - - if (users.length > 0){ - //sort all permisions from highest to lowest - users.sort((a,b) => { - const levelA = ODPermissionLevel[a.permission] - const levelB = ODPermissionLevel[b.permission] - - if (levelB > levelA) return 1 - else if (levelA > levelB) return -1 - else return 0 - }) - - return { - type:users[0].permission, - scope:"channel-user", - level:ODPermissionLevel[users[0].permission], - source:users[0] ?? null - } - } - } - - //check for channel role permissions - if (allowChannelRoleScope){ - const member = await this.#client.fetchGuildMember(guild,user.id) - if (member){ - const memberRoles = member.roles.cache.map((role) => role.id) - const roles = this.getFiltered((permission) => (!idRegex || (idRegex && idRegex.test(permission.id.value))) && permission.scope == "channel-role" && permission.channel && (permission.channel.id == channel.id) && (permission.value instanceof discord.Role) && memberRoles.includes(permission.value.id) && permission.value.guild.id == guild.id) - - if (roles.length > 0){ - //sort all permisions from highest to lowest - roles.sort((a,b) => { - const levelA = ODPermissionLevel[a.permission] - const levelB = ODPermissionLevel[b.permission] - - if (levelB > levelA) return 1 - else if (levelA > levelB) return -1 - else return 0 - }) - - return { - type:roles[0].permission, - scope:"channel-role", - level:ODPermissionLevel[roles[0].permission], - source:roles[0] ?? null - } - } - } - } - } - - //spread result to prevent accidental modification because of referencing - return {...this.defaultResult} - } - - /**Check the permissions for a certain command of the bot. */ - async checkCommandPerms(permissionMode:string,requiredLevel:ODPermissionType,user:discord.User,member?:discord.GuildMember|null,channel?:discord.Channel|null,guild?:discord.Guild|null,settings?:ODPermissionSettings): Promise { - if (permissionMode === "none"){ - return {hasPerms:false,reason:"disabled"} - - }else if (permissionMode === "everyone"){ - const isAdmin = this.hasPermissions(requiredLevel,await this.getPermissions(user,channel,guild,settings)) - return {hasPerms:true,isAdmin} - - }else if (permissionMode === "admin"){ - const isAdmin = this.hasPermissions(requiredLevel,await this.getPermissions(user,channel,guild,settings)) - if (!isAdmin) return {hasPerms:false,reason:"no-perms"} - else return {hasPerms:true,isAdmin} - }else{ - if (!guild || !member){ - this.#debug.debug("ODPermissionManager.checkCommandPerms(): Permission Error, Not in server! (#1)") - return {hasPerms:false,reason:"not-in-server"} - } - const role = await this.#client.fetchGuildRole(guild,permissionMode) - if (!role){ - this.#debug.debug("ODPermissionManager.checkCommandPerms(): Permission Error, Not in server! (#2)") - return {hasPerms:false,reason:"not-in-server"} - } - if (!role.members.has(member.id)) return {hasPerms:false,reason:"no-perms"} - - const isAdmin = this.hasPermissions(requiredLevel,await this.getPermissions(user,channel,guild,settings)) - return {hasPerms:true,isAdmin} - } - } -} \ No newline at end of file diff --git a/src/core/api/modules/plugin.ts b/src/core/api/modules/plugin.ts deleted file mode 100644 index 81ae500..0000000 --- a/src/core/api/modules/plugin.ts +++ /dev/null @@ -1,242 +0,0 @@ -/////////////////////////////////////// -//PLUGIN MODULE -/////////////////////////////////////// -import { ODId, ODManager, ODManagerData, ODSystemError, ODValidId, ODVersion } from "./base" -import nodepath from "path" -import { ODConsolePluginMessage, ODConsoleWarningMessage, ODDebugger } from "./console" - -/**## ODUnknownCrashedPlugin `interface` - * Basic details for a plugin that crashed while loading the `plugin.json` file. - */ -export interface ODUnknownCrashedPlugin { - /**The name of the plugin. (path when plugin crashed before `name` was loaded) */ - name:string, - /**The description of the plugin. (when found before crashing) */ - description:string -} - -/**## ODPluginManager `class` - * This is an Open Ticket plugin manager. - * - * It manages all active plugins in the bot! - * It also contains all "plugin classes" which are managers registered by plugins. - * These are accessible via the `opendiscord.plugins.classes` global. - * - * Use `isPluginLoaded()` to check if a plugin has been loaded. - */ -export class ODPluginManager extends ODManager { - /**A manager for all custom managers registered by plugins. */ - classes: ODPluginClassManager - /**A list of basic details from all plugins that crashed while loading the `plugin.json` file. */ - unknownCrashedPlugins: ODUnknownCrashedPlugin[] = [] - - constructor(debug:ODDebugger){ - super(debug,"plugin") - this.classes = new ODPluginClassManager(debug) - } - - /**Check if a plugin has been loaded successfully and is available for usage.*/ - isPluginLoaded(id:ODValidId): boolean { - const newId = new ODId(id) - const plugin = this.get(newId) - return (plugin !== null && plugin.executed) - } -} - -/**## ODPluginData `interface` - * Parsed data from the `plugin.json` file in a plugin. - */ -export interface ODPluginData { - /**The name of this plugin (shown on startup) */ - name:string, - /**The id of this plugin. (Must be identical to directory name) */ - id:string, - /**The version of this plugin. */ - version:string, - /**The location of the start file of the plugin relative to the rootDir of the plugin */ - startFile:string, - /**A list of compatible versions. (e.g. `["OTv4.0.x", "OMv1.x.x"]`) (optional, will be required in future version) - * - `OT` --> Open Ticket support - * - `OM` --> Open Moderation support - */ - supportedVersions?:string[], - - /**Is this plugin enabled? */ - enabled:boolean, - /**The priority of this plugin. Higher priority will load before lower priority. */ - priority:number, - /**A list of events to register to the `opendiscord.events` global before loading any plugins. This way, plugins with a higher priority are able to use events from this plugin as well! */ - events:string[] - - /**Npm dependencies which are required for this plugin to work. */ - npmDependencies:string[], - /**Plugins which are required for this plugin to work. */ - requiredPlugins:string[], - /**Plugins which are incompatible with this plugin. */ - incompatiblePlugins:string[], - - /**Additional details about this plugin. */ - details:ODPluginDetails -} - -/**## ODPluginDetails `interface` - * Additional details in the `plugin.json` file from a plugin. - */ -export interface ODPluginDetails { - /**The main author of the plugin. Additional contributors can be specified in `contributors`. */ - author:string, - /**A list of plugin contributors. (optional, will be required in future version) */ - contributors?:string[], - /**A short description of this plugin. */ - shortDescription:string, - /**A large description of this plugin. */ - longDescription:string, - /**A URL to a cover image of this plugin. (currently unused) */ - imageUrl:string, - /**A URL to the website/project page of this plugin. (currently unused) */ - projectUrl:string, - /**A list of tags/categories that this plugin affects. */ - tags:string[] -} - -/**## ODPlugin `class` - * This is an Open Ticket plugin. - * - * It represents a single plugin in the `./plugins/` directory. - * All plugins are accessible via the `opendiscord.plugins` global. - * - * Don't re-execute plugins which are already enabled! It might break the bot or plugin. - */ -export class ODPlugin extends ODManagerData { - /**The name of the directory of this plugin. (same as id) */ - dir: string - /**All plugin data found in the `plugin.json` file. */ - data: ODPluginData - /**The name of this plugin. */ - name: string - /**The priority of this plugin. */ - priority: number - /**The version of this plugin. */ - version: ODVersion - /**The additional details of this plugin. */ - details: ODPluginDetails - - /**Is this plugin enabled? */ - enabled: boolean - /**Did this plugin execute successfully?. */ - executed: boolean - /**Did this plugin crash? (A reason is available in the `crashReason`) */ - crashed: boolean - /**The reason which caused this plugin to crash. */ - crashReason: null|"incompatible.plugin"|"missing.plugin"|"missing.dependency"|"incompatible.version"|"executed" = null - - constructor(dir:string, jsondata:ODPluginData){ - super(jsondata.id) - this.dir = dir - this.data = jsondata - this.name = jsondata.name - this.priority = jsondata.priority - this.version = ODVersion.fromString("plugin",jsondata.version) - this.details = jsondata.details - - this.enabled = jsondata.enabled - this.executed = false - this.crashed = false - } - - /**Get the startfile location relative to the `./plugins/` directory. (`./dist/plugins/`) when compiled) */ - getStartFile(){ - const newFile = this.data.startFile.replace(/\.ts$/,".js") - return nodepath.join(this.dir,newFile) - } - /**Execute this plugin. Returns `false` on crash. */ - async execute(debug:ODDebugger,force?:boolean): Promise { - if ((this.enabled && !this.crashed) || force){ - try{ - //import relative plugin directory path (works on windows & unix based systems) - const pluginPath = nodepath.join("../../../../plugins/",this.getStartFile()).replaceAll("\\","/") - await import(pluginPath) - debug.console.log("Plugin \""+this.id.value+"\" loaded successfully!","plugin") - this.executed = true - return true - }catch(error){ - this.crashed = true - this.crashReason = "executed" - - debug.console.log(error.message+", canceling plugin execution...","plugin",[ - {key:"path",value:"./plugins/"+this.dir} - ]) - debug.console.log("You can see more about this error in the ./otdebug.txt file!","info") - debug.console.debugfile.writeText(error.stack) - - return false - } - }else return true - } - - /**Check if a npm dependency exists. */ - #checkDependency(id:string){ - try{ - require.resolve(id) - return true - }catch{ - return false - } - } - - /**Get a list of all missing npm dependencies that are required for this plugin. */ - dependenciesInstalled(){ - const missing: string[] = [] - this.data.npmDependencies.forEach((d) => { - if (!this.#checkDependency(d)){ - missing.push(d) - } - }) - - return missing - } - /**Get a list of all missing plugins that are required for this plugin. */ - pluginsInstalled(manager:ODPluginManager){ - const missing: string[] = [] - this.data.requiredPlugins.forEach((p) => { - const plugin = manager.get(p) - if (!plugin || !plugin.enabled){ - missing.push(p) - } - }) - - return missing - } - /**Get a list of all enabled incompatible plugins that interfere with this plugin. */ - pluginsIncompatible(manager:ODPluginManager){ - const incompatible: string[] = [] - this.data.incompatiblePlugins.forEach((p) => { - const plugin = manager.get(p) - if (plugin && plugin.enabled){ - incompatible.push(p) - } - }) - - return incompatible - } - /**Get a list of all authors & contributors of this plugin. */ - getAuthors(): string[] { - return [this.details.author,...(this.details.contributors ?? [])] - } -} - -/**## ODPluginClassManager `class` - * This is an Open Ticket plugin class manager. - * - * It manages all managers registered by plugins! - * Plugins are able to register their own managers, handlers, functions, classes, ... here. - * By doing this, other plugins are also able to make use of it. - * This can be useful for plugins that want to extend other plugins. - * - * Use `isPluginLoaded()` to check if a plugin has been loaded before trying to access the manager. - */ -export class ODPluginClassManager extends ODManager { - constructor(debug:ODDebugger){ - super(debug,"plugin class") - } -} \ No newline at end of file diff --git a/src/core/api/modules/post.ts b/src/core/api/modules/post.ts deleted file mode 100644 index ef6dfca..0000000 --- a/src/core/api/modules/post.ts +++ /dev/null @@ -1,90 +0,0 @@ -/////////////////////////////////////// -//POST MODULE -/////////////////////////////////////// -import { ODId, ODManager, ODManagerData, ODValidId } from "./base" -import { ODMessageBuildResult, ODMessageBuildSentResult } from "./builder" -import { ODDebugger } from "./console" -import * as discord from "discord.js" - -/**## ODPostManager `class` - * This is an Open Ticket post manager. - * - * It manages `ODPosts`'s for you. - * - * You can use this to get the logs channel of the bot (or some other static channel/category). - */ -export class ODPostManager extends ODManager> { - /**A reference to the main server of the bot */ - #guild: discord.Guild|null = null - - constructor(debug:ODDebugger){ - super(debug,"post") - } - - add(data:ODPost, overwrite?:boolean): boolean { - if (this.#guild) data.useGuild(this.#guild) - return super.add(data,overwrite) - } - /**Initialize the post manager & all posts. */ - async init(guild:discord.Guild){ - this.#guild = guild - for (const post of this.getAll()){ - post.useGuild(guild) - await post.init() - } - } -} - -/**## ODPost `class` - * This is an Open Ticket post class. - * - * A post is just a shortcut to a static discord channel or category. - * This can be used to get a specific channel over and over again! - * - * This class also contains utilities for sending messages via the Open Ticket builders. - */ -export class ODPost extends ODManagerData { - /**A reference to the main server of the bot */ - #guild: discord.Guild|null = null - /**Is this post already initialized? */ - ready: boolean = false - /**The discord.js channel */ - channel: ChannelType|null = null - /**The discord channel id */ - channelId: string - - constructor(id:ODValidId, channelId:string){ - super(id) - this.channelId = channelId - } - - /**Use a specific guild in this class for fetching the channel*/ - useGuild(guild:discord.Guild|null){ - this.#guild = guild - } - /**Change the channel id to another channel! */ - setChannelId(id:string){ - this.channelId = id - } - /**Initialize the discord.js channel of this post. */ - async init(){ - if (this.ready) return - if (!this.#guild) return this.channel = null - try{ - this.channel = await this.#guild.channels.fetch(this.channelId) as ChannelType - }catch{ - this.channel = null - } - this.ready = true - } - /**Send a message to this channel using the Open Ticket builder system */ - async send(msg:ODMessageBuildResult): Promise> { - if (!this.channel || !this.channel.isTextBased()) return {success:false,message:null} - try{ - const sent = await this.channel.send(msg.message) - return {success:true,message:sent} - }catch{ - return {success:false,message:null} - } - } -} \ No newline at end of file diff --git a/src/core/api/modules/progressbar.ts b/src/core/api/modules/progressbar.ts deleted file mode 100644 index b9b8289..0000000 --- a/src/core/api/modules/progressbar.ts +++ /dev/null @@ -1,232 +0,0 @@ -/////////////////////////////////////// -//PROGRESS BAR MODULE -/////////////////////////////////////// -import { ODSystemError, ODManager, ODManagerData, ODValidId } from "./base" -import { ODDebugger } from "./console" -import readline from "readline" - -/**## ODProgressBarRendererManager `class` - * This is an Open Ticket progress bar renderer manager. - * - * It is responsible for managing all console progress bar renderers in Open Ticket. - * - * A renderer is a function which will try to visualize the progress bar in the console. - */ -export class ODProgressBarRendererManager extends ODManager> { - constructor(debug:ODDebugger){ - super(debug,"progress bar renderer") - } -} - -/**## ODProgressBarManager `class` - * This is an Open Ticket progress bar manager. - * - * It is responsible for managing all console progress bars in Open Ticket. An example of this is the slash command registration progress bar. - * - * There are many types of progress bars available, but you can also create your own! - */ -export class ODProgressBarManager extends ODManager { - renderers: ODProgressBarRendererManager - - constructor(debug:ODDebugger){ - super(debug,"progress bar") - this.renderers = new ODProgressBarRendererManager(debug) - } -} - -/**## ODProgressBarRenderFunc `type` - * This is the render function for an Open Ticket console progress bar. - */ -export type ODProgressBarRenderFunc = (settings:Settings,min:number,max:number,value:number,prefix:string|null,suffix:string|null) => string - -/**## ODProgressBarRenderer `class` - * This is an Open Ticket console progress bar renderer. - * - * It is used to render a progress bar in the console of the bot. - * - * There are already a lot of default options available if you just want an easy progress bar! - */ -export class ODProgressBarRenderer extends ODManagerData { - settings: Settings - #render: ODProgressBarRenderFunc - - constructor(id:ODValidId,render:ODProgressBarRenderFunc,settings:Settings){ - super(id) - this.#render = render - this.settings = settings - } - - /**Render a progress bar using this renderer. */ - render(min:number,max:number,value:number,prefix:string|null,suffix:string|null){ - try { - return this.#render(this.settings,min,max,value,prefix,suffix) - }catch(err){ - process.emit("uncaughtException",err) - return "" - } - } - - withAdditionalSettings(settings:Partial): ODProgressBarRenderer { - const newSettings: Settings = {...this.settings} - for (const key of Object.keys(settings)){ - if (typeof settings[key] != "undefined") newSettings[key] = settings[key] - } - return new ODProgressBarRenderer(this.id,this.#render,newSettings) - } -} - -/**## ODProgressBar `class` - * This is an Open Ticket console progress bar. - * - * It is used to create a simple or advanced progress bar in the console of the bot. - * These progress bars are not visible in the `otdebug.txt` file and should only be used as extra visuals. - * - * Use other classes as existing templates or create your own progress bar from scratch using this class. - */ -export class ODProgressBar extends ODManagerData { - /**The renderer of this progress bar. */ - renderer: ODProgressBarRenderer<{}> - /**Is this progress bar currently active? */ - #active: boolean = false - /**A list of listeners when the progress bar stops. */ - #stopListeners: Function[] = [] - /**The current value of the progress bar. */ - protected value: number - /**The minimum value of the progress bar. */ - min: number - /**The maximum value of the progress bar. */ - max: number - /**The initial value of the progress bar. */ - initialValue: number - /**The prefix displayed in the progress bar. */ - prefix:string|null - /**The prefix displayed in the progress bar. */ - suffix:string|null - - /**Enable automatic stopping when reaching `min` or `max`. */ - autoStop: null|"min"|"max" - - constructor(id:ODValidId,renderer:ODProgressBarRenderer<{}>,min:number,max:number,value:number,autoStop:null|"min"|"max",prefix:string|null,suffix:string|null){ - super(id) - this.renderer = renderer - this.min = min - this.max = max - this.initialValue = this.#parseValue(value) - this.value = this.#parseValue(value) - this.autoStop = autoStop - this.prefix = prefix - this.suffix = suffix - } - /**Parse a value in such a way that it doesn't go below/above the min/max limits. */ - #parseValue(value:number){ - if (value > this.max) return this.max - else if (value < this.min) return this.min - else return value - } - /**Render progress bar to the console. */ - #renderStdout(){ - if (!this.#active) return - readline.clearLine(process.stdout,0) - readline.cursorTo(process.stdout,0) - process.stdout.write(this.renderer.render(this.min,this.max,this.value,this.prefix,this.suffix)) - } - /**Start showing this progress bar in the console. */ - start(): boolean { - if (this.#active) return false - this.value = this.#parseValue(this.initialValue) - this.#active = true - this.#renderStdout() - return true - } - /**Update this progress bar while active. (will automatically update the progress bar in the console) */ - protected update(value:number,stop?:boolean): boolean { - if (!this.#active) return false - this.value = this.#parseValue(value) - this.#renderStdout() - if (stop || (this.autoStop == "max" && this.value == this.max) || (this.autoStop == "min" && this.value == this.min)){ - process.stdout.write("\n") - this.#active = false - this.#stopListeners.forEach((cb) => cb()) - this.#stopListeners = [] - } - return true - } - /**Wait for the progress bar to finish. */ - finished(): Promise { - return new Promise((resolve) => { - this.#stopListeners.push(resolve) - }) - } -} - -/**## ODTimedProgressBar `class` - * This is an Open Ticket timed console progress bar. - * - * It is used to create a simple timed progress bar in the console. - * You can set a fixed duration (milliseconds) in the constructor. - */ -export class ODTimedProgressBar extends ODProgressBar { - /**The time in milliseconds. */ - time: number - /**The mode of the timer. */ - mode: "increasing"|"decreasing" - - constructor(id:ODValidId,renderer:ODProgressBarRenderer<{}>,time:number,mode:"increasing"|"decreasing",prefix:string|null,suffix:string|null){ - super(id,renderer,0,time,0,(mode == "increasing") ? "max" : "min",prefix,suffix) - this.time = time - this.mode = mode - } - - /**The timer which is used. */ - async #timer(ms:number): Promise { - return new Promise((resolve) => { - setTimeout(() => { - resolve() - },ms) - }) - } - /**Run the timed progress bar. */ - async #execute(){ - let i = 0 - const fragment = this.time/100 - while (i < 100){ - await this.#timer(fragment) - i++ - super.update((this.mode == "increasing") ? (i*fragment) : this.time-(i*fragment)) - } - } - start(){ - const res = super.start() - if (!res) return false - this.#execute() - return true - } -} - -/**## ODManualProgressBar `class` - * This is an Open Ticket manual console progress bar. - * - * It is used to create a simple manual progress bar in the console. - * You can update the progress manually using `update()`. - */ -export class ODManualProgressBar extends ODProgressBar { - constructor(id:ODValidId,renderer:ODProgressBarRenderer<{}>,amount:number,autoStop:null|"min"|"max",prefix:string|null,suffix:string|null){ - super(id,renderer,0,amount,0,autoStop,prefix,suffix) - } - /**Set the value of the progress bar. */ - set(value:number,stop?:boolean){ - super.update(value,stop) - } - /**Get the current value of the progress bar. */ - get(){ - return this.value - } - /**Increase the value of the progress bar. */ - increase(amount:number,stop?:boolean){ - super.update(this.value+amount,stop) - } - /**Decrease the value of the progress bar. */ - decrease(amount:number,stop?:boolean){ - super.update(this.value-amount,stop) - } -} \ No newline at end of file diff --git a/src/core/api/modules/responder.ts b/src/core/api/modules/responder.ts deleted file mode 100644 index 9f1da86..0000000 --- a/src/core/api/modules/responder.ts +++ /dev/null @@ -1,1418 +0,0 @@ -/////////////////////////////////////// -//RESPONDER MODULE -/////////////////////////////////////// -import { ODId, ODManager, ODValidId, ODSystemError, ODManagerData } from "./base" -import * as discord from "discord.js" -import { ODWorkerManager, ODWorkerCallback, ODWorker } from "./worker" -import { ODDebugger } from "./console" -import { ODClientManager, ODContextMenu, ODSlashCommand, ODTextCommand, ODTextCommandInteractionOption } from "./client" -import { ODDropdownData, ODMessageBuildResult, ODMessageBuildSentResult, ODModalBuildResult } from "./builder" - -/**## ODResponderImplementation `class` - * This is an Open Ticket responder implementation. - * - * It is a basic implementation of the `ODWorkerManager` used by all `ODResponder` classes. - * - * This class can't be used stand-alone & needs to be extended from! - */ -export class ODResponderImplementation extends ODManagerData { - /**The manager that has all workers of this implementation */ - workers: ODWorkerManager - /**The `commandName` or `customId` needs to match this string or regex for this responder to be executed. */ - match: string|RegExp - - constructor(id:ODValidId, match:string|RegExp, callback?:ODWorkerCallback, priority?:number, callbackId?:ODValidId){ - super(id) - this.match = match - this.workers = new ODWorkerManager("descending") - if (callback) this.workers.add(new ODWorker(callbackId ? callbackId : id,priority ?? 0,callback)) - } - /**Execute all workers & return the result. */ - async respond(instance:Instance, source:Source, params:Params): Promise { - throw new ODSystemError("Tried to build an unimplemented ODResponderImplementation") - } -} - -/**## ODResponderTimeoutErrorCallback `type` - * This is the callback for the responder timeout function. It will be executed when something went wrong or the action takes too much time. - */ -export type ODResponderTimeoutErrorCallback = (instance:Instance, source:Source) => void|Promise - -/**## ODResponderManager `class` - * This is an Open Ticket responder manager. - * - * It contains all Open Ticket responders. Responders can respond to an interaction, button, dropdown, modal or command. - * - * Using the Open Ticket responder system has a few advantages compared to vanilla discord.js: - * - plugins can extend/edit replies - * - automatically reply on error - * - independent workers (with priority) - * - fail-safe design using try-catch - * - write code once => reply to both slash & text commands at the same time! - * - know where the request came from & parse options/subcommands & without errors! - * - And so much more! - */ -export class ODResponderManager { - /**A manager for all (text & slash) command responders. */ - commands: ODCommandResponderManager - /**A manager for all button responders. */ - buttons: ODButtonResponderManager - /**A manager for all dropdown/select menu responders. */ - dropdowns: ODDropdownResponderManager - /**A manager for all modal responders. */ - modals: ODModalResponderManager - /**A manager for all context menu responders. */ - contextMenus: ODContextMenuResponderManager - /**A manager for all autocomplete responders. */ - autocomplete: ODAutocompleteResponderManager - - constructor(debug:ODDebugger, client:ODClientManager){ - this.commands = new ODCommandResponderManager(debug,"command responder",client) - this.buttons = new ODButtonResponderManager(debug,"button responder",client) - this.dropdowns = new ODDropdownResponderManager(debug,"dropdown responder",client) - this.modals = new ODModalResponderManager(debug,"modal responder",client) - this.contextMenus = new ODContextMenuResponderManager(debug,"context menu responder",client) - this.autocomplete = new ODAutocompleteResponderManager(debug,"autocomplete responder",client) - } -} - -/**## ODCommandResponderManager `class` - * This is an Open Ticket command responder manager. - * - * It contains all Open Ticket command responders. These can respond to text & slash commands. - * - * Using the Open Ticket responder system has a few advantages compared to vanilla discord.js: - * - plugins can extend/edit replies - * - automatically reply on error - * - independent workers (with priority) - * - fail-safe design using try-catch - * - write code once => reply to both slash & text commands at the same time! - * - know where the request came from & parse options/subcommands & without errors! - * - And so much more! - */ -export class ODCommandResponderManager extends ODManager> { - /**An alias to the Open Ticket client manager. */ - #client: ODClientManager - /**The callback executed when the default workers take too much time to reply. */ - #timeoutErrorCallback: ODResponderTimeoutErrorCallback|null = null - /**The amount of milliseconds before the timeout error callback is executed. */ - #timeoutMs: number|null = null - - constructor(debug:ODDebugger, debugname:string, client:ODClientManager){ - super(debug,debugname) - this.#client = client - } - - /**Set the message to send when the response times out! */ - setTimeoutErrorCallback(callback:ODResponderTimeoutErrorCallback|null, ms:number|null){ - this.#timeoutErrorCallback = callback - this.#timeoutMs = ms - } - - add(data:ODCommandResponder<"slash"|"text",any>, overwrite?:boolean){ - const res = super.add(data,overwrite) - - //add the callback to the slash command manager - this.#client.slashCommands.onInteraction(data.match,(interaction,cmd) => { - const newData = this.get(data.id) - if (!newData) return - newData.respond(new ODCommandResponderInstance(interaction,cmd,this.#timeoutErrorCallback,this.#timeoutMs),"slash",{}) - }) - - //add the callback to the text command manager - this.#client.textCommands.onInteraction(data.prefix,data.match,(interaction,cmd,options) => { - const newData = this.get(data.id) - if (!newData) return - newData.respond(new ODCommandResponderInstance(interaction,cmd,this.#timeoutErrorCallback,this.#timeoutMs,options),"text",{}) - }) - - return res - } -} - -/**## ODCommandResponderInstanceOptions `class` - * This is an Open Ticket command responder instance options manager. - * - * This class will manage all options & subcommands from slash & text commands. - */ -export class ODCommandResponderInstanceOptions { - /**The interaction to get data from. */ - #interaction: discord.ChatInputCommandInteraction|discord.Message - /**The command which is related to the interaction. */ - #cmd:ODSlashCommand|ODTextCommand - /**A list of options which have been parsed by the text command parser. */ - #options: ODTextCommandInteractionOption[] - - constructor(interaction:discord.ChatInputCommandInteraction|discord.Message, cmd:ODSlashCommand|ODTextCommand, options?:ODTextCommandInteractionOption[]){ - this.#interaction = interaction - this.#cmd = cmd - this.#options = options ?? [] - } - - /**Get a string option. */ - getString(name:string,required:true): string - getString(name:string,required:false): string|null - getString(name:string,required:boolean){ - if (this.#interaction instanceof discord.ChatInputCommandInteraction){ - try { - return this.#interaction.options.getString(name,required) - }catch{ - throw new ODSystemError("ODCommandResponderInstanceOptions:getString() slash command option not found!") - } - - }else if (this.#interaction instanceof discord.Message){ - const opt = this.#options.find((opt) => opt.type == "string" && opt.name == name) - if (opt && typeof opt.value == "string") return opt.value - else return null - - }else return null - } - /**Get a boolean option. */ - getBoolean(name:string,required:true): boolean - getBoolean(name:string,required:false): boolean|null - getBoolean(name:string,required:boolean){ - if (this.#interaction instanceof discord.ChatInputCommandInteraction){ - try { - return this.#interaction.options.getBoolean(name,required) - }catch{ - throw new ODSystemError("ODCommandResponderInstanceOptions:getBoolean() slash command option not found!") - } - - }else if (this.#interaction instanceof discord.Message){ - const opt = this.#options.find((opt) => opt.type == "boolean" && opt.name == name) - if (opt && typeof opt.value == "boolean") return opt.value - else return null - - }else return null - } - /**Get a number option. */ - getNumber(name:string,required:true): number - getNumber(name:string,required:false): number|null - getNumber(name:string,required:boolean){ - if (this.#interaction instanceof discord.ChatInputCommandInteraction){ - try { - return this.#interaction.options.getNumber(name,required) - }catch{ - throw new ODSystemError("ODCommandResponderInstanceOptions:getNumber() slash command option not found!") - } - - }else if (this.#interaction instanceof discord.Message){ - const opt = this.#options.find((opt) => opt.type == "number" && opt.name == name) - if (opt && typeof opt.value == "number") return opt.value - else return null - - }else return null - } - /**Get a channel option. */ - getChannel(name:string,required:true): discord.TextChannel|discord.VoiceChannel|discord.StageChannel|discord.NewsChannel|discord.MediaChannel|discord.ForumChannel|discord.CategoryChannel - getChannel(name:string,required:false): discord.TextChannel|discord.VoiceChannel|discord.StageChannel|discord.NewsChannel|discord.MediaChannel|discord.ForumChannel|discord.CategoryChannel|null - getChannel(name:string,required:boolean){ - if (this.#interaction instanceof discord.ChatInputCommandInteraction){ - try { - return this.#interaction.options.getChannel(name,required) - }catch{ - throw new ODSystemError("ODCommandResponderInstanceOptions:getChannel() slash command option not found!") - } - - }else if (this.#interaction instanceof discord.Message){ - const opt = this.#options.find((opt) => opt.type == "channel" && opt.name == name) - if (opt && (opt.value instanceof discord.TextChannel || opt.value instanceof discord.VoiceChannel || opt.value instanceof discord.StageChannel || opt.value instanceof discord.NewsChannel || opt.value instanceof discord.MediaChannel || opt.value instanceof discord.ForumChannel || opt.value instanceof discord.CategoryChannel)) return opt.value - else return null - - }else return null - } - /**Get a role option. */ - getRole(name:string,required:true): discord.Role - getRole(name:string,required:false): discord.Role|null - getRole(name:string,required:boolean){ - if (this.#interaction instanceof discord.ChatInputCommandInteraction){ - try { - return this.#interaction.options.getRole(name,required) - }catch{ - throw new ODSystemError("ODCommandResponderInstanceOptions:getRole() slash command option not found!") - } - - }else if (this.#interaction instanceof discord.Message){ - const opt = this.#options.find((opt) => opt.type == "role" && opt.name == name) - if (opt && opt.value instanceof discord.Role) return opt.value - else return null - - }else return null - } - /**Get a user option. */ - getUser(name:string,required:true): discord.User - getUser(name:string,required:false): discord.User|null - getUser(name:string,required:boolean){ - if (this.#interaction instanceof discord.ChatInputCommandInteraction){ - try { - return this.#interaction.options.getUser(name,required) - }catch{ - throw new ODSystemError("ODCommandResponderInstanceOptions:getUser() slash command option not found!") - } - - }else if (this.#interaction instanceof discord.Message){ - const opt = this.#options.find((opt) => opt.type == "user" && opt.name == name) - if (opt && opt.value instanceof discord.User) return opt.value - else return null - - }else return null - } - /**Get a guild member option. */ - getGuildMember(name:string,required:true): discord.GuildMember - getGuildMember(name:string,required:false): discord.GuildMember|null - getGuildMember(name:string,required:boolean){ - if (this.#interaction instanceof discord.ChatInputCommandInteraction){ - try { - const member = this.#interaction.options.getMember(name) - if (!member && required) throw new ODSystemError("ODCommandResponderInstanceOptions:getGuildMember() slash command option not found!") - return member - }catch{ - throw new ODSystemError("ODCommandResponderInstanceOptions:getGuildMember() slash command option not found!") - } - - }else if (this.#interaction instanceof discord.Message){ - const opt = this.#options.find((opt) => opt.type == "guildmember" && opt.name == name) - if (opt && opt.value instanceof discord.GuildMember) return opt.value - else return null - - }else return null - } - /**Get a mentionable option. */ - getMentionable(name:string,required:true): discord.User|discord.GuildMember|discord.Role - getMentionable(name:string,required:false): discord.User|discord.GuildMember|discord.Role|null - getMentionable(name:string,required:boolean){ - if (this.#interaction instanceof discord.ChatInputCommandInteraction){ - try { - return this.#interaction.options.getMentionable(name,required) - }catch{ - throw new ODSystemError("ODCommandResponderInstanceOptions:getGuildMember() slash command option not found!") - } - - }else if (this.#interaction instanceof discord.Message){ - const opt = this.#options.find((opt) => opt.type == "mentionable" && opt.name == name) - if (opt && (opt.value instanceof discord.User || opt.value instanceof discord.GuildMember || opt.value instanceof discord.Role)) return opt.value - else return null - - }else return null - } - /**Get a subgroup. */ - getSubGroup(): string|null - getSubGroup(){ - if (this.#interaction instanceof discord.ChatInputCommandInteraction){ - try { - return this.#interaction.options.getSubcommandGroup(true) - }catch{ - throw new ODSystemError("ODCommandResponderInstanceOptions:getSubGroup() slash command option not found!") - } - - }else if (this.#interaction instanceof discord.Message && this.#cmd instanceof ODTextCommand){ - //0: name, 1:sub/group, 2:sub - const splittedName: string[] = this.#cmd.builder.name.split(" ") - return splittedName[1] ?? null - - }else return null - } - /**Get a subcommand. */ - getSubCommand(): string|null - getSubCommand(){ - if (this.#interaction instanceof discord.ChatInputCommandInteraction){ - try { - return this.#interaction.options.getSubcommand(true) - }catch{ - throw new ODSystemError("ODCommandResponderInstanceOptions:getSubCommand() slash command option not found!") - } - - }else if (this.#interaction instanceof discord.Message && this.#cmd instanceof ODTextCommand){ - //0: name, 1:sub/group, 2:sub - const splittedName: string[] = this.#cmd.builder.name.split(" ") - - //return the second subcommand when there is a subgroup - if (splittedName.length > 2){ - return splittedName[2] ?? null - }else return splittedName[1] ?? null - - }else return null - } -} - - -/**## ODCommandResponderInstance `class` - * This is an Open Ticket command responder instance. - * - * An instance is an active slash interaction or used text command. You can reply to the command using `reply()` for both slash & text commands. - */ -export class ODCommandResponderInstance { - /**The interaction which is the source of this instance. */ - interaction: discord.ChatInputCommandInteraction|discord.Message - /**The command wich is the source of this instance. */ - cmd:ODSlashCommand|ODTextCommand - /**The type/source of instance. (from text or slash command) */ - type: "message"|"interaction" - /**Did a worker already reply to this instance/interaction? */ - didReply: boolean = false - /**The manager for all options of this command. */ - options: ODCommandResponderInstanceOptions - /**The user who triggered this command. */ - user: discord.User - /**The guild member who triggered this command. */ - member: discord.GuildMember|null - /**The guild where this command was triggered. */ - guild: discord.Guild|null - /**The channel where this command was triggered. */ - channel: discord.TextBasedChannel - - constructor(interaction:discord.ChatInputCommandInteraction|discord.Message, cmd:ODSlashCommand|ODTextCommand, errorCallback:ODResponderTimeoutErrorCallback|null, timeoutMs:number|null, options?:ODTextCommandInteractionOption[]){ - if (!interaction.channel) throw new ODSystemError("ODCommandResponderInstance: Unable to find interaction channel!") - this.interaction = interaction - this.cmd = cmd - this.type = (interaction instanceof discord.Message) ? "message" : "interaction" - this.options = new ODCommandResponderInstanceOptions(interaction,cmd,options) - this.user = (interaction instanceof discord.Message) ? interaction.author : interaction.user - this.member = (interaction.member instanceof discord.GuildMember) ? interaction.member : null - this.guild = interaction.guild - this.channel = interaction.channel - - - setTimeout(async () => { - if (!this.didReply){ - try { - if (!errorCallback){ - this.reply({id:new ODId("looks-like-we-got-an-error-here"), ephemeral:true, message:{ - content:":x: **Something went wrong while replying to this command!**" - }}) - }else{ - await errorCallback(this,(this.type == "interaction") ? "slash" : "text") - } - - }catch(err){ - process.emit("uncaughtException",err) - } - } - },timeoutMs ?? 2500) - } - - /**Reply to this command. */ - async reply(msg:ODMessageBuildResult): Promise> { - try { - const msgFlags: number[] = msg.ephemeral ? [discord.MessageFlags.Ephemeral] : [] - if (this.type == "interaction" && this.interaction instanceof discord.ChatInputCommandInteraction){ - if (this.interaction.replied || this.interaction.deferred){ - const sent = await this.interaction.editReply(Object.assign(msg.message,{flags:msgFlags})) - this.didReply = true - return {success:true,message:sent} - }else{ - const sent = await this.interaction.reply(Object.assign(msg.message,{flags:msgFlags})) - this.didReply = true - return {success:true,message:await sent.fetch()} - } - }else if (this.type == "message" && this.interaction instanceof discord.Message && this.interaction.channel.type != discord.ChannelType.GroupDM){ - const sent = await this.interaction.channel.send(msg.message) - this.didReply = true - return {success:true,message:sent} - }else return {success:false,message:null} - }catch{ - return {success:false,message:null} - } - } - /**Defer this command. */ - async defer(ephemeral:boolean){ - if (this.type != "interaction" || !(this.interaction instanceof discord.ChatInputCommandInteraction)) return false - if (this.interaction.deferred || this.interaction.replied) return false - const msgFlags: number[] = ephemeral ? [discord.MessageFlags.Ephemeral] : [] - await this.interaction.deferReply({flags:msgFlags}) - this.didReply = true - return true - } - /**Show a modal as reply to this command. */ - async modal(modal:ODModalBuildResult){ - if (this.type != "interaction" || !(this.interaction instanceof discord.ChatInputCommandInteraction)) return false - if (this.interaction.deferred || this.interaction.replied) return false - await this.interaction.showModal(modal.modal) - this.didReply = true - return true - } -} - -/**## ODCommandResponder `class` - * This is an Open Ticket command responder. - * - * This class manages all workers which are executed when the related command is triggered. - */ -export class ODCommandResponder extends ODResponderImplementation { - /**The prefix of the text command needs to match this */ - prefix: string - - constructor(id:ODValidId, prefix:string, match:string|RegExp, callback?:ODWorkerCallback, priority?:number, callbackId?:ODValidId){ - super(id,match,callback,priority,callbackId) - this.prefix = prefix - } - - /**Respond to this command */ - async respond(instance:ODCommandResponderInstance, source:Source, params:Params){ - //wait for workers to finish - await this.workers.executeWorkers(instance,source,params) - } -} - -/**## ODButtonResponderManager `class` - * This is an Open Ticket button responder manager. - * - * It contains all Open Ticket button responders. These can respond to button interactions. - * - * Using the Open Ticket responder system has a few advantages compared to vanilla discord.js: - * - plugins can extend/edit replies - * - automatically reply on error - * - independent workers (with priority) - * - fail-safe design using try-catch - * - know where the request came from! - * - And so much more! - */ -export class ODButtonResponderManager extends ODManager> { - /**An alias to the Open Ticket client manager. */ - #client: ODClientManager - /**The callback executed when the default workers take too much time to reply. */ - #timeoutErrorCallback: ODResponderTimeoutErrorCallback|null = null - /**The amount of milliseconds before the timeout error callback is executed. */ - #timeoutMs: number|null = null - /**A list of listeners which will listen to the raw interactionCreate event from discord.js */ - #listeners: ((interaction:discord.ButtonInteraction) => void)[] = [] - - constructor(debug:ODDebugger, debugname:string, client:ODClientManager){ - super(debug,debugname) - this.#client = client - - this.#client.client.on("interactionCreate",(interaction) => { - if (!interaction.isButton()) return - this.#listeners.forEach((cb) => cb(interaction)) - }) - } - - /**Set the message to send when the response times out! */ - setTimeoutErrorCallback(callback:ODResponderTimeoutErrorCallback|null, ms:number|null){ - this.#timeoutErrorCallback = callback - this.#timeoutMs = ms - } - - add(data:ODButtonResponder<"button",any>, overwrite?:boolean){ - const res = super.add(data,overwrite) - - this.#listeners.push((interaction) => { - const newData = this.get(data.id) - if (!newData) return - if ((typeof newData.match == "string") ? interaction.customId == newData.match : newData.match.test(interaction.customId)) newData.respond(new ODButtonResponderInstance(interaction,this.#timeoutErrorCallback,this.#timeoutMs),"button",{}) - }) - - return res - } -} - -/**## ODButtonResponderInstance `class` - * This is an Open Ticket button responder instance. - * - * An instance is an active button interaction. You can reply to the button using `reply()`. - */ -export class ODButtonResponderInstance { - /**The interaction which is the source of this instance. */ - interaction: discord.ButtonInteraction - /**Did a worker already reply to this instance/interaction? */ - didReply: boolean = false - /**The user who triggered this button. */ - user: discord.User - /**The guild member who triggered this button. */ - member: discord.GuildMember|null - /**The guild where this button was triggered. */ - guild: discord.Guild|null - /**The channel where this button was triggered. */ - channel: discord.TextBasedChannel - /**The message this button originates from. */ - message: discord.Message - - constructor(interaction:discord.ButtonInteraction, errorCallback:ODResponderTimeoutErrorCallback|null, timeoutMs:number|null){ - if (!interaction.channel) throw new ODSystemError("ODButtonResponderInstance: Unable to find interaction channel!") - this.interaction = interaction - this.user = interaction.user - this.member = (interaction.member instanceof discord.GuildMember) ? interaction.member : null - this.guild = interaction.guild - this.channel = interaction.channel - this.message = interaction.message - - setTimeout(async () => { - if (!this.didReply){ - try { - if (!errorCallback){ - this.reply({id:new ODId("looks-like-we-got-an-error-here"), ephemeral:true, message:{ - content:":x: **Something went wrong while replying to this button!**" - }}) - }else{ - await errorCallback(this,"button") - } - - }catch(err){ - process.emit("uncaughtException",err) - } - } - },timeoutMs ?? 2500) - } - - /**Reply to this button. */ - async reply(msg:ODMessageBuildResult): Promise> { - try{ - const msgFlags: number[] = msg.ephemeral ? [discord.MessageFlags.Ephemeral] : [] - if (this.interaction.replied || this.interaction.deferred){ - const sent = await this.interaction.editReply(Object.assign(msg.message,{flags:msgFlags})) - this.didReply = true - return {success:true,message:sent} - }else{ - const sent = await this.interaction.reply(Object.assign(msg.message,{flags:msgFlags})) - this.didReply = true - return {success:true,message:await sent.fetch()} - } - }catch{ - return {success:false,message:null} - } - } - /**Update the message of this button. */ - async update(msg:ODMessageBuildResult): Promise> { - try{ - const msgFlags: number[] = msg.ephemeral ? [discord.MessageFlags.Ephemeral] : [] - if (this.interaction.replied || this.interaction.deferred){ - const sent = await this.interaction.editReply(Object.assign(msg.message,{flags:msgFlags})) - this.didReply = true - return {success:true,message:await sent.fetch()} - }else{ - const sent = await this.interaction.update(Object.assign(msg.message,{flags:msgFlags})) - this.didReply = true - return {success:true,message:await sent.fetch()} - } - }catch{ - return {success:false,message:null} - } - } - /**Defer this button. */ - async defer(type:"reply"|"update", ephemeral:boolean){ - if (this.interaction.deferred || this.interaction.replied) return false - if (type == "reply"){ - const msgFlags: number[] = ephemeral ? [discord.MessageFlags.Ephemeral] : [] - await this.interaction.deferReply({flags:msgFlags}) - }else{ - await this.interaction.deferUpdate() - } - this.didReply = true - return true - } - /**Show a modal as reply to this button. */ - async modal(modal:ODModalBuildResult){ - if (this.interaction.deferred || this.interaction.replied) return false - await this.interaction.showModal(modal.modal) - this.didReply = true - return true - } - - /**Get a component from the original message of this button. */ - getMessageComponent(type:"button",id:string|RegExp): discord.ButtonComponent|null - getMessageComponent(type:"string-dropdown",id:string|RegExp): discord.StringSelectMenuComponent|null - getMessageComponent(type:"user-dropdown",id:string|RegExp): discord.UserSelectMenuComponent|null - getMessageComponent(type:"channel-dropdown",id:string|RegExp): discord.ChannelSelectMenuComponent|null - getMessageComponent(type:"role-dropdown",id:string|RegExp): discord.RoleSelectMenuComponent|null - getMessageComponent(type:"mentionable-dropdown",id:string|RegExp): discord.MentionableSelectMenuComponent|null - - getMessageComponent(type:"button"|"string-dropdown"|"user-dropdown"|"channel-dropdown"|"role-dropdown"|"mentionable-dropdown", id:string|RegExp): discord.ButtonComponent|discord.StringSelectMenuComponent|discord.RoleSelectMenuComponent|discord.ChannelSelectMenuComponent|discord.MentionableSelectMenuComponent|discord.UserSelectMenuComponent|null { - let result: discord.ButtonComponent|discord.StringSelectMenuComponent|discord.RoleSelectMenuComponent|discord.ChannelSelectMenuComponent|discord.MentionableSelectMenuComponent|discord.UserSelectMenuComponent|null = null - this.message.components.forEach((row) => { - if (row.type != discord.ComponentType.ActionRow) return - row.components.forEach((component) => { - if (type == "button" && component.type == discord.ComponentType.Button && component.customId && ((typeof id == "string") ? component.customId == id : id.test(component.customId))) result = component - else if (type == "string-dropdown" && component.type == discord.ComponentType.StringSelect && component.customId && ((typeof id == "string") ? component.customId == id : id.test(component.customId))) result = component - else if (type == "user-dropdown" && component.type == discord.ComponentType.UserSelect && component.customId && ((typeof id == "string") ? component.customId == id : id.test(component.customId))) result = component - else if (type == "channel-dropdown" && component.type == discord.ComponentType.ChannelSelect && component.customId && ((typeof id == "string") ? component.customId == id : id.test(component.customId))) result = component - else if (type == "role-dropdown" && component.type == discord.ComponentType.RoleSelect && component.customId && ((typeof id == "string") ? component.customId == id : id.test(component.customId))) result = component - else if (type == "mentionable-dropdown" && component.type == discord.ComponentType.MentionableSelect && component.customId && ((typeof id == "string") ? component.customId == id : id.test(component.customId))) result = component - }) - }) - - return result - } - - /**Get the first embed of the original message if it exists. */ - getMessageEmbed(): discord.Embed|null { - return this.message.embeds[0] ?? null - } -} - -/**## ODButtonResponder `class` - * This is an Open Ticket button responder. - * - * This class manages all workers which are executed when the related button is triggered. - */ -export class ODButtonResponder extends ODResponderImplementation { - /**Respond to this button */ - async respond(instance:ODButtonResponderInstance, source:Source, params:Params){ - //wait for workers to finish - await this.workers.executeWorkers(instance,source,params) - } -} - -/**## ODDropdownResponderManager `class` - * This is an Open Ticket dropdown responder manager. - * - * It contains all Open Ticket dropdown responders. These can respond to dropdown interactions. - * - * Using the Open Ticket responder system has a few advantages compared to vanilla discord.js: - * - plugins can extend/edit replies - * - automatically reply on error - * - independent workers (with priority) - * - fail-safe design using try-catch - * - know where the request came from! - * - And so much more! - */ -export class ODDropdownResponderManager extends ODManager> { - /**An alias to the Open Ticket client manager. */ - #client: ODClientManager - /**The callback executed when the default workers take too much time to reply. */ - #timeoutErrorCallback: ODResponderTimeoutErrorCallback|null = null - /**The amount of milliseconds before the timeout error callback is executed. */ - #timeoutMs: number|null = null - /**A list of listeners which will listen to the raw interactionCreate event from discord.js */ - #listeners: ((interaction:discord.AnySelectMenuInteraction) => void)[] = [] - - constructor(debug:ODDebugger, debugname:string, client:ODClientManager){ - super(debug,debugname) - this.#client = client - - this.#client.client.on("interactionCreate",(interaction) => { - if (!interaction.isAnySelectMenu()) return - this.#listeners.forEach((cb) => cb(interaction)) - }) - } - - /**Set the message to send when the response times out! */ - setTimeoutErrorCallback(callback:ODResponderTimeoutErrorCallback|null, ms:number|null){ - this.#timeoutErrorCallback = callback - this.#timeoutMs = ms - } - - add(data:ODDropdownResponder<"dropdown",any>, overwrite?:boolean){ - const res = super.add(data,overwrite) - - this.#listeners.push((interaction) => { - const newData = this.get(data.id) - if (!newData) return - if ((typeof newData.match == "string") ? interaction.customId == newData.match : newData.match.test(interaction.customId)) newData.respond(new ODDropdownResponderInstance(interaction,this.#timeoutErrorCallback,this.#timeoutMs),"dropdown",{}) - }) - - return res - } -} - -/**## ODDropdownResponderInstanceValues `class` - * This is an Open Ticket dropdown responder instance values manager. - * - * This class will manage all values from the dropdowns & select menus. - */ -export class ODDropdownResponderInstanceValues { - /**The interaction to get data from. */ - #interaction: discord.AnySelectMenuInteraction - /**The type of this dropdown. */ - #type: ODDropdownData["type"] - - constructor(interaction:discord.AnySelectMenuInteraction, type:ODDropdownData["type"]){ - this.#interaction = interaction - this.#type = type - - if (interaction.isChannelSelectMenu()){ - interaction.values - } - } - - /**Get the selected values. */ - getStringValues(): string[] { - try { - return this.#interaction.values - }catch{ - throw new ODSystemError("ODDropdownResponderInstanceValues:getStringValues() invalid values!") - } - } - /**Get the selected roles. */ - async getRoleValues(): Promise { - if (this.#type != "role") throw new ODSystemError("ODDropdownResponderInstanceValues:getRoleValues() dropdown type isn't role!") - try { - const result: discord.Role[] = [] - for (const id of this.#interaction.values){ - if (!this.#interaction.guild) break - const role = await this.#interaction.guild.roles.fetch(id) - if (role) result.push(role) - } - return result - }catch{ - throw new ODSystemError("ODDropdownResponderInstanceValues:getRoleValues() invalid values!") - } - } - /**Get the selected users. */ - async getUserValues(): Promise { - if (this.#type != "role") throw new ODSystemError("ODDropdownResponderInstanceValues:getUserValues() dropdown type isn't user!") - try { - const result: discord.User[] = [] - for (const id of this.#interaction.values){ - const user = await this.#interaction.client.users.fetch(id) - if (user) result.push(user) - } - return result - }catch{ - throw new ODSystemError("ODDropdownResponderInstanceValues:getUserValues() invalid values!") - } - } - /**Get the selected channels. */ - async getChannelValues(): Promise { - if (this.#type != "role") throw new ODSystemError("ODDropdownResponderInstanceValues:getChannelValues() dropdown type isn't channel!") - try { - const result: discord.GuildBasedChannel[] = [] - for (const id of this.#interaction.values){ - if (!this.#interaction.guild) break - const guild = await this.#interaction.guild.channels.fetch(id) - if (guild) result.push(guild) - } - return result - }catch{ - throw new ODSystemError("ODDropdownResponderInstanceValues:getChannelValues() invalid values!") - } - } -} - -/**## ODDropdownResponderInstance `class` - * This is an Open Ticket dropdown responder instance. - * - * An instance is an active dropdown interaction. You can reply to the dropdown using `reply()`. - */ -export class ODDropdownResponderInstance { - /**The interaction which is the source of this instance. */ - interaction: discord.AnySelectMenuInteraction - /**Did a worker already reply to this instance/interaction? */ - didReply: boolean = false - /**The dropdown type. */ - type: ODDropdownData["type"] - /**The manager for all values of this dropdown. */ - values: ODDropdownResponderInstanceValues - /**The user who triggered this dropdown. */ - user: discord.User - /**The guild member who triggered this dropdown. */ - member: discord.GuildMember|null - /**The guild where this dropdown was triggered. */ - guild: discord.Guild|null - /**The channel where this dropdown was triggered. */ - channel: discord.TextBasedChannel - /**The message this dropdown originates from. */ - message: discord.Message - - constructor(interaction:discord.AnySelectMenuInteraction, errorCallback:ODResponderTimeoutErrorCallback|null, timeoutMs:number|null){ - if (!interaction.channel) throw new ODSystemError("ODDropdownResponderInstance: Unable to find interaction channel!") - this.interaction = interaction - if (interaction.isStringSelectMenu()){ - this.type = "string" - }else if (interaction.isRoleSelectMenu()){ - this.type = "role" - }else if (interaction.isUserSelectMenu()){ - this.type = "user" - }else if (interaction.isChannelSelectMenu()){ - this.type = "channel" - }else if (interaction.isMentionableSelectMenu()){ - this.type = "mentionable" - }else throw new ODSystemError("ODDropdownResponderInstance: invalid dropdown type!") - - this.values = new ODDropdownResponderInstanceValues(interaction,this.type) - this.user = interaction.user - this.member = (interaction.member instanceof discord.GuildMember) ? interaction.member : null - this.guild = interaction.guild - this.channel = interaction.channel - this.message = interaction.message - - setTimeout(async () => { - if (!this.didReply){ - try { - if (!errorCallback){ - this.reply({id:new ODId("looks-like-we-got-an-error-here"), ephemeral:true, message:{ - content:":x: **Something went wrong while replying to this dropdown!**" - }}) - }else{ - await errorCallback(this,"dropdown") - } - - }catch(err){ - process.emit("uncaughtException",err) - } - } - },timeoutMs ?? 2500) - } - - /**Reply to this dropdown. */ - async reply(msg:ODMessageBuildResult): Promise> { - try { - const msgFlags: number[] = msg.ephemeral ? [discord.MessageFlags.Ephemeral] : [] - if (this.interaction.replied || this.interaction.deferred){ - const sent = await this.interaction.editReply(Object.assign(msg.message,{flags:msgFlags})) - this.didReply = true - return {success:true,message:sent} - }else{ - const sent = await this.interaction.reply(Object.assign(msg.message,{flags:msgFlags})) - this.didReply = true - return {success:true,message:await sent.fetch()} - } - }catch{ - return {success:false,message:null} - } - } - /**Update the message of this dropdown. */ - async update(msg:ODMessageBuildResult): Promise> { - try{ - const msgFlags: number[] = msg.ephemeral ? [discord.MessageFlags.Ephemeral] : [] - if (this.interaction.replied || this.interaction.deferred){ - const sent = await this.interaction.editReply(Object.assign(msg.message,{flags:msgFlags})) - this.didReply = true - return {success:true,message:await sent.fetch()} - }else{ - const sent = await this.interaction.update(Object.assign(msg.message,{flags:msgFlags})) - this.didReply = true - return {success:true,message:await sent.fetch()} - } - }catch{ - return {success:false,message:null} - } - } - /**Defer this dropdown. */ - async defer(type:"reply"|"update", ephemeral:boolean){ - if (this.interaction.deferred || this.interaction.replied) return false - if (type == "reply"){ - const msgFlags: number[] = ephemeral ? [discord.MessageFlags.Ephemeral] : [] - await this.interaction.deferReply({flags:msgFlags}) - }else{ - await this.interaction.deferUpdate() - } - this.didReply = true - return true - } - /**Show a modal as reply to this dropdown. */ - async modal(modal:ODModalBuildResult){ - if (this.interaction.deferred || this.interaction.replied) return false - await this.interaction.showModal(modal.modal) - this.didReply = true - return true - } - - /**Get a component from the original message of this dropdown. */ - getMessageComponent(type:"button",id:string|RegExp): discord.ButtonComponent|null - getMessageComponent(type:"string-dropdown",id:string|RegExp): discord.StringSelectMenuComponent|null - getMessageComponent(type:"user-dropdown",id:string|RegExp): discord.UserSelectMenuComponent|null - getMessageComponent(type:"channel-dropdown",id:string|RegExp): discord.ChannelSelectMenuComponent|null - getMessageComponent(type:"role-dropdown",id:string|RegExp): discord.RoleSelectMenuComponent|null - getMessageComponent(type:"mentionable-dropdown",id:string|RegExp): discord.MentionableSelectMenuComponent|null - - getMessageComponent(type:"button"|"string-dropdown"|"user-dropdown"|"channel-dropdown"|"role-dropdown"|"mentionable-dropdown", id:string|RegExp): discord.ButtonComponent|discord.StringSelectMenuComponent|discord.RoleSelectMenuComponent|discord.ChannelSelectMenuComponent|discord.MentionableSelectMenuComponent|discord.UserSelectMenuComponent|null { - let result: discord.ButtonComponent|discord.StringSelectMenuComponent|discord.RoleSelectMenuComponent|discord.ChannelSelectMenuComponent|discord.MentionableSelectMenuComponent|discord.UserSelectMenuComponent|null = null - this.message.components.forEach((row) => { - if (row.type != discord.ComponentType.ActionRow) return - row.components.forEach((component) => { - if (type == "button" && component.type == discord.ComponentType.Button && component.customId && ((typeof id == "string") ? component.customId == id : id.test(component.customId))) result = component - else if (type == "string-dropdown" && component.type == discord.ComponentType.StringSelect && component.customId && ((typeof id == "string") ? component.customId == id : id.test(component.customId))) result = component - else if (type == "user-dropdown" && component.type == discord.ComponentType.UserSelect && component.customId && ((typeof id == "string") ? component.customId == id : id.test(component.customId))) result = component - else if (type == "channel-dropdown" && component.type == discord.ComponentType.ChannelSelect && component.customId && ((typeof id == "string") ? component.customId == id : id.test(component.customId))) result = component - else if (type == "role-dropdown" && component.type == discord.ComponentType.RoleSelect && component.customId && ((typeof id == "string") ? component.customId == id : id.test(component.customId))) result = component - else if (type == "mentionable-dropdown" && component.type == discord.ComponentType.MentionableSelect && component.customId && ((typeof id == "string") ? component.customId == id : id.test(component.customId))) result = component - }) - }) - - return result - } - - /**Get the first embed of the original message if it exists. */ - getMessageEmbed(): discord.Embed|null { - return this.message.embeds[0] ?? null - } -} - -/**## ODDropdownResponder `class` - * This is an Open Ticket dropdown responder. - * - * This class manages all workers which are executed when the related dropdown is triggered. - */ -export class ODDropdownResponder extends ODResponderImplementation { - /**Respond to this dropdown */ - async respond(instance:ODDropdownResponderInstance, source:Source, params:Params){ - //wait for workers to finish - await this.workers.executeWorkers(instance,source,params) - } -} - -/**## ODModalResponderManager `class` - * This is an Open Ticket modal responder manager. - * - * It contains all Open Ticket modal responders. These can respond to modal interactions. - * - * Using the Open Ticket responder system has a few advantages compared to vanilla discord.js: - * - plugins can extend/edit replies - * - automatically reply on error - * - independent workers (with priority) - * - fail-safe design using try-catch - * - know where the request came from! - * - And so much more! - */ -export class ODModalResponderManager extends ODManager> { - /**An alias to the Open Ticket client manager. */ - #client: ODClientManager - /**The callback executed when the default workers take too much time to reply. */ - #timeoutErrorCallback: ODResponderTimeoutErrorCallback|null = null - /**The amount of milliseconds before the timeout error callback is executed. */ - #timeoutMs: number|null = null - /**A list of listeners which will listen to the raw interactionCreate event from discord.js */ - #listeners: ((interaction:discord.ModalSubmitInteraction) => void)[] = [] - - constructor(debug:ODDebugger, debugname:string, client:ODClientManager){ - super(debug,debugname) - this.#client = client - - this.#client.client.on("interactionCreate",(interaction) => { - if (!interaction.isModalSubmit()) return - this.#listeners.forEach((cb) => cb(interaction)) - }) - } - - /**Set the message to send when the response times out! */ - setTimeoutErrorCallback(callback:ODResponderTimeoutErrorCallback|null, ms:number|null){ - this.#timeoutErrorCallback = callback - this.#timeoutMs = ms - } - - add(data:ODModalResponder<"modal",any>, overwrite?:boolean){ - const res = super.add(data,overwrite) - - this.#listeners.push((interaction) => { - const newData = this.get(data.id) - if (!newData) return - if ((typeof newData.match == "string") ? interaction.customId == newData.match : newData.match.test(interaction.customId)) newData.respond(new ODModalResponderInstance(interaction,this.#timeoutErrorCallback,this.#timeoutMs),"modal",{}) - }) - - return res - } -} - -/**## ODModalResponderInstanceValues `class` - * This is an Open Ticket modal responder instance values manager. - * - * This class will manage all fields from the modals. - */ -export class ODModalResponderInstanceValues { - /**The interaction to get data from. */ - #interaction: discord.ModalSubmitInteraction - - constructor(interaction:discord.ModalSubmitInteraction){ - this.#interaction = interaction - } - - /**Get the value of a text field. */ - getTextField(name:string,required:true): string - getTextField(name:string,required:false): string|null - getTextField(name:string,required:boolean){ - try { - const data = this.#interaction.fields.getField(name,discord.ComponentType.TextInput) - if (!data && required) throw new ODSystemError("ODModalResponderInstanceValues:getTextField() field not found!") - return (data) ? data.value : null - }catch{ - throw new ODSystemError("ODModalResponderInstanceValues:getTextField() field not found!") - } - } -} - -/**## ODModalResponderInstance `class` - * This is an Open Ticket modal responder instance. - * - * An instance is an active modal interaction. You can reply to the modal using `reply()`. - */ -export class ODModalResponderInstance { - /**The interaction which is the source of this instance. */ - interaction: discord.ModalSubmitInteraction - /**Did a worker already reply to this instance/interaction? */ - didReply: boolean = false - /**The manager for all fields of this modal. */ - values: ODModalResponderInstanceValues - /**The user who triggered this modal. */ - user: discord.User - /**The guild member who triggered this modal. */ - member: discord.GuildMember|null - /**The guild where this modal was triggered. */ - guild: discord.Guild|null - /**The channel where this modal was triggered. */ - channel: discord.TextBasedChannel|null - - constructor(interaction:discord.ModalSubmitInteraction, errorCallback:ODResponderTimeoutErrorCallback|null, timeoutMs:number|null){ - this.interaction = interaction - this.values = new ODModalResponderInstanceValues(interaction) - this.user = interaction.user - this.member = (interaction.member instanceof discord.GuildMember) ? interaction.member : null - this.guild = interaction.guild - this.channel = interaction.channel - - setTimeout(async () => { - if (!this.didReply){ - try { - if (!errorCallback){ - this.reply({id:new ODId("looks-like-we-got-an-error-here"), ephemeral:true, message:{ - content:":x: **Something went wrong while replying to this modal!**" - }}) - }else{ - await errorCallback(this,"modal") - } - - }catch(err){ - process.emit("uncaughtException",err) - } - } - },timeoutMs ?? 2500) - } - - /**Reply to this modal. */ - async reply(msg:ODMessageBuildResult): Promise> { - try{ - const msgFlags: number[] = msg.ephemeral ? [discord.MessageFlags.Ephemeral] : [] - const sent = await this.interaction.followUp(Object.assign(msg.message,{flags:msgFlags})) - this.didReply = true - return {success:true,message:sent} - }catch{ - return {success:false,message:null} - } - } - /**Update the message of this modal. */ - async update(msg:ODMessageBuildResult): Promise> { - try{ - const msgFlags: number[] = msg.ephemeral ? [discord.MessageFlags.Ephemeral] : [] - if (this.interaction.replied || this.interaction.deferred){ - const sent = await this.interaction.editReply(Object.assign(msg.message,{flags:msgFlags})) - this.didReply = true - return {success:true,message:await sent.fetch()} - }else{ - const sent = await this.interaction.reply(Object.assign(msg.message,{flags:msgFlags})) - this.didReply = true - return {success:true,message:await sent.fetch()} - } - }catch{ - return {success:false,message:null} - } - } - /**Defer this modal. */ - async defer(type:"reply"|"update", ephemeral:boolean){ - if (this.interaction.deferred || this.interaction.replied) return false - if (type == "reply"){ - const msgFlags: number[] = ephemeral ? [discord.MessageFlags.Ephemeral] : [] - await this.interaction.deferReply({flags:msgFlags}) - }else{ - await this.interaction.deferUpdate() - } - this.didReply = true - return true - } -} - -/**## ODModalResponder `class` - * This is an Open Ticket modal responder. - * - * This class manages all workers which are executed when the related modal is triggered. - */ -export class ODModalResponder extends ODResponderImplementation { - /**Respond to this modal */ - async respond(instance:ODModalResponderInstance, source:Source, params:Params){ - //wait for workers to finish - await this.workers.executeWorkers(instance,source,params) - } -} - -/**## ODContextMenuResponderManager `class` - * This is an Open Ticket context menu responder manager. - * - * It contains all Open Ticket context menu responders. These can respond to user/message context menu interactions. - * - * Using the Open Ticket responder system has a few advantages compared to vanilla discord.js: - * - plugins can extend/edit replies - * - automatically reply on error - * - independent workers (with priority) - * - fail-safe design using try-catch - * - know where the request came from! - * - And so much more! - */ -export class ODContextMenuResponderManager extends ODManager> { - /**An alias to the Open Ticket client manager. */ - #client: ODClientManager - /**The callback executed when the default workers take too much time to reply. */ - #timeoutErrorCallback: ODResponderTimeoutErrorCallback|null = null - /**The amount of milliseconds before the timeout error callback is executed. */ - #timeoutMs: number|null = null - - constructor(debug:ODDebugger, debugname:string, client:ODClientManager){ - super(debug,debugname) - this.#client = client - } - - /**Set the message to send when the response times out! */ - setTimeoutErrorCallback(callback:ODResponderTimeoutErrorCallback|null, ms:number|null){ - this.#timeoutErrorCallback = callback - this.#timeoutMs = ms - } - - add(data:ODContextMenuResponder<"context-menu",any>, overwrite?:boolean){ - const res = super.add(data,overwrite) - - this.#client.contextMenus.onInteraction(data.match,(interaction,cmd) => { - const newData = this.get(data.id) - if (!newData) return - newData.respond(new ODContextMenuResponderInstance(interaction,cmd,this.#timeoutErrorCallback,this.#timeoutMs),"context-menu",{}) - }) - - return res - } -} - -/**## ODContextMenuResponderInstance `class` - * This is an Open Ticket context menu responder instance. - * - * An instance is an active context menu interaction. You can reply to the context menu using `reply()`. - */ -export class ODContextMenuResponderInstance { - /**The interaction which is the source of this instance. */ - interaction: discord.ContextMenuCommandInteraction - /**Did a worker already reply to this instance/interaction? */ - didReply: boolean = false - /**The context menu wich is the source of this instance. */ - menu:ODContextMenu - /**The user who triggered this context menu. */ - user: discord.User - /**The guild member who triggered this context menu. */ - member: discord.GuildMember|null - /**The guild where this context menu was triggered. */ - guild: discord.Guild|null - /**The channel where this context menu was triggered. */ - channel: discord.TextBasedChannel - /**The target of this context menu (user or message). */ - target: discord.Message|discord.User - - constructor(interaction:discord.ContextMenuCommandInteraction, menu:ODContextMenu, errorCallback:ODResponderTimeoutErrorCallback|null, timeoutMs:number|null){ - if (!interaction.channel) throw new ODSystemError("ODContextMenuResponderInstance: Unable to find interaction channel!") - this.interaction = interaction - this.menu = menu - this.user = interaction.user - this.member = (interaction.member instanceof discord.GuildMember) ? interaction.member : null - this.guild = interaction.guild - this.channel = interaction.channel - if (interaction.isMessageContextMenuCommand()) this.target = interaction.targetMessage - else if (interaction.isUserContextMenuCommand()) this.target = interaction.targetUser - else throw new ODSystemError("ODContextMenuResponderInstance: Invalid context menu type. Should be of the type User/Message!") - - setTimeout(async () => { - if (!this.didReply){ - try { - if (!errorCallback){ - this.reply({id:new ODId("looks-like-we-got-an-error-here"), ephemeral:true, message:{ - content:":x: **Something went wrong while replying to this context menu!**" - }}) - }else{ - await errorCallback(this,"context-menu") - } - - }catch(err){ - process.emit("uncaughtException",err) - } - } - },timeoutMs ?? 2500) - } - - /**Reply to this context menu. */ - async reply(msg:ODMessageBuildResult): Promise> { - try{ - const msgFlags: number[] = msg.ephemeral ? [discord.MessageFlags.Ephemeral] : [] - if (this.interaction.replied || this.interaction.deferred){ - const sent = await this.interaction.editReply(Object.assign(msg.message,{flags:msgFlags})) - this.didReply = true - return {success:true,message:sent} - }else{ - const sent = await this.interaction.reply(Object.assign(msg.message,{flags:msgFlags})) - this.didReply = true - return {success:true,message:await sent.fetch()} - } - }catch{ - return {success:false,message:null} - } - } - /**Update the message of this context menu. */ - async update(msg:ODMessageBuildResult): Promise> { - try{ - const msgFlags: number[] = msg.ephemeral ? [discord.MessageFlags.Ephemeral] : [] - if (this.interaction.replied || this.interaction.deferred){ - const sent = await this.interaction.editReply(Object.assign(msg.message,{flags:msgFlags})) - this.didReply = true - return {success:true,message:await sent.fetch()} - }else throw new ODSystemError("Unable to update context menu interaction!") - }catch{ - return {success:false,message:null} - } - } - /**Defer this context menu. */ - async defer(type:"reply", ephemeral:boolean){ - if (this.interaction.deferred || this.interaction.replied) return false - if (type == "reply"){ - const msgFlags: number[] = ephemeral ? [discord.MessageFlags.Ephemeral] : [] - await this.interaction.deferReply({flags:msgFlags}) - } - this.didReply = true - return true - } - /**Show a modal as reply to this context menu. */ - async modal(modal:ODModalBuildResult){ - if (this.interaction.deferred || this.interaction.replied) return false - await this.interaction.showModal(modal.modal) - this.didReply = true - return true - } -} - -/**## ODContextMenuResponder `class` - * This is an Open Ticket context menu responder. - * - * This class manages all workers which are executed when the related context menu is triggered. - */ -export class ODContextMenuResponder extends ODResponderImplementation { - /**Respond to this button */ - async respond(instance:ODContextMenuResponderInstance, source:Source, params:Params){ - //wait for workers to finish - await this.workers.executeWorkers(instance,source,params) - } -} - -/**## ODAutocompleteResponderManager `class` - * This is an Open Ticket autocomplete responder manager. - * - * It contains all Open Ticket autocomplete responders. These can respond to autocomplete interactions. - * - * Using the Open Ticket responder system has a few advantages compared to vanilla discord.js: - * - plugins can extend/edit replies - * - automatically reply on error - * - independent workers (with priority) - * - fail-safe design using try-catch - * - know where the request came from! - * - And so much more! - */ -export class ODAutocompleteResponderManager extends ODManager> { - /**An alias to the Open Ticket client manager. */ - #client: ODClientManager - /**The callback executed when the default workers take too much time to reply. */ - #timeoutErrorCallback: ODResponderTimeoutErrorCallback|null = null - /**The amount of milliseconds before the timeout error callback is executed. */ - #timeoutMs: number|null = null - - constructor(debug:ODDebugger, debugname:string, client:ODClientManager){ - super(debug,debugname) - this.#client = client - } - - /**Set the message to send when the response times out! */ - setTimeoutErrorCallback(callback:ODResponderTimeoutErrorCallback|null, ms:number|null){ - this.#timeoutErrorCallback = callback - this.#timeoutMs = ms - } - - add(data:ODAutocompleteResponder<"autocomplete",any>, overwrite?:boolean){ - const res = super.add(data,overwrite) - - this.#client.autocompletes.onInteraction(data.cmdMatch,data.match,(interaction) => { - const newData = this.get(data.id) - if (!newData) return - newData.respond(new ODAutocompleteResponderInstance(interaction,this.#timeoutErrorCallback,this.#timeoutMs),"autocomplete",{}) - }) - - return res - } -} - -/**## ODAutocompleteResponderInstance `class` - * This is an Open Ticket autocomplete responder instance. - * - * An instance is an active autocomplete interaction. You can reply to the autocomplete using `reply()`. - */ -export class ODAutocompleteResponderInstance { - /**The interaction which is the source of this instance. */ - interaction: discord.AutocompleteInteraction - /**Did a worker already respond to this instance/interaction? */ - didRespond: boolean = false - /**The user who triggered this autocomplete. */ - user: discord.User - /**The guild member who triggered this autocomplete. */ - member: discord.GuildMember|null - /**The guild where this autocomplete was triggered. */ - guild: discord.Guild|null - /**The channel where this autocomplete was triggered. */ - channel: discord.TextBasedChannel - /**The target slash command option of this autocomplete. */ - target: discord.AutocompleteFocusedOption - - constructor(interaction:discord.AutocompleteInteraction, errorCallback:ODResponderTimeoutErrorCallback|null, timeoutMs:number|null){ - if (!interaction.channel) throw new ODSystemError("ODAutocompleteResponderInstance: Unable to find interaction channel!") - this.interaction = interaction - this.user = interaction.user - this.member = (interaction.member instanceof discord.GuildMember) ? interaction.member : null - this.guild = interaction.guild - this.channel = interaction.channel - this.target = interaction.options.getFocused(true) - - setTimeout(async () => { - if (!this.didRespond){ - process.emit("uncaughtException",new ODSystemError("Autocomplete responder instance failed to respond widthin 2.5sec!")) - } - },timeoutMs ?? 2500) - } - - /**Reply to this autocomplete. */ - async autocomplete(choices:(string|discord.ApplicationCommandOptionChoiceData)[]): Promise<{success:boolean}> { - const newChoices: (discord.ApplicationCommandOptionChoiceData)[] = choices.map((raw) => { - if (typeof raw == "string") return {name:raw,value:raw} - else return raw - }) - - try{ - if (this.interaction.responded){ - return {success:false} - }else{ - await this.interaction.respond(newChoices) - this.didRespond = true - return {success:true} - } - }catch(err){ - process.emit("uncaughtException",err) - return {success:false} - } - } - /**Reply to this autocomplete, but filter choices based on the input of the user. */ - async filteredAutocomplete(choices:(string|discord.ApplicationCommandOptionChoiceData)[]): Promise<{success:boolean}> { - const newChoices: (discord.ApplicationCommandOptionChoiceData)[] = choices.map((raw) => { - if (typeof raw == "string") return {name:raw,value:raw} - else return raw - }) - - const filteredChoices = newChoices.filter((choice) => choice.name.startsWith(this.target.value) || choice.value.toString().startsWith(this.target.value)).slice(0,25) - return await this.autocomplete(filteredChoices) - } -} - -/**## ODAutocompleteResponder `class` - * This is an Open Ticket autocomplete responder. - * - * This class manages all workers which are executed when the related autocomplete is triggered. - */ -export class ODAutocompleteResponder extends ODResponderImplementation { - /**The slash command of the autocomplete should match the following regex. */ - cmdMatch: string|RegExp - - constructor(id:ODValidId,cmdMatch:string|RegExp,match:string|RegExp,callback?:ODWorkerCallback,priority?:number,callbackId?:ODValidId){ - super(id,match,callback,priority,callbackId) - this.cmdMatch = cmdMatch - } - - /**Respond to this autocomplete interaction. */ - async respond(instance:ODAutocompleteResponderInstance, source:Source, params:Params){ - //wait for workers to finish - await this.workers.executeWorkers(instance,source,params) - } -} \ No newline at end of file diff --git a/src/core/api/modules/session.ts b/src/core/api/modules/session.ts deleted file mode 100644 index 5be116b..0000000 --- a/src/core/api/modules/session.ts +++ /dev/null @@ -1,155 +0,0 @@ -/////////////////////////////////////// -//SESSION MODULE -/////////////////////////////////////// -import { ODId, ODManager, ODManagerData, ODValidId } from "./base" -import { ODDebugger } from "./console" -import * as crypto from "crypto" - -/**## ODSessionManager `class` - * This is an Open Ticket session manager. - * - * It contains all sessions in Open Ticket. Sessions are a sort of temporary storage which will be cleared when the bot stops. - * Data in sessions have a randomly generated key which will always be unique. - * - * Visit the `ODSession` class for more info - */ -export class ODSessionManager extends ODManager { - constructor(debug:ODDebugger){ - super(debug,"session") - } -} - -/**## ODSessionInstance `interface` - * This interface represents a single session instance. It contains an id, data & some dates. - */ -export interface ODSessionInstance { - /**The id of this session instance. */ - id:string, - /**The creation date of this session instance. */ - creation:number, - /**The custom amount of minutes before this session expires. */ - timeout:number|null, - /**This is the data from this session instance */ - data:any -} - -/**## ODSessionTimeoutCallback `type` - * This is the callback used for session timeout listeners. - */ -export type ODSessionTimeoutCallback = (id:string, timeout:"default"|"custom", data:any, creation:Date) => void - -/**## ODSession `class` - * This is an Open Ticket session. - * - * It can be used to create 100% unique id's for usage in the bot. An id can also store additional data which isn't saved to the filesystem. - * You can almost compare it to the PHP session system. - */ -export class ODSession extends ODManagerData { - /**The history of previously generated instance ids. Used to reduce the risk of generating the same id twice. */ - #idHistory: string[] = [] - /**The max length of the instance id history. */ - #maxIdHistoryLength: number = 500 - /**An array of all the currently active session instances. */ - sessions: ODSessionInstance[] = [] - /**The default amount of minutes before a session automatically stops. */ - timeoutMinutes: number = 30 - /**The id of the auto-timeout session checker interval */ - #intervalId: NodeJS.Timeout - /**Listeners for when a session times-out. */ - #timeoutListeners: ODSessionTimeoutCallback[] = [] - - constructor(id:ODValidId, intervalSeconds?:number){ - super(id) - - //create the auto-timeout session checker - this.#intervalId = setInterval(() => { - const deletableSessions: {instance:ODSessionInstance,reason:"default"|"custom"}[] = [] - - //collect all deletable sessions - this.sessions.forEach((session) => { - if (session.timeout && (new Date().getTime() - session.creation) > session.timeout*60000){ - //stop session => custom timeout - deletableSessions.push({instance:session,reason:"custom"}) - }else if (!session.timeout && (new Date().getTime() - session.creation) > this.timeoutMinutes*60000){ - //stop session => default timeout - deletableSessions.push({instance:session,reason:"default"}) - } - }) - - //permanently delete sessions - deletableSessions.forEach((session) => { - const index = this.sessions.findIndex((s) => s.id === session.instance.id) - this.sessions.splice(index,1) - - //emit timeout listeners - this.#timeoutListeners.forEach((cb) => cb(session.instance.id,session.reason,session.instance.data,new Date(session.instance.creation))) - }) - - },((intervalSeconds) ? (intervalSeconds * 1000) : 60000)) - } - - /**Create a unique hex id of 8 characters and add it to the instance id history */ - #createUniqueId(): string { - const hex = crypto.randomBytes(4).toString("hex") - if (this.#idHistory.includes(hex)){ - return this.#createUniqueId() - }else{ - this.#idHistory.push(hex) - if (this.#idHistory.length > this.#maxIdHistoryLength) this.#idHistory.shift() - return hex - } - } - /**Stop the global interval that automatically deletes timed-out sessions. (This action can't be reverted!) */ - stopAutoTimeout(){ - clearInterval(this.#intervalId) - } - - /**Start a session instance with data. Returns the unique id required to access the session. */ - start(data?:any): string { - const id = this.#createUniqueId() - this.sessions.push({ - id,data, - creation:new Date().getTime(), - timeout:null - }) - return id - } - /**Get the data of a session instance. Returns `null` when not found. */ - data(id:string): any|null { - const session = this.sessions.find((session) => session.id === id) - if (!session) return null - return session.data - } - /**Stop & delete a session instance. Returns `true` when sucessful. */ - stop(id:string): boolean { - const index = this.sessions.findIndex((session) => session.id === id) - if (index < 0) return false - this.sessions.splice(index,1) - return true - } - /**Update the data of a session instance. Returns `true` when sucessful. */ - update(id:string, data:any): boolean { - const session = this.sessions.find((session) => session.id === id) - if (!session) return false - session.data = data - return true - } - /**Change the global or session timeout minutes. Returns `true` when sucessful. */ - setTimeout(min:number, id?:string): boolean { - if (!id){ - //change global timeout minutes - this.timeoutMinutes = min - return true - }else{ - //change session instance timeout minutes - const session = this.sessions.find((session) => session.id === id) - if (!session) return false - session.timeout = min - return true - } - } - /**Listen for a session timeout (default or custom) */ - onTimeout(callback:ODSessionTimeoutCallback){ - this.#timeoutListeners.push(callback) - } -} \ No newline at end of file diff --git a/src/core/api/modules/startscreen.ts b/src/core/api/modules/startscreen.ts deleted file mode 100644 index 9aab04b..0000000 --- a/src/core/api/modules/startscreen.ts +++ /dev/null @@ -1,320 +0,0 @@ -/////////////////////////////////////// -//STARTSCREEN MODULE -/////////////////////////////////////// -import { ODId, ODManager, ODManagerData, ODValidId } from "./base" -import { ODDebugger, ODError, ODLiveStatusManager } from "./console" -import { ODFlag } from "./flag" -import { ODPlugin, ODUnknownCrashedPlugin } from "./plugin" -import ansis from "ansis" - -/**## ODStartScreenComponentRenderCallback `type` - * This is the render function of a startscreen component. It also sends the location of where the component is rendered. - */ -export type ODStartScreenComponentRenderCallback = (location:number) => string|Promise - -/**## ODStartScreenManager `class` - * This is an Open Ticket startscreen manager. - * - * This class is responsible for managing & rendering the startscreen of the bot. - * The startscreen is the part you see when the bot has started up successfully. (e.g. the Open Ticket logo, logs, livestatus, flags, ...) - */ -export class ODStartScreenManager extends ODManager { - /**Alias to the Open Ticket debugger. */ - #debug: ODDebugger - /**Alias to the livestatus manager. */ - livestatus: ODLiveStatusManager - - constructor(debug:ODDebugger,livestatus:ODLiveStatusManager){ - super(debug,"startscreen component") - this.#debug = debug - this.livestatus = livestatus - } - - /**Get all components in sorted order. */ - getSortedComponents(priority:"ascending"|"descending"){ - return this.getAll().sort((a,b) => { - if (priority == "ascending") return a.priority-b.priority - else return b.priority-a.priority - }) - } - /**Render all startscreen components in priority order. */ - async renderAllComponents(){ - const components = this.getSortedComponents("descending") - - let location = 0 - for (const component of components){ - try { - const renderedText = await component.renderAll(location) - console.log(renderedText) - this.#debug.console.debugfile.writeText("[STARTSCREEN] Component: \""+component.id+"\"\n"+ansis.strip(renderedText)) - }catch(e){ - this.#debug.console.log("Unable to render \""+component.id+"\" startscreen component!","error") - this.#debug.console.debugfile.writeErrorMessage(new ODError(e,"uncaughtException")) - } - location++ - } - } -} - -/**## ODStartScreenComponent `class` - * This is an Open Ticket startscreen component. - * - * This component can be rendered to the start screen of the bot. - * An optional priority can be specified to choose the location of the component. - * - * It's recommended to use pre-built components except if you really need a custom one. - */ -export class ODStartScreenComponent extends ODManagerData { - /**The priority of this component. */ - priority: number - /**An optional render function which will be inserted before the default renderer. */ - renderBefore: ODStartScreenComponentRenderCallback|null = null - /**The render function which will render the contents of this component. */ - render: ODStartScreenComponentRenderCallback - /**An optional render function which will be inserted behind the default renderer. */ - renderAfter: ODStartScreenComponentRenderCallback|null = null - - constructor(id:ODValidId, priority:number, render:ODStartScreenComponentRenderCallback){ - super(id) - this.priority = priority - this.render = render - } - - /**Render this component and combine it with the `renderBefore` & `renderAfter` contents. */ - async renderAll(location:number){ - const textBefore = (this.renderBefore) ? await this.renderBefore(location) : "" - const text = await this.render(location) - const textAfter = (this.renderAfter) ? await this.renderAfter(location) : "" - return (textBefore ? textBefore+"\n" : "")+text+(textAfter ? "\n"+textAfter : "") - } -} - -/**## ODStartScreenProperty `type` - * This interface contains properties used in a few default templates of the startscreen component. - */ -export interface ODStartScreenProperty { - /**The key or name of this property. */ - key:string, - /**The value or contents of this property. */ - value:string -} - -/**## ODStartScreenLogoComponent `class` - * This is an Open Ticket startscreen logo component. - * - * This component will render an ASCII art logo (from an array) to the startscreen. Every property in the array is another row. - * An optional priority can be specified to choose the location of the component. - */ -export class ODStartScreenLogoComponent extends ODStartScreenComponent { - /**The ASCII logo contents. */ - logo: string[] - /**When enabled, the component will add a new line above the logo. */ - topPadding: boolean - /**When enabled, the component will add a new line below the logo. */ - bottomPadding: boolean - /**The color of the logo in hex format. */ - logoHexColor: string - - constructor(id:ODValidId, priority:number, logo:string[], topPadding?:boolean, bottomPadding?:boolean, logoHexColor?:string){ - super(id,priority,() => { - const renderedTop = (this.topPadding ? "\n" : "") - const renderedLogo = this.logo.join("\n") - const renderedBottom = (this.bottomPadding ? "\n" : "") - return ansis.hex(this.logoHexColor)(renderedTop+renderedLogo+renderedBottom) - }) - this.logo = logo - this.topPadding = topPadding ?? false - this.bottomPadding = bottomPadding ?? false - this.logoHexColor = logoHexColor ?? "#f8ba00" - } -} - -/**## ODStartScreenHeaderAlignmentSettings `type` - * This interface contains all settings used in the startscreen header component. - */ -export interface ODStartScreenHeaderAlignmentSettings { - /**The alignment settings for this header. */ - align:"center"|"left"|"right", - /**The width or component to use when calculating center & right alignment. */ - width:number|ODStartScreenComponent -} - -/**## ODStartScreenHeaderComponent `class` - * This is an Open Ticket startscreen header component. - * - * This component will render a header to the startscreen. Properties can be aligned left, right or centered. - * An optional priority can be specified to choose the location of the component. - */ -export class ODStartScreenHeaderComponent extends ODStartScreenComponent { - /**All properties of this header component. */ - properties: ODStartScreenProperty[] - /**The spacer used between properties. */ - spacer: string - /**The alignment settings of this header component. */ - align: ODStartScreenHeaderAlignmentSettings|null - - constructor(id:ODValidId, priority:number, properties:ODStartScreenProperty[], spacer?:string, align?:ODStartScreenHeaderAlignmentSettings){ - super(id,priority,async () => { - const renderedProperties = ansis.bold(this.properties.map((prop) => prop.key+": "+prop.value).join(this.spacer)) - if (!this.align || this.align.align == "left"){ - return renderedProperties - }else if (this.align.align == "right"){ - const width = (typeof this.align.width == "number") ? this.align.width : ( - ansis.strip(await this.align.width.renderAll(0)).split("\n").map((row) => row.length).reduce((prev,curr) => { - if (prev < curr) return curr - else return prev - },0) - ) - const offset = width - ansis.strip(renderedProperties).length - if (offset < 0) return renderedProperties - else{ - return (" ".repeat(offset) + renderedProperties) - } - }else if (this.align.align == "center"){ - const width = (typeof this.align.width == "number") ? this.align.width : ( - ansis.strip(await this.align.width.renderAll(0)).split("\n").map((row) => row.length).reduce((prev,curr) => { - if (prev < curr) return curr - else return prev - }) - ) - const offset = Math.round((width - ansis.strip(renderedProperties).length)/2) - if (offset < 0) return renderedProperties - else{ - return (" ".repeat(offset) + renderedProperties) - } - } - return renderedProperties - }) - this.properties = properties - this.spacer = spacer ?? " - " - this.align = align ?? null - } -} - -/**## ODStartScreenCategoryComponent `class` - * This is an Open Ticket startscreen category component. - * - * This component will render a category to the startscreen. This will only render the category name. You'll need to provide your own renderer for the contents. - * An optional priority can be specified to choose the location of the component. - */ -export class ODStartScreenCategoryComponent extends ODStartScreenComponent { - /**The name of this category. */ - name: string - /**When enabled, this category will still be rendered when the contents are empty. (enabled by default) */ - renderIfEmpty: boolean - - constructor(id:ODValidId, priority:number, name:string, render:ODStartScreenComponentRenderCallback, renderIfEmpty?:boolean){ - super(id,priority,async (location) => { - const contents = await render(location) - if (contents != "" || this.renderIfEmpty){ - return ansis.bold.underline("\n"+name.toUpperCase()+(contents != "" ? ":\n" : ":")) + contents - }else return "" - }) - this.name = name - this.renderIfEmpty = renderIfEmpty ?? true - } -} - -/**## ODStartScreenPropertiesCategoryComponent `class` - * This is an Open Ticket startscreen properties category component. - * - * This component will render a properties category to the startscreen. This will list the properties in the category. - * An optional priority can be specified to choose the location of the component. - */ -export class ODStartScreenPropertiesCategoryComponent extends ODStartScreenCategoryComponent { - /**The properties of this category component. */ - properties: ODStartScreenProperty[] - /**The hex color for the key/name of all the properties. */ - propertyHexColor: string - - constructor(id:ODValidId, priority:number, name:string, properties:ODStartScreenProperty[], propertyHexColor?:string, renderIfEmpty?:boolean){ - super(id,priority,name,() => { - return this.properties.map((prop) => ansis.hex(this.propertyHexColor)(prop.key+": ")+prop.value).join("\n") - },renderIfEmpty) - - this.properties = properties - this.propertyHexColor = propertyHexColor ?? "#f8ba00" - } -} - -/**## ODStartScreenFlagsCategoryComponent `class` - * This is an Open Ticket startscreen flags category component. - * - * This component will render a flags category to the startscreen. This will list the enabled flags in the category. - * An optional priority can be specified to choose the location of the component. - */ -export class ODStartScreenFlagsCategoryComponent extends ODStartScreenCategoryComponent { - /**A list of all flags to render. */ - flags: ODFlag[] - - constructor(id:ODValidId, priority:number, flags:ODFlag[]){ - super(id,priority,"flags",() => { - return this.flags.filter((flag) => (flag.value == true)).map((flag) => ansis.blue("["+flag.name+"] "+flag.description)).join("\n") - },false) - this.flags = flags - } -} - -/**## ODStartScreenPluginsCategoryComponent `class` - * This is an Open Ticket startscreen plugins category component. - * - * This component will render a plugins category to the startscreen. This will list the enabled, disabled & crashed plugins in the category. - * An optional priority can be specified to choose the location of the component. - */ -export class ODStartScreenPluginsCategoryComponent extends ODStartScreenCategoryComponent { - /**A list of all plugins to render. */ - plugins: ODPlugin[] - /**A list of all crashed plugins to render. */ - unknownCrashedPlugins: ODUnknownCrashedPlugin[] - - constructor(id:ODValidId, priority:number, plugins:ODPlugin[], unknownCrashedPlugins:ODUnknownCrashedPlugin[]){ - super(id,priority,"plugins",() => { - const disabledPlugins = this.plugins.filter((plugin) => !plugin.enabled) - - const renderedActivePlugins = this.plugins.filter((plugin) => plugin.enabled && plugin.executed).sort((a,b) => b.priority-a.priority).map((plugin) => ansis.green("✅ ["+plugin.name+"] "+plugin.details.shortDescription)) - const renderedCrashedPlugins = this.plugins.filter((plugin) => plugin.enabled && plugin.crashed).sort((a,b) => b.priority-a.priority).map((plugin) => ansis.red("❌ ["+plugin.name+"] "+plugin.details.shortDescription)) - const renderedDisabledPlugins = (disabledPlugins.length > 4) ? [ansis.gray("💤 (+"+disabledPlugins.length+" disabled plugins)")] : disabledPlugins.sort((a,b) => b.priority-a.priority).map((plugin) => ansis.gray("💤 ["+plugin.name+"] "+plugin.details.shortDescription)) - const renderedUnknownPlugins = unknownCrashedPlugins.map((plugin) => ansis.red("❌ ["+plugin.name+"] "+plugin.description)) - - return [ - ...renderedActivePlugins, - ...renderedDisabledPlugins, - ...renderedCrashedPlugins, - ...renderedUnknownPlugins - ].join("\n") - },false) - this.plugins = plugins - this.unknownCrashedPlugins = unknownCrashedPlugins - } -} - -/**## ODStartScreenLiveStatusCategoryComponent `class` - * This is an Open Ticket startscreen livestatus category component. - * - * This component will render a livestatus category to the startscreen. This will list the livestatus messages in the category. - * An optional priority can be specified to choose the location of the component. - */ -export class ODStartScreenLiveStatusCategoryComponent extends ODStartScreenCategoryComponent { - /**A reference to the Open Ticket livestatus manager. */ - livestatus: ODLiveStatusManager - - constructor(id:ODValidId, priority:number, livestatus:ODLiveStatusManager){ - super(id,priority,"livestatus",async () => { - const messages = await this.livestatus.getAllMessages() - return this.livestatus.renderer.render(messages) - },false) - this.livestatus = livestatus - } -} - -/**## ODStartScreenLogsCategoryComponent `class` - * This is an Open Ticket startscreen logs category component. - * - * This component will render a logs category to the startscreen. This will only render the logs category name. - * An optional priority can be specified to choose the location of the component. - */ -export class ODStartScreenLogCategoryComponent extends ODStartScreenCategoryComponent { - constructor(id:ODValidId, priority:number){ - super(id,priority,"logs",() => "",true) - } -} \ No newline at end of file diff --git a/src/core/api/modules/stat.ts b/src/core/api/modules/stat.ts deleted file mode 100644 index dccc1e6..0000000 --- a/src/core/api/modules/stat.ts +++ /dev/null @@ -1,313 +0,0 @@ -/////////////////////////////////////// -//STAT MODULE -/////////////////////////////////////// -import { ODId, ODManager, ODManagerData, ODSystemError, ODValidId } from "./base" -import { ODDebugger } from "./console" -import { ODDatabase, ODJsonDatabaseStructure } from "./database" -import * as discord from "discord.js" - -/**## ODValidStatValue `type` - * These are the only allowed types for a stat value to improve compatibility with different database systems. - */ -export type ODValidStatValue = string|number|boolean - -/**## ODStatsManagerInitCallback `type` - * This callback can be used to execute something when the stats have been initiated. - * - * By default this is used to clear stats from users that left the server or tickets which don't exist anymore. - */ -export type ODStatsManagerInitCallback = (database:ODJsonDatabaseStructure, deletables:ODJsonDatabaseStructure) => void|Promise - -/**## ODStatScopeSetMode `type` - * This type contains all valid methods for changing the value of a stat. - */ -export type ODStatScopeSetMode = "set"|"increase"|"decrease" - -/**## ODStatsManager `class` - * This is an Open Ticket stats manager. - * - * This class is responsible for managing all stats of the bot. - * Stats are categorized in "scopes" which can be accessed in this manager. - * - * Stats can be accessed in the individual scopes. - */ -export class ODStatsManager extends ODManager { - /**Alias to Open Ticket debugger. */ - #debug: ODDebugger - /**Alias to Open Ticket stats database. */ - database: ODDatabase|null = null - /**All the listeners for the init event. */ - #initListeners: ODStatsManagerInitCallback[] = [] - - constructor(debug:ODDebugger){ - super(debug,"stat scope") - this.#debug = debug - } - - /**Select the database to use to read/write all stats from/to. */ - useDatabase(database:ODDatabase){ - this.database = database - } - add(data:ODStatScope, overwrite?:boolean): boolean { - data.useDebug(this.#debug,"stat") - if (this.database) data.useDatabase(this.database) - return super.add(data,overwrite) - } - /**Init all stats and run `onInit()` listeners. */ - async init(){ - if (!this.database) throw new ODSystemError("Unable to initialize stats scopes due to missing database!") - - //get all valid categories - const validCategories: string[] = [] - for (const scope of this.getAll()){ - validCategories.push(...scope.init()) - } - - //filter out the deletable stats - const deletableStats: ODJsonDatabaseStructure = [] - const data = await this.database.getAll() - data.forEach((data) => { - if (!validCategories.includes(data.category)) deletableStats.push(data) - }) - - //do additional deletion - for (const cb of this.#initListeners){ - await cb(data,deletableStats) - } - - //delete all deletable stats - for (const data of deletableStats){ - if (!this.database) return - await this.database.delete(data.category,data.key) - } - } - /**Reset all stats. (clears the entire database) */ - async reset(){ - if (!this.database) return - const data = await this.database.getAll() - for (const d of data){ - if (!this.database) return - await this.database.delete(d.category,d.key) - } - } - /**Run a function when the stats are initialized. This can be used to clear stats from users that left the server or tickets which don't exist anymore. */ - onInit(callback:ODStatsManagerInitCallback){ - this.#initListeners.push(callback) - } -} - -/**## ODStatScope `class` - * This is an Open Ticket stat scope. - * - * A scope can contain multiple stats. Every scope is seperated from other scopes. - * Here, you can read & write the values of all stats. - * - * The built-in Open Ticket scopes are: `global`, `user`, `ticket` - */ -export class ODStatScope extends ODManager { - /**The id of this statistics scope. */ - id: ODId - /**Is this stat scope already initialized? */ - ready: boolean = false - /**Alias to Open Ticket stats database. */ - database: ODDatabase|null = null - /**The name of this scope (used in embed title) */ - name:string - - constructor(id:ODValidId, name:string){ - super() - this.id = new ODId(id) - this.name = name - } - - /**Select the database to use to read/write all stats from/to. (Automatically assigned when used in `ODStatsManager`) */ - useDatabase(database:ODDatabase){ - this.database = database - } - /**Get the value of a statistic. The `scopeId` is the unique id of the user, channel, role, etc that the stats are related to. */ - async getStat(id:ODValidId, scopeId:string): Promise { - if (!this.database) return null - const newId = new ODId(id) - const data = await this.database.get(this.id.value+"_"+newId.value,scopeId) - - if (typeof data == "undefined"){ - //set stats to default value & return - return this.resetStat(id,scopeId) - }else if (typeof data == "string" || typeof data == "boolean" || typeof data == "number"){ - //return value received from database - return data - } - //return null on error - return null - } - /**Get the value of a statistic for all `scopeId`'s. The `scopeId` is the unique id of the user, channel, role, etc that the stats are related to. */ - async getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> { - if (!this.database) return [] - const newId = new ODId(id) - const data = await this.database.getCategory(this.id.value+"_"+newId.value) ?? [] - const output: {id:string,value:ODValidStatValue}[] = [] - - for (const stat of data){ - if (typeof stat.value == "string" || typeof stat.value == "boolean" || typeof stat.value == "number"){ - //return value received from database - output.push({id:stat.key,value:stat.value}) - } - } - - //return null on error - return output - } - /**Set, increase or decrease the value of a statistic. The `scopeId` is the unique id of the user, channel, role, etc that the stats are related to. */ - async setStat(id:ODValidId, scopeId:string, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise { - if (!this.database) return false - const stat = this.get(id) - if (!stat) return false - if (mode == "set" || typeof value != "number"){ - await this.database.set(this.id.value+"_"+stat.id.value,scopeId,value) - }else if (mode == "increase"){ - const currentValue = await this.getStat(id,scopeId) - if (typeof currentValue != "number") await this.database.set(this.id.value+"_"+stat.id.value,scopeId,0+value) - else await this.database.set(this.id.value+"_"+stat.id.value,scopeId,currentValue+value) - }else if (mode == "decrease"){ - const currentValue = await this.getStat(id,scopeId) - if (typeof currentValue != "number") await this.database.set(this.id.value+"_"+stat.id.value,scopeId,0-value) - else await this.database.set(this.id.value+"_"+stat.id.value,scopeId,currentValue-value) - } - return true - } - /**Reset the value of a statistic to the initial value. The `scopeId` is the unique id of the user, channel, role, etc that the stats are related to. */ - async resetStat(id:ODValidId, scopeId:string): Promise { - if (!this.database) return null - const stat = this.get(id) - if (!stat) return null - if (stat.value != null) await this.database.set(this.id.value+"_"+stat.id.value,scopeId,stat.value) - return stat.value - } - /**Initialize this stat scope & return a list of all statistic ids in the following format: `_` */ - init(): string[] { - //get all valid stats categories - this.ready = true - return this.getAll().map((stat) => this.id.value+"_"+stat.id.value) - } - /**Render all stats in this scope for usage in a discord message/embed. */ - async render(scopeId:string, guild:discord.Guild, channel:discord.TextBasedChannel, user:discord.User): Promise { - //sort from high priority to low - const derefArray = [...this.getAll()] - derefArray.sort((a,b) => { - return b.priority-a.priority - }) - const result: string[] = [] - - for (const stat of derefArray){ - try { - if (stat instanceof ODDynamicStat){ - //dynamic render (without value) - result.push(await stat.render("",scopeId,guild,channel,user)) - }else{ - //normal render (with value) - const value = await this.getStat(stat.id,scopeId) - if (value != null) result.push(await stat.render(value,scopeId,guild,channel,user)) - } - - }catch(err){ - process.emit("uncaughtException",err) - } - } - - return result.filter((stat) => stat !== "").join("\n") - } -} - -/**## ODStatGlobalScope `class` - * This is an Open Ticket stat global scope. - * - * A scope can contain multiple stats. Every scope is seperated from other scopes. - * Here, you can read & write the values of all stats. - * - * This scope is made specifically for the global stats of Open Ticket. - */ -export class ODStatGlobalScope extends ODStatScope { - getStat(id:ODValidId): Promise { - return super.getStat(id,"GLOBAL") - } - getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> { - return super.getAllStats(id) - } - setStat(id:ODValidId, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise { - return super.setStat(id,"GLOBAL",value,mode) - } - resetStat(id:ODValidId): Promise { - return super.resetStat(id,"GLOBAL") - } - render(scopeId:"GLOBAL", guild:discord.Guild, channel:discord.TextBasedChannel, user: discord.User): Promise { - return super.render("GLOBAL",guild,channel,user) - } -} - -/**## ODStatRenderer `type` - * This callback will render a single statistic for a discord embed/message. - */ -export type ODStatRenderer = (value:ODValidStatValue, scopeId:string, guild:discord.Guild, channel:discord.TextBasedChannel, user:discord.User) => string|Promise - -/**## ODStat `class` - * This is an Open Ticket statistic. - * - * This single statistic doesn't do anything except defining the rules of this statistic. - * Use it in a stats scope to register a new statistic. A statistic can also include a priority to choose the render priority. - * - * It's recommended to use the `ODBasicStat` & `ODDynamicStat` classes instead of this one! - */ -export class ODStat extends ODManagerData { - /**The priority of this statistic. */ - priority: number - /**The render function of this statistic. */ - render: ODStatRenderer - /**The value of this statistic. */ - value: ODValidStatValue|null - - constructor(id:ODValidId, priority:number, render:ODStatRenderer, value?:ODValidStatValue){ - super(id) - this.priority = priority - this.render = render - this.value = value ?? null - } -} - -/**## ODBasicStat `class` - * This is an Open Ticket basic statistic. - * - * This single statistic will store a number, boolean or string in the database. - * Use it to create a simple statistic for any stats scope. - */ -export class ODBasicStat extends ODStat { - /**The name of this stat. Rendered in discord embeds/messages. */ - name: string - - constructor(id:ODValidId, priority:number, name:string, value:ODValidStatValue){ - super(id,priority,(value) => { - return ""+name+": `"+value.toString()+"`" - },value) - this.name = name - } -} - -/**## ODDynamicStatRenderer `type` - * This callback will render a single dynamic statistic for a discord embed/message. - */ -export type ODDynamicStatRenderer = (scopeId:string, guild:discord.Guild, channel:discord.TextBasedChannel, user:discord.User) => string|Promise - -/**## ODDynamicStat `class` - * This is an Open Ticket dynamic statistic. - * - * A dynamic statistic does not store anything in the database! Instead, it will execute a function to return a custom result. - * This can be used to show statistics which are not stored in the database. - * - * This is used in Open Ticket for the live ticket status, participants & system status. - */ -export class ODDynamicStat extends ODStat { - constructor(id:ODValidId, priority:number, render:ODDynamicStatRenderer){ - super(id,priority,(value,scopeId,guild,channel,user) => { - return render(scopeId,guild,channel,user) - }) - } -} \ No newline at end of file diff --git a/src/core/api/modules/verifybar.ts b/src/core/api/modules/verifybar.ts deleted file mode 100644 index 2b74277..0000000 --- a/src/core/api/modules/verifybar.ts +++ /dev/null @@ -1,61 +0,0 @@ -/////////////////////////////////////// -//VERIFYBAR MODULE -/////////////////////////////////////// -import { ODId, ODManager, ODManagerData, ODValidId } from "./base" -import { ODMessage } from "./builder" -import { ODDebugger } from "./console" -import { ODButtonResponderInstance } from "./responder" -import * as discord from "discord.js" -import { ODWorkerManager } from "./worker" - -/**## ODVerifyBar `class` - * This is an Open Ticket verifybar. - * - * It is contains 2 sets of workers and a lot of utilities for the (✅ ❌) verifybars in the bot. - * - * It doesn't contain the code which activates or spawns the verifybars! - */ -export class ODVerifyBar extends ODManagerData { - /**All workers that will run when the verifybar is accepted. */ - success: ODWorkerManager|null}> - /**All workers that will run when the verifybar is stopped. */ - failure: ODWorkerManager|null}> - /**The message that will be built wen activating this verifybar. */ - message: ODMessage<"verifybar",{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:ODVerifyBar,originalMessage:discord.Message}> - /**When disabled, it will skip the verifybar and instantly fire the `success` workers. */ - enabled: boolean - - constructor(id:ODValidId, message:ODMessage<"verifybar",{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,originalMessage:discord.Message}>, enabled?:boolean){ - super(id) - this.success = new ODWorkerManager("descending") - this.failure = new ODWorkerManager("descending") - this.message = message - this.enabled = enabled ?? true - } - - /**Build the message and reply to a button with this verifybar. */ - async activate(responder:ODButtonResponderInstance){ - if (this.enabled){ - //show verifybar - const {guild,channel,user,message} = responder - await responder.update(await this.message.build("verifybar",{guild,channel,user,verifybar:this,originalMessage:message})) - }else{ - //instant success - if (this.success) await this.success.executeWorkers(responder,"verifybar",{data:null,verifybarMessage:null}) - } - } -} - -/**## ODVerifyBarManager `class` - * This is an Open Ticket verifybar manager. - * - * It contains all (✅ ❌) verifybars in the bot. - * The `ODVerifyBar` classes contain `ODWorkerManager`'s that will be fired when the continue/stop buttons are pressed. - * - * It doesn't contain the code which activates the verifybars! This should be implemented by your own. - */ -export class ODVerifyBarManager extends ODManager { - constructor(debug:ODDebugger){ - super(debug,"verifybar") - } -} \ No newline at end of file diff --git a/src/core/api/modules/worker.ts b/src/core/api/modules/worker.ts deleted file mode 100644 index 566603d..0000000 --- a/src/core/api/modules/worker.ts +++ /dev/null @@ -1,93 +0,0 @@ -/////////////////////////////////////// -//WORKER MODULE -/////////////////////////////////////// -import { ODId, ODManager, ODManagerData, ODValidId } from "./base" - -/**## ODWorkerCallback `type` - * This is the callback used in `ODWorker`! - */ -export type ODWorkerCallback = (instance:Instance, params:Params, source:Source, cancel:() => void) => void|Promise - -/**## ODWorker `class` - * This is an Open Ticket worker. - * - * You can compare it with a normal javascript callback, but slightly more advanced! - * - * - It has an `id` for identification of the function - * - A `priority` to know when to execute this callback (related to others) - * - It knows who called this callback (`source`) - * - And much more! - */ -export class ODWorker extends ODManagerData { - /**The priority of this worker */ - priority: number - /**The main callback of this worker */ - callback: ODWorkerCallback - - constructor(id:ODValidId, priority:number, callback:ODWorkerCallback){ - super(id) - this.priority = priority - this.callback = callback - } -} - -/**## ODWorker `class` - * This is an Open Ticket worker manager. - * - * It manages & executes `ODWorker`'s in the correct order. - * - * You can register a custom worker in this class to create a message or button. - */ -export class ODWorkerManager extends ODManager> { - /**The order of execution for workers inside this manager. */ - #priorityOrder: "ascending"|"descending" - /**The backup worker will be executed when one of the workers fails or cancels execution. */ - backupWorker: ODWorker<{reason:"error"|"cancel"},Source,Params>|null = null - - constructor(priorityOrder:"ascending"|"descending"){ - super() - this.#priorityOrder = priorityOrder - } - - /**Get all workers in sorted order. */ - getSortedWorkers(priority:"ascending"|"descending"){ - const derefArray = [...this.getAll()] - - return derefArray.sort((a,b) => { - if (priority == "ascending") return a.priority-b.priority - else return b.priority-a.priority - }) - } - /**Execute all workers on an instance using the given source & parameters. */ - async executeWorkers(instance:Instance, source:Source, params:Params){ - const derefParams = {...params} - const workers = this.getSortedWorkers(this.#priorityOrder) - let didCancel = false - let didCrash = false - - for (const worker of workers){ - if (didCancel) break - try { - await worker.callback(instance,derefParams,source,() => { - didCancel = true - }) - }catch(err){ - process.emit("uncaughtException",err) - didCrash = true - } - } - if (didCancel && this.backupWorker){ - try{ - await this.backupWorker.callback({reason:"cancel"},derefParams,source,() => {}) - }catch(err){ - process.emit("uncaughtException",err) - } - }else if (didCrash && this.backupWorker){ - try{ - await this.backupWorker.callback({reason:"error"},derefParams,source,() => {}) - }catch(err){ - process.emit("uncaughtException",err) - } - } - } -} \ No newline at end of file diff --git a/src/core/api/openticket/blacklist.ts b/src/core/api/openticket/blacklist.ts index d7dedcd..ea349b3 100644 --- a/src/core/api/openticket/blacklist.ts +++ b/src/core/api/openticket/blacklist.ts @@ -1,8 +1,7 @@ /////////////////////////////////////// //OPENTICKET BLACKLIST MODULE /////////////////////////////////////// -import { ODManager, ODManagerData, ODValidId } from "../modules/base" -import { ODDebugger } from "../modules/console" +import * as api from "@open-discord-bots/framework/api" /**## ODBlacklist `class` * This is an Open Ticket blacklisted user. @@ -11,11 +10,11 @@ import { ODDebugger } from "../modules/console" * * Create this class & add it to the `ODBlacklistManager` to blacklist someone! */ -export class ODBlacklist extends ODManagerData { +export class ODBlacklist extends api.ODManagerData { /**The reason why this user got blacklisted. (optional) */ #reason: string|null - constructor(id:ODValidId,reason:string|null){ + constructor(id:api.ODValidId,reason:string|null){ super(id) this.#reason = reason } @@ -37,8 +36,8 @@ export class ODBlacklist extends ODManagerData { * * All `ODBlacklist`'s added, removed & edited in this list will be synced automatically with the database. */ -export class ODBlacklistManager extends ODManager { - constructor(debug:ODDebugger){ +export class ODBlacklistManager extends api.ODManager { + constructor(debug:api.ODDebugger){ super(debug,"blacklist") } } \ No newline at end of file diff --git a/src/core/api/openticket/option.ts b/src/core/api/openticket/option.ts index 69d2be9..6ca7dcb 100644 --- a/src/core/api/openticket/option.ts +++ b/src/core/api/openticket/option.ts @@ -1,10 +1,8 @@ /////////////////////////////////////// //OPENTICKET OPTION MODULE /////////////////////////////////////// -import { ODDatabase } from "../modules/database" +import * as api from "@open-discord-bots/framework/api" import { ODJsonConfig_DefaultOptionEmbedSettingsType, ODJsonConfig_DefaultOptionPingSettingsType } from "../defaults/config" -import { ODId, ODManager, ODValidJsonType, ODValidId, ODVersion, ODValidButtonColor, ODManagerData, ODSystemError } from "../modules/base" -import { ODDebugger } from "../modules/console" import * as discord from "discord.js" import * as crypto from "crypto" import { ODRoleUpdateMode } from "./role" @@ -16,13 +14,13 @@ import { ODRoleUpdateMode } from "./role" * * All option types including: tickets, websites & reaction roles are stored here. */ -export class ODOptionManager extends ODManager { +export class ODOptionManager extends api.ODManager { /**A reference to the Open Ticket debugger. */ - #debug: ODDebugger + #debug: api.ODDebugger /**The option suffix manager used to generate channel suffixes for ticket names. */ suffix: ODOptionSuffixManager - constructor(debug:ODDebugger){ + constructor(debug:api.ODDebugger){ super(debug,"option") this.#debug = debug this.suffix = new ODOptionSuffixManager(debug) @@ -41,7 +39,7 @@ export interface ODOptionDataJson { /**The id of this property. */ id:string, /**The value of this property. */ - value:ODValidJsonType + value:api.ODValidJsonType } /**## ODOptionDataJson `interface` @@ -65,15 +63,15 @@ export interface ODOptionJson { * * It's recommended to use `ODTicketOption`, `ODWebsiteOption` or `ODRoleOption` instead! */ -export class ODOption extends ODManager> { +export class ODOption extends api.ODManager> { /**The id of this option. (from the config) */ - id:ODId + id:api.ODId /**The type of this option. (e.g. `opendiscord:ticket`, `opendiscord:website`, `opendiscord:role`) */ type: string - constructor(id:ODValidId, type:string, data:ODOptionData[]){ + constructor(id:api.ODValidId, type:string, data:ODOptionData[]){ super() - this.id = new ODId(id) + this.id = new api.ODId(id) this.type = type data.forEach((data) => { this.add(data) @@ -81,7 +79,7 @@ export class ODOption extends ODManager> { } /**Convert this option to a JSON object for storing this option in the database. */ - toJson(version:ODVersion): ODOptionJson { + toJson(version:api.ODVersion): ODOptionJson { const data = this.getAll().map((data) => { return { id:data.id.toString(), @@ -110,11 +108,11 @@ export class ODOption extends ODManager> { * * When this property is edited, the database will be updated automatically. */ -export class ODOptionData extends ODManagerData { +export class ODOptionData extends api.ODManagerData { /**The value of this property. */ #value: DataType - constructor(id:ODValidId, value:DataType){ + constructor(id:api.ODValidId, value:DataType){ super(id) this.#value = value } @@ -143,7 +141,7 @@ export interface ODTicketOptionIds { "opendiscord:button-emoji":ODOptionData, "opendiscord:button-label":ODOptionData, - "opendiscord:button-color":ODOptionData, + "opendiscord:button-color":ODOptionData, "opendiscord:admins":ODOptionData, "opendiscord:admins-readonly":ODOptionData, @@ -198,28 +196,28 @@ export interface ODTicketOptionIds { export class ODTicketOption extends ODOption { type: "opendiscord:ticket" = "opendiscord:ticket" - constructor(id:ODValidId, data:ODOptionData[]){ + constructor(id:api.ODValidId, data:ODOptionData[]){ super(id,"opendiscord:ticket",data) } get(id:OptionId): ODTicketOptionIds[OptionId] - get(id:ODValidId): ODOptionData|null + get(id:api.ODValidId): ODOptionData|null - get(id:ODValidId): ODOptionData|null { + get(id:api.ODValidId): ODOptionData|null { return super.get(id) } remove(id:OptionId): ODTicketOptionIds[OptionId] - remove(id:ODValidId): ODOptionData|null + remove(id:api.ODValidId): ODOptionData|null - remove(id:ODValidId): ODOptionData|null { + remove(id:api.ODValidId): ODOptionData|null { return super.remove(id) } exists(id:keyof ODTicketOptionIds): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } @@ -252,28 +250,28 @@ export interface ODWebsiteOptionIds { export class ODWebsiteOption extends ODOption { type: "opendiscord:website" = "opendiscord:website" - constructor(id:ODValidId, data:ODOptionData[]){ + constructor(id:api.ODValidId, data:ODOptionData[]){ super(id,"opendiscord:website",data) } get(id:OptionId): ODWebsiteOptionIds[OptionId] - get(id:ODValidId): ODOptionData|null + get(id:api.ODValidId): ODOptionData|null - get(id:ODValidId): ODOptionData|null { + get(id:api.ODValidId): ODOptionData|null { return super.get(id) } remove(id:OptionId): ODWebsiteOptionIds[OptionId] - remove(id:ODValidId): ODOptionData|null + remove(id:api.ODValidId): ODOptionData|null - remove(id:ODValidId): ODOptionData|null { + remove(id:api.ODValidId): ODOptionData|null { return super.remove(id) } exists(id:keyof ODWebsiteOptionIds): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } @@ -292,7 +290,7 @@ export interface ODRoleOptionIds { "opendiscord:button-emoji":ODOptionData, "opendiscord:button-label":ODOptionData, - "opendiscord:button-color":ODOptionData, + "opendiscord:button-color":ODOptionData, "opendiscord:roles":ODOptionData, "opendiscord:mode":ODOptionData, @@ -310,28 +308,28 @@ export interface ODRoleOptionIds { export class ODRoleOption extends ODOption { type: "opendiscord:role" = "opendiscord:role" - constructor(id:ODValidId, data:ODOptionData[]){ + constructor(id:api.ODValidId, data:ODOptionData[]){ super(id,"opendiscord:role",data) } get(id:OptionId): ODRoleOptionIds[OptionId] - get(id:ODValidId): ODOptionData|null + get(id:api.ODValidId): ODOptionData|null - get(id:ODValidId): ODOptionData|null { + get(id:api.ODValidId): ODOptionData|null { return super.get(id) } remove(id:OptionId): ODRoleOptionIds[OptionId] - remove(id:ODValidId): ODOptionData|null + remove(id:api.ODValidId): ODOptionData|null - remove(id:ODValidId): ODOptionData|null { + remove(id:api.ODValidId): ODOptionData|null { return super.remove(id) } exists(id:keyof ODRoleOptionIds): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } @@ -347,8 +345,8 @@ export class ODRoleOption extends ODOption { * * All ticket options should have a corresponding option suffix class. */ -export class ODOptionSuffixManager extends ODManager { - constructor(debug:ODDebugger){ +export class ODOptionSuffixManager extends api.ODManager { + constructor(debug:api.ODDebugger){ super(debug,"ticket suffix") } @@ -381,18 +379,18 @@ export class ODOptionSuffixManager extends ODManager { * * Use `getSuffix()` to get the new suffix! */ -export class ODOptionSuffix extends ODManagerData { +export class ODOptionSuffix extends api.ODManagerData { /**The option of this suffix. */ option: ODTicketOption - constructor(id:ODValidId, option:ODTicketOption){ + constructor(id:api.ODValidId, option:ODTicketOption){ super(id) this.option = option } /**Get the suffix for a new ticket. */ async getSuffix(member:discord.GuildMember): Promise { - throw new ODSystemError("Tried to use an unimplemented ODOptionSuffix!") + throw new api.ODSystemError("Tried to use an unimplemented ODOptionSuffix!") } } @@ -444,9 +442,9 @@ export class ODOptionUserIdSuffix extends ODOptionSuffix { */ export class ODOptionCounterDynamicSuffix extends ODOptionSuffix { /**The database where the value of this counter is stored. */ - database: ODDatabase + database: api.ODDatabase - constructor(id:ODValidId, option:ODTicketOption, database:ODDatabase){ + constructor(id:api.ODValidId, option:ODTicketOption, database:api.ODDatabase){ super(id,option) this.database = database this.#init() @@ -474,9 +472,9 @@ export class ODOptionCounterDynamicSuffix extends ODOptionSuffix { */ export class ODOptionCounterFixedSuffix extends ODOptionSuffix { /**The database where the value of this counter is stored. */ - database: ODDatabase + database: api.ODDatabase - constructor(id:ODValidId, option:ODTicketOption, database:ODDatabase){ + constructor(id:api.ODValidId, option:ODTicketOption, database:api.ODDatabase){ super(id,option) this.database = database this.#init() @@ -508,9 +506,9 @@ export class ODOptionCounterFixedSuffix extends ODOptionSuffix { */ export class ODOptionRandomNumberSuffix extends ODOptionSuffix { /**The database where previous random numbers are stored. */ - database: ODDatabase + database: api.ODDatabase - constructor(id:ODValidId, option:ODTicketOption, database:ODDatabase){ + constructor(id:api.ODValidId, option:ODTicketOption, database:api.ODDatabase){ super(id,option) this.database = database this.#init() @@ -551,9 +549,9 @@ export class ODOptionRandomNumberSuffix extends ODOptionSuffix { */ export class ODOptionRandomHexSuffix extends ODOptionSuffix { /**The database where previous random hexes are stored. */ - database: ODDatabase + database: api.ODDatabase - constructor(id:ODValidId, option:ODTicketOption, database:ODDatabase){ + constructor(id:api.ODValidId, option:ODTicketOption, database:api.ODDatabase){ super(id,option) this.database = database this.#init() diff --git a/src/core/api/openticket/panel.ts b/src/core/api/openticket/panel.ts index 633a0a8..68bb888 100644 --- a/src/core/api/openticket/panel.ts +++ b/src/core/api/openticket/panel.ts @@ -1,9 +1,8 @@ /////////////////////////////////////// //OPENTICKET PANEL MODULE /////////////////////////////////////// +import * as api from "@open-discord-bots/framework/api" import { ODJsonConfig_DefaultPanelEmbedSettingsType } from "../defaults/config" -import { ODId, ODManager, ODValidJsonType, ODValidId, ODVersion, ODValidButtonColor, ODManagerData } from "../modules/base" -import { ODDebugger } from "../modules/console" /**## ODPanelManager `class` * This is an Open Ticket panel manager. @@ -12,11 +11,11 @@ import { ODDebugger } from "../modules/console" * * Panels are not stored in the database and will be parsed from the config every startup. */ -export class ODPanelManager extends ODManager { +export class ODPanelManager extends api.ODManager { /**A reference to the Open Ticket debugger. */ - #debug: ODDebugger + #debug: api.ODDebugger - constructor(debug:ODDebugger){ + constructor(debug:api.ODDebugger){ super(debug,"option") this.#debug = debug } @@ -34,7 +33,7 @@ export interface ODPanelDataJson { /**The id of this property. */ id:string, /**The value of this property. */ - value:ODValidJsonType + value:api.ODValidJsonType } /**## ODPanelDataJson `interface` @@ -78,20 +77,20 @@ export interface ODPanelIds { * * This class contains all data related to this panel (parsed from the config). */ -export class ODPanel extends ODManager> { +export class ODPanel extends api.ODManager> { /**The id of this panel. (from the config) */ - id:ODId + id:api.ODId - constructor(id:ODValidId, data:ODPanelData[]){ + constructor(id:api.ODValidId, data:ODPanelData[]){ super() - this.id = new ODId(id) + this.id = new api.ODId(id) data.forEach((data) => { this.add(data) }) } /**Convert this panel to a JSON object for storing this panel in the database. */ - toJson(version:ODVersion): ODPanelJson { + toJson(version:api.ODVersion): ODPanelJson { const data = this.getAll().map((data) => { return { id:data.id.toString(), @@ -112,23 +111,23 @@ export class ODPanel extends ODManager> { } get(id:PanelId): ODPanelIds[PanelId] - get(id:ODValidId): ODPanelData|null + get(id:api.ODValidId): ODPanelData|null - get(id:ODValidId): ODPanelData|null { + get(id:api.ODValidId): ODPanelData|null { return super.get(id) } remove(id:PanelId): ODPanelIds[PanelId] - remove(id:ODValidId): ODPanelData|null + remove(id:api.ODValidId): ODPanelData|null - remove(id:ODValidId): ODPanelData|null { + remove(id:api.ODValidId): ODPanelData|null { return super.remove(id) } exists(id:keyof ODPanelIds): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -140,11 +139,11 @@ export class ODPanel extends ODManager> { * * When this property is edited, the database will be updated automatically. */ -export class ODPanelData extends ODManagerData { +export class ODPanelData extends api.ODManagerData { /**The value of this property. */ #value: DataType - constructor(id:ODValidId, value:DataType){ + constructor(id:api.ODValidId, value:DataType){ super(id) this.#value = value } diff --git a/src/core/api/openticket/priority.ts b/src/core/api/openticket/priority.ts index 90ea38a..c69fd15 100644 --- a/src/core/api/openticket/priority.ts +++ b/src/core/api/openticket/priority.ts @@ -1,8 +1,7 @@ /////////////////////////////////////// //OPENTICKET PRIORITY MODULE /////////////////////////////////////// -import { ODId, ODManager, ODValidJsonType, ODValidId, ODVersion, ODManagerData } from "../modules/base" -import { ODDebugger } from "../modules/console" +import * as api from "@open-discord-bots/framework/api" import * as discord from "discord.js" /**## ODPriorityManager `class` @@ -12,11 +11,11 @@ import * as discord from "discord.js" * * Priorities levels can be changed/updated/translated by plugins to allow for more customisability. */ -export class ODPriorityManager extends ODManager { +export class ODPriorityManager extends api.ODManager { /**A reference to the Open Ticket debugger. */ - #debug: ODDebugger + #debug: api.ODDebugger - constructor(debug:ODDebugger){ + constructor(debug:api.ODDebugger){ super(debug,"priority") this.#debug = debug } @@ -53,23 +52,23 @@ export interface ODPriorityManagerIds { */ export class ODPriorityManager_Default extends ODPriorityManager { get(id:PriorityId): ODPriorityManagerIds[PriorityId] - get(id:ODValidId): ODPriorityLevel|null + get(id:api.ODValidId): ODPriorityLevel|null - get(id:ODValidId): ODPriorityLevel|null { + get(id:api.ODValidId): ODPriorityLevel|null { return super.get(id) } remove(id:PriorityId): ODPriorityManagerIds[PriorityId] - remove(id:ODValidId): ODPriorityLevel|null + remove(id:api.ODValidId): ODPriorityLevel|null - remove(id:ODValidId): ODPriorityLevel|null { + remove(id:api.ODValidId): ODPriorityLevel|null { return super.remove(id) } exists(id:keyof ODPriorityManagerIds): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -83,7 +82,7 @@ export class ODPriorityManager_Default extends ODPriorityManager { * * #### 🚨 Negative priorities are treated as `disabled/no-priority`! */ -export class ODPriorityLevel extends ODManagerData { +export class ODPriorityLevel extends api.ODManagerData { /**The priority level itself. A negative number (e.g. `-1`) is treated as `disabled/no-priority`. */ priority:number /**The raw name of the level (used in text/slash command inputs). */ @@ -95,7 +94,7 @@ export class ODPriorityLevel extends ODManagerData { /**The emoji added to the channel name when the level is applied to a ticket. */ channelEmoji:string|null - constructor(id:ODValidId,priority:number,rawName:string,displayName:string,displayEmoji:string|null,channelEmoji:string|null){ + constructor(id:api.ODValidId,priority:number,rawName:string,displayName:string,displayEmoji:string|null,channelEmoji:string|null){ super(id) this.priority = priority this.rawName = rawName diff --git a/src/core/api/openticket/question.ts b/src/core/api/openticket/question.ts index 5f19a4b..20ff80b 100644 --- a/src/core/api/openticket/question.ts +++ b/src/core/api/openticket/question.ts @@ -1,8 +1,7 @@ /////////////////////////////////////// //OPENTICKET OPTION MODULE /////////////////////////////////////// -import { ODId, ODManager, ODValidJsonType, ODValidId, ODVersion, ODManagerData } from "../modules/base" -import { ODDebugger } from "../modules/console" +import * as api from "@open-discord-bots/framework/api" /**## ODQuestionManager `class` * This is an Open Ticket question manager. @@ -11,11 +10,11 @@ import { ODDebugger } from "../modules/console" * * Questions are not stored in the database and will be parsed from the config every startup. */ -export class ODQuestionManager extends ODManager { +export class ODQuestionManager extends api.ODManager { /**A reference to the Open Ticket debugger. */ - #debug: ODDebugger + #debug: api.ODDebugger - constructor(debug:ODDebugger){ + constructor(debug:api.ODDebugger){ super(debug,"question") this.#debug = debug } @@ -33,7 +32,7 @@ export interface ODQuestionDataJson { /**The id of this property. */ id:string, /**The value of this property. */ - value:ODValidJsonType + value:api.ODValidJsonType } /**## ODQuestionDataJson `interface` @@ -57,15 +56,15 @@ export interface ODQuestionJson { * * Use `ODShortQuestion` or `ODParagraphQuestion` instead! */ -export class ODQuestion extends ODManager> { +export class ODQuestion extends api.ODManager> { /**The id of this question. (from the config) */ - id:ODId + id:api.ODId /**The type of this question (e.g. `opendiscord:short` or `opendiscord:paragraph`) */ type: string - constructor(id:ODValidId, type:string, data:ODQuestionData[]){ + constructor(id:api.ODValidId, type:string, data:ODQuestionData[]){ super() - this.id = new ODId(id) + this.id = new api.ODId(id) this.type = type data.forEach((data) => { this.add(data) @@ -73,7 +72,7 @@ export class ODQuestion extends ODManager> { } /**Convert this question to a JSON object for storing this question in the database. */ - toJson(version:ODVersion): ODQuestionJson { + toJson(version:api.ODVersion): ODQuestionJson { const data = this.getAll().map((data) => { return { id:data.id.toString(), @@ -102,11 +101,11 @@ export class ODQuestion extends ODManager> { * * When this property is edited, the database will be updated automatically. */ -export class ODQuestionData extends ODManagerData { +export class ODQuestionData extends api.ODManagerData { /**The value of this property. */ #value: DataType - constructor(id:ODValidId, value:DataType){ + constructor(id:api.ODValidId, value:DataType){ super(id) this.#value = value } @@ -149,28 +148,28 @@ export interface ODShortQuestionIds { export class ODShortQuestion extends ODQuestion { type: "opendiscord:short" = "opendiscord:short" - constructor(id:ODValidId, data:ODQuestionData[]){ + constructor(id:api.ODValidId, data:ODQuestionData[]){ super(id,"opendiscord:short",data) } get(id:QuestionId): ODShortQuestionIds[QuestionId] - get(id:ODValidId): ODQuestionData|null + get(id:api.ODValidId): ODQuestionData|null - get(id:ODValidId): ODQuestionData|null { + get(id:api.ODValidId): ODQuestionData|null { return super.get(id) } remove(id:QuestionId): ODShortQuestionIds[QuestionId] - remove(id:ODValidId): ODQuestionData|null + remove(id:api.ODValidId): ODQuestionData|null - remove(id:ODValidId): ODQuestionData|null { + remove(id:api.ODValidId): ODQuestionData|null { return super.remove(id) } exists(id:keyof ODShortQuestionIds): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } @@ -203,28 +202,28 @@ export interface ODParagraphQuestionIds { export class ODParagraphQuestion extends ODQuestion { type: "opendiscord:paragraph" = "opendiscord:paragraph" - constructor(id:ODValidId, data:ODQuestionData[]){ + constructor(id:api.ODValidId, data:ODQuestionData[]){ super(id,"opendiscord:paragraph",data) } get(id:QuestionId): ODParagraphQuestionIds[QuestionId] - get(id:ODValidId): ODQuestionData|null + get(id:api.ODValidId): ODQuestionData|null - get(id:ODValidId): ODQuestionData|null { + get(id:api.ODValidId): ODQuestionData|null { return super.get(id) } remove(id:QuestionId): ODParagraphQuestionIds[QuestionId] - remove(id:ODValidId): ODQuestionData|null + remove(id:api.ODValidId): ODQuestionData|null - remove(id:ODValidId): ODQuestionData|null { + remove(id:api.ODValidId): ODQuestionData|null { return super.remove(id) } exists(id:keyof ODParagraphQuestionIds): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } diff --git a/src/core/api/openticket/role.ts b/src/core/api/openticket/role.ts index b61c462..4c5ffd7 100644 --- a/src/core/api/openticket/role.ts +++ b/src/core/api/openticket/role.ts @@ -1,8 +1,7 @@ /////////////////////////////////////// //OPENTICKET ROLE MODULE /////////////////////////////////////// -import { ODId, ODManager, ODValidJsonType, ODValidId, ODVersion, ODManagerData } from "../modules/base" -import { ODDebugger } from "../modules/console" +import * as api from "@open-discord-bots/framework/api" import * as discord from "discord.js" /**## ODRoleManager `class` @@ -12,11 +11,11 @@ import * as discord from "discord.js" * * Roles are not stored in the database and will be parsed from the config every startup. */ -export class ODRoleManager extends ODManager { +export class ODRoleManager extends api.ODManager { /**A reference to the Open Ticket debugger. */ - #debug: ODDebugger + #debug: api.ODDebugger - constructor(debug:ODDebugger){ + constructor(debug:api.ODDebugger){ super(debug,"role") this.#debug = debug } @@ -34,7 +33,7 @@ export interface ODRoleDataJson { /**The id of this property. */ id:string, /**The value of this property. */ - value:ODValidJsonType + value:api.ODValidJsonType } /**## ODRoleJson `interface` @@ -67,20 +66,20 @@ export interface ODRoleIds { * * These properties will be used to handle reaction role options. */ -export class ODRole extends ODManager> { +export class ODRole extends api.ODManager> { /**The id of this role. (from the config) */ - id:ODId + id:api.ODId - constructor(id:ODValidId, data:ODRoleData[]){ + constructor(id:api.ODValidId, data:ODRoleData[]){ super() - this.id = new ODId(id) + this.id = new api.ODId(id) data.forEach((data) => { this.add(data) }) } /**Convert this role to a JSON object for storing this role in the database. */ - toJson(version:ODVersion): ODRoleJson { + toJson(version:api.ODVersion): ODRoleJson { const data = this.getAll().map((data) => { return { id:data.id.toString(), @@ -101,23 +100,23 @@ export class ODRole extends ODManager> { } get(id:OptionId): ODRoleIds[OptionId] - get(id:ODValidId): ODRoleData|null + get(id:api.ODValidId): ODRoleData|null - get(id:ODValidId): ODRoleData|null { + get(id:api.ODValidId): ODRoleData|null { return super.get(id) } remove(id:OptionId): ODRoleIds[OptionId] - remove(id:ODValidId): ODRoleData|null + remove(id:api.ODValidId): ODRoleData|null - remove(id:ODValidId): ODRoleData|null { + remove(id:api.ODValidId): ODRoleData|null { return super.remove(id) } exists(id:keyof ODRoleIds): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -129,11 +128,11 @@ export class ODRole extends ODManager> { * * When this property is edited, the database will be updated automatically. */ -export class ODRoleData extends ODManagerData { +export class ODRoleData extends api.ODManagerData { /**The value of this property. */ #value: DataType - constructor(id:ODValidId, value:DataType){ + constructor(id:api.ODValidId, value:DataType){ super(id) this.#value = value } diff --git a/src/core/api/openticket/ticket.ts b/src/core/api/openticket/ticket.ts index 2d8203a..57de978 100644 --- a/src/core/api/openticket/ticket.ts +++ b/src/core/api/openticket/ticket.ts @@ -1,8 +1,7 @@ /////////////////////////////////////// //OPENTICKET TICKET MODULE /////////////////////////////////////// -import { ODId, ODManager, ODValidJsonType, ODValidId, ODVersion, ODManagerData } from "../modules/base" -import { ODDebugger } from "../modules/console" +import * as api from "@open-discord-bots/framework/api" import { ODClientManager_Default } from "../defaults/client" import { ODTicketOption } from "./option" import * as discord from "discord.js" @@ -14,15 +13,15 @@ import * as discord from "discord.js" * * All tickets which are added, removed or modified in this manager will be updated automatically in the database. */ -export class ODTicketManager extends ODManager { +export class ODTicketManager extends api.ODManager { /**A reference to the main server of the bot */ #guild: discord.Guild|null = null /**A reference to the Open Ticket client manager. */ #client: ODClientManager_Default /**A reference to the Open Ticket debugger. */ - #debug: ODDebugger + #debug: api.ODDebugger - constructor(debug:ODDebugger, client:ODClientManager_Default){ + constructor(debug:api.ODDebugger, client:ODClientManager_Default){ super(debug,"ticket") this.#debug = debug this.#client = client @@ -132,7 +131,7 @@ export interface ODTicketDataJson { /**The id of this property. */ id:string, /**The value of this property. */ - value:ODValidJsonType + value:api.ODValidJsonType } /**## ODTicketDataJson `interface` @@ -200,15 +199,15 @@ export interface ODTicketIds { * * These properties contain the current state of the ticket & are used by actions like claiming, pinning, closing, ... */ -export class ODTicket extends ODManager> { +export class ODTicket extends api.ODManager> { /**The id of this ticket. (discord channel id) */ - id:ODId + id:api.ODId /**The option related to this ticket. */ #option: ODTicketOption - constructor(id:ODValidId, option:ODTicketOption, data:ODTicketData[]){ + constructor(id:api.ODValidId, option:ODTicketOption, data:ODTicketData[]){ super() - this.id = new ODId(id) + this.id = new api.ODId(id) this.#option = option data.forEach((data) => { this.add(data) @@ -225,7 +224,7 @@ export class ODTicket extends ODManager> { } /**Convert this ticket to a JSON object for storing this ticket in the database. */ - toJson(version:ODVersion): ODTicketJson { + toJson(version:api.ODVersion): ODTicketJson { const data = this.getAll().map((data) => { return { id:data.id.toString(), @@ -247,23 +246,23 @@ export class ODTicket extends ODManager> { } get(id:OptionId): ODTicketIds[OptionId] - get(id:ODValidId): ODTicketData|null + get(id:api.ODValidId): ODTicketData|null - get(id:ODValidId): ODTicketData|null { + get(id:api.ODValidId): ODTicketData|null { return super.get(id) } remove(id:OptionId): ODTicketIds[OptionId] - remove(id:ODValidId): ODTicketData|null + remove(id:api.ODValidId): ODTicketData|null - remove(id:ODValidId): ODTicketData|null { + remove(id:api.ODValidId): ODTicketData|null { return super.remove(id) } exists(id:keyof ODTicketIds): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -275,11 +274,11 @@ export class ODTicket extends ODManager> { * * When this property is edited, the database will be updated automatically. */ -export class ODTicketData extends ODManagerData { +export class ODTicketData extends api.ODManagerData { /**The value of this property. */ #value: DataType - constructor(id:ODValidId, value:DataType){ + constructor(id:api.ODValidId, value:DataType){ super(id) this.#value = value } diff --git a/src/core/api/openticket/transcript.ts b/src/core/api/openticket/transcript.ts index 9234ec9..b99690a 100644 --- a/src/core/api/openticket/transcript.ts +++ b/src/core/api/openticket/transcript.ts @@ -1,13 +1,10 @@ /////////////////////////////////////// //OPENTICKET TRANSCRIPT MODULE /////////////////////////////////////// -import { ODId, ODManager, ODValidJsonType, ODValidId, ODManagerData, ODValidButtonColor } from "../modules/base" -import { ODDebugger } from "../modules/console" +import * as api from "@open-discord-bots/framework/api" +import { ODPermissionManager_Default } from "../defaults/permission" import { ODTicket, ODTicketManager } from "./ticket" -import { ODMessageBuildResult } from "../modules/builder" -import { ODClientManager } from "../modules/client" import * as discord from "discord.js" -import { ODPermissionManager_Default } from "#opendiscord-types" /**## ODTranscriptManager `class` * This is an Open Ticket transcript manager. @@ -16,13 +13,13 @@ import { ODPermissionManager_Default } from "#opendiscord-types" * * The 2 default built-in transcript generators are: `opendiscord:html-compiler` & `opendiscord:text-compiler`. */ -export class ODTranscriptManager extends ODManager> { +export class ODTranscriptManager extends api.ODManager> { /**The manager responsible for collecting all messages in a channel. */ collector: ODTranscriptCollector /**Alias for the client manager. */ - #client: ODClientManager + #client: api.ODClientManager - constructor(debug:ODDebugger, tickets:ODTicketManager, client:ODClientManager, permissions:ODPermissionManager_Default){ + constructor(debug:api.ODDebugger, tickets:ODTicketManager, client:api.ODClientManager, permissions:ODPermissionManager_Default){ super(debug,"transcript compiler") this.#client = client this.collector = new ODTranscriptCollector(tickets,client,permissions) @@ -53,7 +50,7 @@ export interface ODTranscriptCompilerInitResult { /**When not successfull, what was the reason? This will also be shown to the user. */ errorReason:string|null, /**An optional message which will be sent while the transcript is being generated. */ - pendingMessage:ODMessageBuildResult|null, + pendingMessage:api.ODMessageBuildResult|null, /**An optional object containing data from the init() function which can be used in the compiler. */ initData:InitData, } @@ -83,15 +80,15 @@ export interface ODTranscriptCompilerCompileResult { */ export interface ODTranscriptCompilerReadyResult { /**The message to be sent in the specified channel in the server. */ - channelMessage?:ODMessageBuildResult, + channelMessage?:api.ODMessageBuildResult, /**The message to be sent to the DM of the ticket creator. */ - creatorDmMessage?:ODMessageBuildResult, + creatorDmMessage?:api.ODMessageBuildResult, /**The message to be sent to the DM of all participants. */ - participantDmMessage?:ODMessageBuildResult, + participantDmMessage?:api.ODMessageBuildResult, /**The message to be sent to the DM of all admins who actively participated in the ticket. */ - activeAdminDmMessage?:ODMessageBuildResult, + activeAdminDmMessage?:api.ODMessageBuildResult, /**The message to be sent to the DM of all admins who were assigned to this ticket. */ - everyAdminDmMessage?:ODMessageBuildResult + everyAdminDmMessage?:api.ODMessageBuildResult } /**## ODTranscriptCompiler `class` @@ -101,7 +98,7 @@ export interface ODTranscriptCompilerReadyResult { * * These functions should be defined when creating this compiler. Existing compilers already exist for html & text transcripts. */ -export class ODTranscriptCompiler extends ODManagerData { +export class ODTranscriptCompiler extends api.ODManagerData { /*Initialise the system every time a transcript is created. Returns optional "pending" message to display while the transcript is being compiled. */ init: ODTranscriptCompilerInitFunction|null /*Compile or create the transcript. Returns data to give to the ready() function for message creation. */ @@ -109,7 +106,7 @@ export class ODTranscriptCompiler|null - constructor(id:ODValidId, init?:ODTranscriptCompilerInitFunction, compile?:ODTranscriptCompilerCompileFunction, ready?:ODTranscriptCompilerReadyFunction|null){ + constructor(id:api.ODValidId, init?:ODTranscriptCompilerInitFunction, compile?:ODTranscriptCompilerCompileFunction, ready?:ODTranscriptCompilerReadyFunction|null){ super(id) this.init = init ?? null this.compile = compile ?? null @@ -134,23 +131,23 @@ export interface ODTranscriptCompilerIds { */ export class ODTranscriptManager_Default extends ODTranscriptManager { get(id:CompilerId): ODTranscriptCompilerIds[CompilerId] - get(id:ODValidId): ODTranscriptCompiler|null + get(id:api.ODValidId): ODTranscriptCompiler|null - get(id:ODValidId): ODTranscriptCompiler|null { + get(id:api.ODValidId): ODTranscriptCompiler|null { return super.get(id) } remove(id:CompilerId): ODTranscriptCompilerIds[CompilerId] - remove(id:ODValidId): ODTranscriptCompiler|null + remove(id:api.ODValidId): ODTranscriptCompiler|null - remove(id:ODValidId): ODTranscriptCompiler|null { + remove(id:api.ODValidId): ODTranscriptCompiler|null { return super.remove(id) } exists(id:keyof ODTranscriptCompilerIds): boolean - exists(id:ODValidId): boolean + exists(id:api.ODValidId): boolean - exists(id:ODValidId): boolean { + exists(id:api.ODValidId): boolean { return super.exists(id) } } @@ -166,11 +163,11 @@ export class ODTranscriptCollector { /**Alias for the ticket manager. */ #tickets: ODTicketManager /**Alias for the client manager. */ - #client: ODClientManager + #client: api.ODClientManager /**Alias for the permissions manager. */ #permissions: ODPermissionManager_Default - constructor(tickets:ODTicketManager,client:ODClientManager,permissions:ODPermissionManager_Default){ + constructor(tickets:ODTicketManager,client:api.ODClientManager,permissions:ODPermissionManager_Default){ this.#tickets = tickets this.#client = client this.#permissions = permissions @@ -420,7 +417,7 @@ export class ODTranscriptCollector { } } /**Create the `ODValidButtonColor` from the discord.js button style. */ - #handleButtonComponentStyle(style:discord.ButtonStyle): ODValidButtonColor { + #handleButtonComponentStyle(style:discord.ButtonStyle): api.ODValidButtonColor { if (style == discord.ButtonStyle.Danger) return "red" else if (style == discord.ButtonStyle.Success) return "green" else if (style == discord.ButtonStyle.Primary) return "blue" @@ -622,7 +619,7 @@ export interface ODTranscriptButtonComponentData extends ODTranscriptComponentDa /**The emoji of this button. */ emoji: ODTranscriptEmojiData|null, /**The color of this button. */ - color: ODValidButtonColor, + color: api.ODValidButtonColor, /**Is this button a url or button? */ mode: "url"|"button", /**The url of this button. */ diff --git a/src/core/cli/editConfig.ts b/src/core/cli/editConfig.ts index 9eebf29..9e78b53 100644 --- a/src/core/cli/editConfig.ts +++ b/src/core/cli/editConfig.ts @@ -1,4 +1,4 @@ -import {opendiscord, api, utilities} from "../../index" +import {opendiscord, utilities, api } from "../../index" import {Terminal, terminal} from "terminal-kit" import ansis from "ansis" import {renderHeader} from "./cli" diff --git a/src/core/cli/quickSetup.ts b/src/core/cli/quickSetup.ts index 22a44d5..3d4b9e0 100644 --- a/src/core/cli/quickSetup.ts +++ b/src/core/cli/quickSetup.ts @@ -384,14 +384,14 @@ async function renderQuickSetupLanguage(backFn:() => api.ODPromiseVoid){ style:terminal.white, hintStyle:terminal.gray, cancelable:true, - autoComplete:opendiscord.defaults.getDefault("languageList"), + autoComplete:opendiscord.sharedFuses.getFuse("languageList"), autoCompleteHint:true, autoCompleteMenu:autoCompleteMenuOpts as Terminal.Autocompletion }).promise if (typeof answer != "string") return await backFn() else{ - if (!opendiscord.defaults.getDefault("languageList").includes(answer.toLowerCase())){ + if (!opendiscord.sharedFuses.getFuse("languageList").includes(answer.toLowerCase())){ terminal.red.bold("\n\n❌ Please insert an available language from the list. (TIP: use tab for autocomplete)\n") await utilities.timer(2000) return await renderQuickSetupLanguage(backFn) diff --git a/src/core/startup/dump.ts b/src/core/startup/dump.ts deleted file mode 100644 index 5ec486b..0000000 --- a/src/core/startup/dump.ts +++ /dev/null @@ -1,49 +0,0 @@ -import {opendiscord, api, utilities} from "../../index" -import * as discord from "discord.js" -import * as fs from "fs" - - -/** WHAT IS THIS?? - * This is the '!OPENTICKET:dump' command. - * It's a utility command which can only be used by the creator of Open Ticket or the owner of the bot. - * This command will send the `otdebug.txt` file in DM. It's not dangerous as the `otdebug.txt` file doesn't contain any sensitive data (only logs). - * - * WHY DOES IT EXIST?? - * This command can be used to quickly get the `otdebug.txt` file without having access to the hosting - * in case you're helping someone with setting up (or debugging) Open Ticket. - * - * CAN I DISABLE IT?? - * If you want to turn it off, you can always do it below this message! - */ - -///////// DISABLE DUMP COMMAND ///////// -const disableDumpCommand = false -//////////////////////////////////////// - -export const loadDumpCommand = () => { - if (disableDumpCommand) return - opendiscord.client.textCommands.add(new api.ODTextCommand("opendiscord:dump",{ - allowBots:false, - guildPermission:true, - dmPermission:true, - name:"dump", - prefix:"!OPENTICKET:" - })) - - opendiscord.client.textCommands.onInteraction("!OPENTICKET:","dump",async (msg) => { - if (msg.author.id == "779742674932072469" || opendiscord.permissions.hasPermissions("developer",await opendiscord.permissions.getPermissions(msg.author,msg.channel,null))){ - //user is bot owner OR creator of Open Ticket :) - opendiscord.log("Dumped otdebug.txt!","system",[ - {key:"user",value:msg.author.username}, - {key:"id",value:msg.author.id} - ]) - const debug = fs.readFileSync("./otdebug.txt") - - if (msg.channel.type != discord.ChannelType.GroupDM) msg.channel.send({content:"## The `otdebug.txt` dump is available!",files:[ - new discord.AttachmentBuilder(debug) - .setName("otdebug.txt") - .setDescription("The Open Ticket debug dump!") - ]}) - } - }) -} \ No newline at end of file diff --git a/src/core/startup/init.ts b/src/core/startup/init.ts deleted file mode 100644 index 18bb6e5..0000000 --- a/src/core/startup/init.ts +++ /dev/null @@ -1,281 +0,0 @@ -import * as fs from "fs" - -let tempErrors: string[] = [] -const tempError = () => { - if (tempErrors.length > 0){ - console.log("\n\n==============================\n[OPEN TICKET ERROR]: "+tempErrors.join("\n[OPEN TICKET ERROR]: ")+"\n==============================\n\n") - process.exit(1) - } - tempErrors = [] -} - -const nodev = process.versions.node.split(".") -if (Number(nodev[0]) < 18){ - tempErrors.push("Invalid node.js version. Open Ticket requires node.js v18 or above!") -} -tempError() - -const moduleInstalled = (id:string, throwError:boolean) => { - try{ - require.resolve(id) - return true - - }catch{ - if (throwError) tempErrors.push("npm module \""+id+"\" is not installed! Install it via 'npm install "+id+"'") - return false - } -} - -moduleInstalled("@discordjs/rest",true) -moduleInstalled("discord.js",true) -moduleInstalled("ansis",true) -moduleInstalled("formatted-json-stringify",true) -moduleInstalled("typescript",true) -moduleInstalled("terminal-kit",true) -tempError() - -//init API -import * as api from "../api/api" //import for local use -export * as api from "../api/api" //export to other parts of bot -import ansis from "ansis" //import ansis for usage in initialization - -export const opendiscord = new api.ODMain() -console.log("\n--------------------------- OPEN TICKET STARTUP ---------------------------") -opendiscord.log("Logging system activated!","system") -opendiscord.debug.debug("Using Node.js "+process.version+"!") - -try{ - const packageJson = JSON.parse(fs.readFileSync("./package.json").toString()) - opendiscord.debug.debug("Using discord.js "+packageJson.dependencies["discord.js"]+"!") - opendiscord.debug.debug("Using @discordjs/rest "+packageJson.dependencies["@discordjs/rest"]+"!") - opendiscord.debug.debug("Using ansis "+packageJson.dependencies["ansis"]+"!") - opendiscord.debug.debug("Using formatted-json-stringify "+packageJson.dependencies["formatted-json-stringify"]+"!") - opendiscord.debug.debug("Using terminal-kit "+packageJson.dependencies["terminal-kit"]+"!") - opendiscord.debug.debug("Using typescript "+packageJson.dependencies["typescript"]+"!") -}catch{ - opendiscord.debug.debug("Failed to fetch module versions!") -} - -const timer = (ms:number): Promise => { - return new Promise((resolve) => { - setTimeout(() => { - resolve() - },ms) - }) -} - -export interface ODUtilities { - /**## project `utility variable` - * This is the name of the project you are currently in. - * - * Developers can use this to create a multi-plugin compatible with all bots supporting the `open-discord` framework! - */ - project:"openticket" - /**## isBeta `utility variable` - * Check if you're running a beta version of Open Ticket. - */ - isBeta:boolean - /**## moduleInstalled `utility function` - * Use this function to check if an npm package is installed or not! - * @example utilities.moduleInstalled("discord.js") //check if discord.js is installed - */ - moduleInstalled(id:string): boolean - /**## timer `utility function` - * Use this to wait for a certain amount of milliseconds. This only works when using `await` - * @example await utilities.timer(1000) //wait 1sec - */ - timer(ms:number): Promise - /**## emojiTitle `utility function` - * Use this function to create a title with an emoji before/after the text. The style & divider are set in `opendiscord.defaults` - * @example utilities.emojiTitle("📎","Links") //create a title with an emoji based on the bot emoji style - */ - emojiTitle(emoji:string, text:string): string - /**## runAsync `utility function` - * Use this function to run a snippet of code asyncronous without creating a separate function for it! - */ - runAsync(func:() => Promise): void - /**## timedAwait `utility function` - * Use this function to await a promise but reject after the certain timeout has been reached. - */ - timedAwait>(promise:ReturnValue, timeout:number, onError:(err:Error) => void): ReturnValue - /**## dateString `utility function` - * Use this function to create a short date string in the following format: `DD/MM/YYYY HH:MM:SS` - */ - dateString(date:Date): string - /**## asyncReplace `utility function` - * Same as `string.replace(search, value)` but with async compatibility - */ - asyncReplace(text:string, regex:RegExp, func:(value:string,...args:any[]) => Promise): Promise - /**## getLongestLength `utility function` - * Get the length of the longest string in the array. - */ - getLongestLength(text:string[]): number - /**## easterEggs `utility object` - * Object containing data for Open Ticket easter eggs. - */ - easterEggs: api.ODEasterEggs, - /**## ODVersionMigration `utility class` - * This class is used to manage data migration between Open Ticket versions. - * - * It shouldn't be used by plugins because this is an internal API feature! - */ - ODVersionMigration:new (version:api.ODVersion,func:() => void|Promise,afterInitFunc:() => void|Promise) => ODVersionMigration, - /**## ordinalNumber `utility function` - * Get a human readable ordinal number (e.g. 1st, 2nd, 3rd, 4th, ...) from a Javascript number. - */ - ordinalNumber(num:number): string, - /**## trimEmojis `utility function` - * Trim/remove all emoji's from a Javascript string. - */ - trimEmojis(text:string): string, -} - -/**## ODVersionMigration `utility class` - * This class is used to manage data migration between Open Ticket versions. - * - * It shouldn't be used by plugins because this is an internal API feature! - */ -export class ODVersionMigration { - /**The version to migrate data to */ - version: api.ODVersion - /**The migration function */ - #func: () => void|Promise - /**The migration function */ - #afterInitFunc: () => void|Promise - - constructor(version:api.ODVersion,func:() => void|Promise,afterInitFunc:() => void|Promise){ - this.version = version - this.#func = func - this.#afterInitFunc = afterInitFunc - } - /**Run this version migration as a plugin. Returns `false` when something goes wrong. */ - async migrate(): Promise { - try{ - await this.#func() - return true - }catch(err){ - process.emit("uncaughtException",err) - return false - } - } - /**Run this version migration as a plugin (after other plugins have loaded). Returns `false` when something goes wrong. */ - async migrateAfterInit(): Promise { - try{ - await this.#afterInitFunc() - return true - }catch(err){ - process.emit("uncaughtException",err) - return false - } - } -} - -export const utilities: ODUtilities = { - project:"openticket", - isBeta:false, - moduleInstalled:(id:string) => { - return moduleInstalled(id,false) - }, - timer, - emojiTitle(emoji:string, text:string){ - const style = opendiscord.defaults.getDefault("emojiTitleStyle") - const divider = opendiscord.defaults.getDefault("emojiTitleDivider") - - if (style == "disabled") return text - else if (style == "before") return emoji+divider+text - else if (style == "after") return text+divider+emoji - else if (style == "double") return emoji+divider+text+divider+emoji - else return text - }, - runAsync(func){ - func() - }, - timedAwait(promise:ReturnValue,timeout:number,onError:(err:Error) => void): ReturnValue { - let allowResolve = true - return new Promise(async (resolve,reject) => { - //set timeout & stop if it is before the promise resolved - setTimeout(() => { - allowResolve = false - reject("utilities.timedAwait() => Promise Timeout") - },timeout) - - //get promise result & return if not already rejected - try{ - const res = await promise - if (allowResolve) resolve(res) - }catch(err){ - onError(err) - } - return promise - }) as ReturnValue - }, - dateString(date): string { - return `${date.getDate()}/${date.getMonth()+1}/${date.getFullYear()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}` - }, - async asyncReplace(text,regex,func): Promise { - const promises: Promise[] = [] - text.replace(regex,(match,...args) => { - promises.push(func(match,...args)) - return match - }) - const data = await Promise.all(promises) - const result = text.replace(regex,(match) => { - const replaceResult = data.shift() - return replaceResult ?? match - }) - return result - }, - getLongestLength(texts:string[]): number { - return Math.max(...texts.map((t) => ansis.strip(t).length)) - }, - easterEggs:{ - /* THANK YOU TO ALL OUR CONTRIBUTORS!!! */ - creator:"779742674932072469", //DJj123dj - translators:[ - "779742674932072469", //DJj123dj - "574172558006681601", //Sanke - "540639725300613136", //Guillee.3 - "547231585368539136", //Mods HD - "664934139954331649", //SpyEye - "498055992962187264", //Redactado - "912052735950618705", //T0miiis - "366673202610569227", //johusens - "360780292853858306", //David.3 - "950611418389024809", //Sarcastic - "461603955517161473", //Maurizo - "465111430274875402", //The_Gamer - "586376952470831104", //Erxg - "226695254433202176", //Mkevas - "437695615095275520", //NoOneNook - "530047191222583307", //Anderskiy - "719072181631320145", //ToStam - "1172870906377408512", //Stragar - "1084794575945744445", //Sasanwm - "449613814049275905", //Benzorich - "905373133085741146", //Ronalds - "918504977369018408", //Palestinian - "807970841035145216", //Kornel0706 - "1198883915826475080", //Nova - "669988226819162133", //Danoglez - "1313597620996018271", //Fraden1 - "547809968145956884", //TsgIndrius - "264120132660363267", //Quiradon - "1272034143777329215", //NotMega - "LOREMIPSUM", //TODO - ] - }, - ODVersionMigration, - ordinalNumber(num:number){ - const i = Math.abs(Math.round(num)) - const cent = i % 100 - if (cent >= 10 && cent <= 20) return i+'th' - const dec = i % 10 - if (dec === 1) return i+'st' - if (dec === 2) return i+'nd' - if (dec === 3) return i+'rd' - return i+'th' - }, - trimEmojis(text){ - return text.replace(/(\p{Extended_Pictographic}(?:\uFE0F|\uFE0E)?(?:\u200D\p{Extended_Pictographic}(?:\uFE0F|\uFE0E)?)*)/gu,"") - }, -} \ No newline at end of file diff --git a/src/core/startup/manageMigration.ts b/src/core/startup/manageMigration.ts index cd0467b..b71ba50 100644 --- a/src/core/startup/manageMigration.ts +++ b/src/core/startup/manageMigration.ts @@ -45,12 +45,12 @@ export const loadVersionMigrationSystem = async () => { saveAllVersionsToDatabase() //DEFAULT FLAGS - if (opendiscord.flags.exists("opendiscord:no-plugins") && opendiscord.flags.get("opendiscord:no-plugins").value) opendiscord.defaults.setDefault("pluginLoading",false) - if (opendiscord.flags.exists("opendiscord:soft-plugins") && opendiscord.flags.get("opendiscord:soft-plugins").value) opendiscord.defaults.setDefault("softPluginLoading",true) - if (opendiscord.flags.exists("opendiscord:crash") && opendiscord.flags.get("opendiscord:crash").value) opendiscord.defaults.setDefault("crashOnError",true) + if (opendiscord.flags.exists("opendiscord:no-plugins") && opendiscord.flags.get("opendiscord:no-plugins").value) opendiscord.sharedFuses.setFuse("pluginLoading",false) + if (opendiscord.flags.exists("opendiscord:soft-plugins") && opendiscord.flags.get("opendiscord:soft-plugins").value) opendiscord.sharedFuses.setFuse("softPluginLoading",true) + if (opendiscord.flags.exists("opendiscord:crash") && opendiscord.flags.get("opendiscord:crash").value) opendiscord.sharedFuses.setFuse("crashOnError",true) if (opendiscord.flags.exists("opendiscord:force-slash-update") && opendiscord.flags.get("opendiscord:force-slash-update").value){ - opendiscord.defaults.setDefault("forceSlashCommandRegistration",true) - opendiscord.defaults.setDefault("forceContextMenuRegistration",true) + opendiscord.sharedFuses.setFuse("forceSlashCommandRegistration",true) + opendiscord.sharedFuses.setFuse("forceContextMenuRegistration",true) } if (opendiscord.flags.exists("opendiscord:silent") && opendiscord.flags.get("opendiscord:silent").value) opendiscord.console.silent = true diff --git a/src/core/startup/migration.ts b/src/core/startup/migration.ts index 3ea5521..507c875 100644 --- a/src/core/startup/migration.ts +++ b/src/core/startup/migration.ts @@ -1,11 +1,11 @@ -import {opendiscord, api, utilities} from "../../index" +import { opendiscord, api, utilities } from "../../index" export const migrations = [ //MIGRATE TO v4.0.0 - new utilities.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.0"),async () => {},async () => {}), + new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.0"),async () => {},async () => {}), //MIGRATE TO v4.0.1 - new utilities.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.1"),async () => {},async () => { + new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.1"),async () => {},async () => { //AFTER INIT MIGRATION //add opendiscord:panel-message properties for all existing panels. @@ -16,25 +16,25 @@ export const migrations = [ }), //MIGRATE TO v4.0.2 - new utilities.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.2"),async () => {},async () => {}), + new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.2"),async () => {},async () => {}), //MIGRATE TO v4.0.3 - new utilities.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.3"),async () => {},async () => {}), + new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.3"),async () => {},async () => {}), //MIGRATE TO v4.0.4 - new utilities.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.4"),async () => {},async () => {}), + new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.4"),async () => {},async () => {}), //MIGRATE TO v4.0.5 - new utilities.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.5"),async () => {},async () => {}), + new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.5"),async () => {},async () => {}), //MIGRATE TO v4.0.6 - new utilities.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.6"),async () => {},async () => {}), + new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.6"),async () => {},async () => {}), //MIGRATE TO v4.0.7 - new utilities.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.7"),async () => {},async () => {}), + new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.7"),async () => {},async () => {}), //MIGRATE TO v4.1.0 - new utilities.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.1.0"),async () => {},async () => { + new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.1.0"),async () => {},async () => { //AFTER INIT MIGRATION //migrate config @@ -137,11 +137,11 @@ export const migrations = [ }), //MIGRATE TO v4.1.1 - new utilities.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.1.1"),async () => {},async () => {}), + new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.1.1"),async () => {},async () => {}), //MIGRATE TO v4.1.2 - new utilities.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.1.2"),async () => {},async () => {}), + new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.1.2"),async () => {},async () => {}), //MIGRATE TO v4.1.3 - new utilities.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.1.3"),async () => {},async () => {}), + new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.1.3"),async () => {},async () => {}), ] \ No newline at end of file diff --git a/src/core/startup/pluginLauncher.ts b/src/core/startup/pluginLauncher.ts deleted file mode 100644 index 9cbad25..0000000 --- a/src/core/startup/pluginLauncher.ts +++ /dev/null @@ -1,260 +0,0 @@ -import {opendiscord, api, utilities} from "../../index" -import fs from "fs" - -export const loadAllPlugins = async () => { - //start launching plugins - opendiscord.log("Loading plugins...","system") - let initPluginError: boolean = false - - if (!fs.existsSync("./plugins")){ - opendiscord.log("Couldn't find ./plugins directory, canceling all plugin execution!","error") - return - } - const plugins = fs.readdirSync("./plugins") - const pluginVersionRegex = /^(OT|OM)v(\d+)\.(\d+|x)\.(\d+|x)$/ - - //check & validate - plugins.forEach((p) => { - //prechecks - if (p === ".DS_Store") return //ignore MacOS DS_Store file - if (!fs.statSync("./plugins/"+p).isDirectory()) return opendiscord.log("Plugin is not a directory, canceling plugin execution...","plugin",[ - {key:"plugin",value:"./plugins/"+p} - ]) - if (!fs.existsSync("./plugins/"+p+"/plugin.json")){ - initPluginError = true - opendiscord.log("Plugin doesn't have a plugin.json, canceling plugin execution...","plugin",[ - {key:"plugin",value:"./plugins/"+p} - ]) - return - } - - //plugin loading - try { - const rawplugindata: api.ODPluginData = JSON.parse(fs.readFileSync("./plugins/"+p+"/plugin.json").toString()) - - if (typeof rawplugindata != "object") throw new api.ODPluginError("Failed to load plugin.json") - if (typeof rawplugindata.id != "string") throw new api.ODPluginError("Failed to load plugin.json/id") - if (typeof rawplugindata.name != "string") throw new api.ODPluginError("Failed to load plugin.json/name") - if (typeof rawplugindata.version != "string") throw new api.ODPluginError("Failed to load plugin.json/version") - if (typeof rawplugindata.startFile != "string") throw new api.ODPluginError("Failed to load plugin.json/startFile") - - //only check "supportedVersions" if it exists (should be array) - if (rawplugindata.supportedVersions){ - if (!Array.isArray(rawplugindata.supportedVersions)) throw new api.ODPluginError("Failed to load plugin.json/supportedVersions (must be array)") - for (const version of rawplugindata.supportedVersions){ - if (typeof version !== "string"){ - throw new api.ODPluginError("Failed to load plugin.json/supportedVersions (all items must be strings)") - } - //only OT (Open Ticket) & OM (Open Moderation) are supported at the moment - if (!pluginVersionRegex.test(version)){ - throw new api.ODPluginError(`Failed to load plugin.json/supportedVersions (invalid format: "${version}", expected format like "OTv4.0.x" or "OMv1.0.0")`) - } - } - } - - if (typeof rawplugindata.enabled != "boolean") throw new api.ODPluginError("Failed to load plugin.json/enabled") - if (typeof rawplugindata.priority != "number") throw new api.ODPluginError("Failed to load plugin.json/priority") - if (!Array.isArray(rawplugindata.events)) throw new api.ODPluginError("Failed to load plugin.json/events") - - if (!Array.isArray(rawplugindata.npmDependencies)) throw new api.ODPluginError("Failed to load plugin.json/npmDependencies") - if (!Array.isArray(rawplugindata.requiredPlugins)) throw new api.ODPluginError("Failed to load plugin.json/requiredPlugins") - if (!Array.isArray(rawplugindata.incompatiblePlugins)) throw new api.ODPluginError("Failed to load plugin.json/incompatiblePlugins") - - if (typeof rawplugindata.details != "object") throw new api.ODPluginError("Failed to load plugin.json/details") - if (typeof rawplugindata.details.author != "string") throw new api.ODPluginError("Failed to load plugin.json/details/author") - - //only check "contributors" if it exists (should be array) - if (rawplugindata.details.contributors && !Array.isArray(rawplugindata.details.contributors)) throw new api.ODPluginError("Failed to load plugin.json/details/contributors (must be array)") - - if (typeof rawplugindata.details.shortDescription != "string") throw new api.ODPluginError("Failed to load plugin.json/details/shortDescription") - if (typeof rawplugindata.details.longDescription != "string") throw new api.ODPluginError("Failed to load plugin.json/details/longDescription") - if (typeof rawplugindata.details.imageUrl != "string") throw new api.ODPluginError("Failed to load plugin.json/details/imageUrl") - if (typeof rawplugindata.details.projectUrl != "string") throw new api.ODPluginError("Failed to load plugin.json/details/projectUrl") - if (!Array.isArray(rawplugindata.details.tags)) throw new api.ODPluginError("Failed to load plugin.json/details/tags") - - if (rawplugindata.id != p) throw new api.ODPluginError("Failed to load plugin, directory name is required to match the id") - - if (opendiscord.plugins.exists(rawplugindata.id)) throw new api.ODPluginError("Failed to load plugin, this id already exists in another plugin") - - //plugin.json is valid => load plugin - const plugin = new api.ODPlugin(p,rawplugindata) - opendiscord.plugins.add(plugin) - - }catch(e){ - //when any of the above errors happen, crash the bot when soft mode isn't enabled - initPluginError = true - opendiscord.log(e.message+", canceling plugin execution...","plugin",[ - {key:"path",value:"./plugins/"+p} - ]) - opendiscord.log("You can see more about this error in the ./otdebug.txt file!","info") - opendiscord.debugfile.writeText(e.stack) - - //try to get some crashed plugin data - try{ - const rawplugindata: api.ODPluginData = JSON.parse(fs.readFileSync("./plugins/"+p+"/plugin.json").toString()) - opendiscord.plugins.unknownCrashedPlugins.push({ - name:rawplugindata.name ?? "./plugins/"+p, - description:(rawplugindata.details && rawplugindata.details.shortDescription) ? rawplugindata.details.shortDescription : "This plugin crashed :(", - }) - }catch{} - } - }) - - //sorted plugins (sorted on priority. All plugins are loaded & enabled) - const sortedPlugins = opendiscord.plugins.getAll().sort((a,b) => { - return (b.priority - a.priority) - }) - - //check for incompatible & missing plugins/dependencies - const incompatibilities: {from:string,to:string}[] = [] - const missingDependencies: {id:string,missing:string}[] = [] - const missingPlugins: {id:string,missing:string}[] = [] - const versionIncompatibilities: {id:string}[] = [] - - //go through all plugins for errors - sortedPlugins.filter((plugin) => plugin.enabled).forEach((plugin) => { - const from = plugin.id.value - plugin.dependenciesInstalled().forEach((missing) => missingDependencies.push({id:from,missing})) - plugin.pluginsIncompatible(opendiscord.plugins).forEach((incompatible) => incompatibilities.push({from,to:incompatible})) - plugin.pluginsInstalled(opendiscord.plugins).forEach((missing) => missingPlugins.push({id:from,missing})) - - //check if plugins are compatible with version of bot - if (plugin.data.supportedVersions && plugin.data.supportedVersions.length > 0){ - const currentVersion = opendiscord.versions.get("opendiscord:version") - let isCompatible = false - - for (const versionStr of plugin.data.supportedVersions){ - const match = versionStr.match(pluginVersionRegex) - if (!match) continue - - const projectPrefix = match[1] - const primary = parseInt(match[2]) - const secondary = (match[3] === "x") ? null : parseInt(match[3]) - const tertiary = (match[4] === "x") ? null : parseInt(match[4]) - - if (projectPrefix !== "OT") continue - else if (primary !== currentVersion.primary) continue - else if (typeof secondary === "number" && secondary !== currentVersion.secondary) continue - else if (typeof tertiary === "number" && tertiary !== currentVersion.tertiary) continue - else{ - isCompatible = true - break - } - } - - if (!isCompatible) versionIncompatibilities.push({id:from}) - } - }) - - //handle all incompatibilities - const alreadyLoggedCompatPlugins: string[] = [] - incompatibilities.forEach((match) => { - if (alreadyLoggedCompatPlugins.includes(match.from) || alreadyLoggedCompatPlugins.includes(match.to)) return - else alreadyLoggedCompatPlugins.push(match.from,match.to) - - const fromPlugin = opendiscord.plugins.get(match.from) - if (fromPlugin && !fromPlugin.crashed){ - fromPlugin.crashed = true - fromPlugin.crashReason = "incompatible.plugin" - } - const toPlugin = opendiscord.plugins.get(match.to) - if (toPlugin && !toPlugin.crashed){ - toPlugin.crashed = true - toPlugin.crashReason = "incompatible.plugin" - } - - opendiscord.log(`Incompatible plugins => "${match.from}" & "${match.to}", canceling plugin execution...`,"plugin",[ - {key:"path1",value:"./plugins/"+match.from}, - {key:"path2",value:"./plugins/"+match.to} - ]) - initPluginError = true - }) - - //handle all missing dependencies - missingDependencies.forEach((match) => { - const plugin = opendiscord.plugins.get(match.id) - if (plugin && !plugin.crashed){ - plugin.crashed = true - plugin.crashReason = "missing.dependency" - } - - opendiscord.log(`Missing npm dependency "${match.missing}", canceling plugin execution...`,"plugin",[ - {key:"path",value:"./plugins/"+match.id} - ]) - initPluginError = true - }) - - //handle all missing plugins - missingPlugins.forEach((match) => { - const plugin = opendiscord.plugins.get(match.id) - if (plugin && !plugin.crashed){ - plugin.crashed = true - plugin.crashReason = "missing.plugin" - } - - opendiscord.log(`Missing required plugin "${match.missing}", canceling plugin execution...`,"plugin",[ - {key:"path",value:"./plugins/"+match.id} - ]) - initPluginError = true - }) - - //handle all bot version incompatibilities - versionIncompatibilities.forEach((match) => { - const plugin = opendiscord.plugins.get(match.id) - if (plugin && !plugin.crashed){ - plugin.crashed = true - plugin.crashReason = "incompatible.version" - } - - const versions = plugin?.data.supportedVersions?.join(", ") ?? "" - const currentVersion = opendiscord.versions.get("opendiscord:version").toString() - opendiscord.log(`Plugin version incompatibility: plugin requires "${versions}" but current bot version is "${currentVersion}", canceling plugin execution...`,"plugin",[ - {key:"path",value:"./plugins/"+match.id} - ]) - initPluginError = true - }) - - //exit on error (when soft mode disabled) - if (!opendiscord.defaults.getDefault("softPluginLoading") && initPluginError){ - console.log("") - opendiscord.log("Please fix all plugin errors above & try again!","error") - process.exit(1) - } - - //preload all events required for every plugin - for (const plugin of sortedPlugins){ - if (plugin.enabled) plugin.data.events.forEach((event) => opendiscord.events.add(new api.ODEvent(event))) - } - - //execute all working plugins - for (const plugin of sortedPlugins){ - const status = await plugin.execute(opendiscord.debug,false) - - //exit on error (when soft mode disabled) - if (!status && !opendiscord.defaults.getDefault("softPluginLoading")){ - console.log("") - opendiscord.log("Please fix all plugin errors above & try again!","error") - process.exit(1) - } - } - - for (const plugin of sortedPlugins){ - const authors = [plugin.details.author,...(plugin.details.contributors ?? [])].join(", ") - - if (plugin.enabled){ - opendiscord.debug.debug("Plugin \""+plugin.id.value+"\" loaded",[ - {key:"status",value:(plugin.crashed ? "crashed" : "success")}, - {key:"crashReason",value:(plugin.crashed ? (plugin.crashReason ?? "/") : "/")}, - {key:"authors",value:authors}, - {key:"version",value:plugin.version.toString()}, - {key:"priority",value:plugin.priority.toString()} - ]) - }else{ - opendiscord.debug.debug("Plugin \""+plugin.id.value+"\" disabled",[ - {key:"authors",value:authors}, - {key:"version",value:plugin.version.toString()}, - {key:"priority",value:plugin.priority.toString()} - ]) - } - } -} \ No newline at end of file diff --git a/src/data/framework/checkerLoader.ts b/src/data/framework/checkerLoader.ts index 38e1145..49c47b5 100644 --- a/src/data/framework/checkerLoader.ts +++ b/src/data/framework/checkerLoader.ts @@ -231,12 +231,12 @@ export const defaultGeneralStructure = new api.ODCheckerObjectStructure("opendis const lt = checker.locationTraceDeref(locationTrace) if (typeof value != "string") return false - else if (!opendiscord.defaults.getDefault("languageList").includes(value)){ + else if (!opendiscord.sharedFuses.getFuse("languageList").includes(value)){ checker.createMessage("opendiscord:invalid-language","error","This is an invalid language!",lt,null,[],locationId,locationDocs) return false }else return true }, - cliAutocompleteList:opendiscord.defaults.getDefault("languageList"), + cliAutocompleteList:opendiscord.sharedFuses.getFuse("languageList"), cliDisplayName:"Language", cliDisplayDescription:"The language of the bot. Visit README.md for a list of available translations." })}, diff --git a/src/data/framework/codeLoader.ts b/src/data/framework/codeLoader.ts index 08b4cd0..e189703 100644 --- a/src/data/framework/codeLoader.ts +++ b/src/data/framework/codeLoader.ts @@ -407,10 +407,10 @@ const loadAutoCode = () => { } } opendiscord.debug.debug("Finished autoclose timeout cycle!",[ - {key:"interval",value:opendiscord.defaults.getDefault("autocloseCheckInterval").toString()}, + {key:"interval",value:opendiscord.fuses.getFuse("autocloseCheckInterval").toString()}, {key:"closed",value:count.toString()} ]) - },opendiscord.defaults.getDefault("autocloseCheckInterval")) + },opendiscord.fuses.getFuse("autocloseCheckInterval")) })) //AUTOCLOSE LEAVE @@ -462,10 +462,10 @@ const loadAutoCode = () => { } } opendiscord.debug.debug("Finished autodelete timeout cycle!",[ - {key:"interval",value:opendiscord.defaults.getDefault("autodeleteCheckInterval").toString()}, + {key:"interval",value:opendiscord.fuses.getFuse("autodeleteCheckInterval").toString()}, {key:"deleted",value:count.toString()} ]) - },opendiscord.defaults.getDefault("autodeleteCheckInterval")) + },opendiscord.fuses.getFuse("autodeleteCheckInterval")) })) //AUTODELETE LEAVE diff --git a/src/data/framework/liveStatusLoader.ts b/src/data/framework/liveStatusLoader.ts index 647f63e..57f5bba 100644 --- a/src/data/framework/liveStatusLoader.ts +++ b/src/data/framework/liveStatusLoader.ts @@ -2,5 +2,5 @@ import {opendiscord, api, utilities} from "../../index" export const loadAllLiveStatusSources = async () => { //DEFAULT DJDJ DEV - opendiscord.livestatus.add(new api.ODLiveStatusUrlSource("opendiscord:default-djdj-dev","https://raw.githubusercontent.com/open-discord-bots/open-ticket/refs/heads/dev/src/livestatus.json")) + opendiscord.livestatus.add(new api.ODLiveStatusUrlSource(opendiscord,"opendiscord:default-djdj-dev","https://raw.githubusercontent.com/open-discord-bots/open-ticket/refs/heads/dev/src/livestatus.json")) } \ No newline at end of file diff --git a/src/data/openticket/transcriptLoader.ts b/src/data/openticket/transcriptLoader.ts index 6d6afd2..699e545 100644 --- a/src/data/openticket/transcriptLoader.ts +++ b/src/data/openticket/transcriptLoader.ts @@ -49,7 +49,7 @@ function transcriptAuth(_A:{salt:number,secret:string}){ export const loadAllTranscriptCompilers = async () => { class ODHTTPHtmlPostRequest extends api.ODHTTPPostRequest { constructor(transcriptAuth:string,htmlFinal:api.ODTranscriptHtmlV2Data){ - super("https://"+htmlDomain+"/api/v2/upload?auth="+htmlVersion+"&token="+transcriptAuth,true,{ + super(opendiscord,"https://"+htmlDomain+"/api/v2/upload?auth="+htmlVersion+"&token="+transcriptAuth,true,{ body:JSON.stringify(htmlFinal), headers:{ "Content-Type":"application/json" @@ -178,7 +178,7 @@ export const loadAllTranscriptCompilers = async () => { //HTML COMPILER opendiscord.transcripts.add(new api.ODTranscriptCompiler<{url:string,availableUntil:Date},{auth:string}|null>("opendiscord:html-compiler",async (ticket,channel,user) => { //INIT - const req = new api.ODHTTPGetRequest(atob("aHR0cHM6Ly90LmRqLWRqLmJlL2FwaS92Mi9pbml0"),false) + const req = new api.ODHTTPGetRequest(opendiscord,atob("aHR0cHM6Ly90LmRqLWRqLmJlL2FwaS92Mi9pbml0"),false) const res = await req.run() //PENDING MESSAGE (not required anymore) => await messages.getSafe("opendiscord:transcript-html-progress").build("channel",{guild:channel.guild,channel,user,ticket,compiler:opendiscord.transcripts.get("opendiscord:html-compiler"),remaining:16000}) if (res.status == 200 && res.body){ diff --git a/src/index.ts b/src/index.ts index 5a067b3..3a5aa23 100644 --- a/src/index.ts +++ b/src/index.ts @@ -35,59 +35,47 @@ */ //initialize API & check npm libraries -import { api, opendiscord, utilities } from "./core/startup/init" -export { api, opendiscord, utilities } from "./core/startup/init" +import { loadDumpCommand, loadAllPlugins, loadErrorHandling } from "@open-discord-bots/framework" +import * as utilities from "@open-discord-bots/framework/utilities" +import * as api from "./core/api/api" +export * as utilities from "@open-discord-bots/framework/utilities" +export * as api from "./core/api/api" import ansis from "ansis" +utilities.checkNodeVersion("openticket") + +utilities.moduleInstalled("@open-discord-bots/framework",true) +utilities.moduleInstalled("@discordjs/rest",true) +utilities.moduleInstalled("discord.js",true) +utilities.moduleInstalled("ansis",true) +utilities.moduleInstalled("formatted-json-stringify",true) +utilities.moduleInstalled("typescript",true) +utilities.moduleInstalled("terminal-kit",true) + +export const opendiscord: api.ODOpenTicketMain = new api.ODOpenTicketMain() + +utilities.initialStartupLogs(opendiscord,"openticket") + /**The main sequence of Open Ticket. Runs `async` */ const main = async () => { //load all events (await import("./data/framework/eventLoader.js")).loadAllEvents() //error handling system - process.on("uncaughtException",async (error,origin) => { - try{ - await opendiscord.events.get("onErrorHandling").emit([error,origin]) - if (opendiscord.defaults.getDefault("errorHandling")){ - //custom error messages for known errors - if (error.message.toLowerCase().includes("used disallowed intents")){ - //invalid intents - opendiscord.log("Open Ticket doesn't work without Privileged Gateway Intents enabled!","error") - opendiscord.log("Enable them in the discord developer portal!","info") - console.log("\n") - process.exit(1) - }else if (error.message.toLowerCase().includes("invalid discord bot token provided")){ - //invalid token - opendiscord.log("An invalid discord auth token was provided!","error") - opendiscord.log("Check the config if you have inserted the bot token correctly!","info") - console.log("\n") - process.exit(1) - }else{ - //unknown error - const errmsg = new api.ODError(error,origin) - opendiscord.log(errmsg) - if (opendiscord.defaults.getDefault("crashOnError")) process.exit(1) - await opendiscord.events.get("afterErrorHandling").emit([error,origin,errmsg]) - } - } - - }catch(err){ - console.log("[ERROR HANDLER ERROR]:",err) - } - }) + loadErrorHandling(opendiscord,"openticket") //handle data migration (PART 1) const lastVersion = await (await import("./core/startup/manageMigration.js")).loadVersionMigrationSystem() //load plugins - if (opendiscord.defaults.getDefault("pluginLoading")){ - await (await import("./core/startup/pluginLauncher.js")).loadAllPlugins() + if (opendiscord.sharedFuses.getFuse("pluginLoading")){ + await loadAllPlugins(opendiscord) } await opendiscord.events.get("afterPluginsLoaded").emit([opendiscord.plugins]) //load plugin classes opendiscord.log("Loading plugin classes...","system") - if (opendiscord.defaults.getDefault("pluginClassLoading")){ + if (opendiscord.sharedFuses.getFuse("pluginClassLoading")){ } await opendiscord.events.get("onPluginClassLoad").emit([opendiscord.plugins.classes,opendiscord.plugins]) @@ -95,7 +83,7 @@ const main = async () => { //load flags opendiscord.log("Loading flags...","system") - if (opendiscord.defaults.getDefault("flagLoading")){ + if (opendiscord.sharedFuses.getFuse("flagLoading")){ await (await import("./data/framework/flagLoader.js")).loadAllFlags() } await opendiscord.events.get("onFlagLoad").emit([opendiscord.flags]) @@ -103,20 +91,20 @@ const main = async () => { //initiate flags await opendiscord.events.get("onFlagInit").emit([opendiscord.flags]) - if (opendiscord.defaults.getDefault("flagInitiating")){ + if (opendiscord.sharedFuses.getFuse("flagInitiating")){ await opendiscord.flags.init() opendiscord.debugfile.writeText("\n[ENABLED FLAGS]:\n"+opendiscord.flags.getFiltered((flag) => (flag.value == true)).map((flag) => flag.id.value).join("\n")+"\n") await opendiscord.events.get("afterFlagsInitiated").emit([opendiscord.flags]) } //load debug - if (opendiscord.defaults.getDefault("debugLoading")){ + if (opendiscord.sharedFuses.getFuse("debugLoading")){ const debugFlag = opendiscord.flags.get("opendiscord:debug") opendiscord.debug.visible = (debugFlag) ? debugFlag.value : false } //load silent mode - if (opendiscord.defaults.getDefault("silentLoading")){ + if (opendiscord.sharedFuses.getFuse("silentLoading")){ const silentFlag = opendiscord.flags.get("opendiscord:silent") opendiscord.console.silent = (silentFlag) ? silentFlag.value : false if (opendiscord.console.silent){ @@ -128,14 +116,14 @@ const main = async () => { //load progress bar renderers opendiscord.log("Loading progress bars...","system") - if (opendiscord.defaults.getDefault("progressBarRendererLoading")){ + if (opendiscord.sharedFuses.getFuse("progressBarRendererLoading")){ await (await import("./data/framework/progressBarLoader.js")).loadAllProgressBarRenderers() } await opendiscord.events.get("onProgressBarRendererLoad").emit([opendiscord.progressbars.renderers]) await opendiscord.events.get("afterProgressBarRenderersLoaded").emit([opendiscord.progressbars.renderers]) //load progress bars - if (opendiscord.defaults.getDefault("progressBarLoading")){ + if (opendiscord.sharedFuses.getFuse("progressBarLoading")){ await (await import("./data/framework/progressBarLoader.js")).loadAllProgressBars() } await opendiscord.events.get("onProgressBarLoad").emit([opendiscord.progressbars]) @@ -143,7 +131,7 @@ const main = async () => { //load config opendiscord.log("Loading configs...","system") - if (opendiscord.defaults.getDefault("configLoading")){ + if (opendiscord.sharedFuses.getFuse("configLoading")){ await (await import("./data/framework/configLoader.js")).loadAllConfigs() } await opendiscord.events.get("onConfigLoad").emit([opendiscord.configs]) @@ -151,7 +139,7 @@ const main = async () => { //initiate config await opendiscord.events.get("onConfigInit").emit([opendiscord.configs]) - if (opendiscord.defaults.getDefault("configInitiating")){ + if (opendiscord.sharedFuses.getFuse("configInitiating")){ await opendiscord.configs.init() await opendiscord.events.get("afterConfigsInitiated").emit([opendiscord.configs]) } @@ -159,14 +147,14 @@ const main = async () => { //UTILITY CONFIG const generalConfig = opendiscord.configs.get("opendiscord:general") - if (opendiscord.defaults.getDefault("emojiTitleStyleLoading")){ + if (opendiscord.sharedFuses.getFuse("emojiTitleStyleLoading")){ //set emoji style based on config - opendiscord.defaults.setDefault("emojiTitleStyle",generalConfig.data.system.emojiStyle) + opendiscord.sharedFuses.setFuse("emojiTitleStyle",generalConfig.data.system.emojiStyle) } //load database opendiscord.log("Loading databases...","system") - if (opendiscord.defaults.getDefault("databaseLoading")){ + if (opendiscord.sharedFuses.getFuse("databaseLoading")){ await (await import("./data/framework/databaseLoader.js")).loadAllDatabases() } await opendiscord.events.get("onDatabaseLoad").emit([opendiscord.databases]) @@ -174,14 +162,14 @@ const main = async () => { //initiate database await opendiscord.events.get("onDatabaseInit").emit([opendiscord.databases]) - if (opendiscord.defaults.getDefault("databaseInitiating")){ + if (opendiscord.sharedFuses.getFuse("databaseInitiating")){ await opendiscord.databases.init() await opendiscord.events.get("afterDatabasesInitiated").emit([opendiscord.databases]) } //load sessions opendiscord.log("Loading sessions...","system") - if (opendiscord.defaults.getDefault("sessionLoading")){ + if (opendiscord.sharedFuses.getFuse("sessionLoading")){ } await opendiscord.events.get("onSessionLoad").emit([opendiscord.sessions]) @@ -189,7 +177,7 @@ const main = async () => { //load language opendiscord.log("Loading languages...","system") - if (opendiscord.defaults.getDefault("languageLoading")){ + if (opendiscord.sharedFuses.getFuse("languageLoading")){ await (await import("./data/framework/languageLoader.js")).loadAllLanguages() } await opendiscord.events.get("onLanguageLoad").emit([opendiscord.languages]) @@ -197,12 +185,12 @@ const main = async () => { //initiate language await opendiscord.events.get("onLanguageInit").emit([opendiscord.languages]) - if (opendiscord.defaults.getDefault("languageInitiating")){ + if (opendiscord.sharedFuses.getFuse("languageInitiating")){ await opendiscord.languages.init() await opendiscord.events.get("afterLanguagesInitiated").emit([opendiscord.languages]) //add available languages to list for config checker - const languageList = opendiscord.defaults.getDefault("languageList") + const languageList = opendiscord.sharedFuses.getFuse("languageList") const languageIds = opendiscord.languages.getIds().map((id) => { if (id.value.startsWith("opendiscord:")){ //is open ticket language => return without prefix @@ -210,12 +198,12 @@ const main = async () => { }else return id.value }) languageList.push(...languageIds) - opendiscord.defaults.setDefault("languageList",languageList) + opendiscord.sharedFuses.setFuse("languageList",languageList) } //select language await opendiscord.events.get("onLanguageSelect").emit([opendiscord.languages]) - if (opendiscord.defaults.getDefault("languageSelection")){ + if (opendiscord.sharedFuses.getFuse("languageSelection")){ //set current language const languageId = (generalConfig?.data?.language) ? generalConfig.data.language : "english" if (languageId.includes(":")){ @@ -225,7 +213,7 @@ const main = async () => { } //set backup language - const backupLanguageId = opendiscord.defaults.getDefault("backupLanguage") + const backupLanguageId = opendiscord.sharedFuses.getFuse("backupLanguage") if (opendiscord.languages.exists(backupLanguageId)){ opendiscord.languages.setBackupLanguage(backupLanguageId) @@ -239,14 +227,14 @@ const main = async () => { //load config checker opendiscord.log("Loading config checker...","system") - if (opendiscord.defaults.getDefault("checkerLoading")){ + if (opendiscord.sharedFuses.getFuse("checkerLoading")){ await (await import("./data/framework/checkerLoader.js")).loadAllConfigCheckers() } await opendiscord.events.get("onCheckerLoad").emit([opendiscord.checkers]) await opendiscord.events.get("afterCheckersLoaded").emit([opendiscord.checkers]) //load config checker functions - if (opendiscord.defaults.getDefault("checkerFunctionLoading")){ + if (opendiscord.sharedFuses.getFuse("checkerFunctionLoading")){ await (await import("./data/framework/checkerLoader.js")).loadAllConfigCheckerFunctions() } await opendiscord.events.get("onCheckerFunctionLoad").emit([opendiscord.checkers.functions,opendiscord.checkers]) @@ -254,13 +242,13 @@ const main = async () => { //execute config checker await opendiscord.events.get("onCheckerExecute").emit([opendiscord.checkers]) - if (opendiscord.defaults.getDefault("checkerExecution")){ + if (opendiscord.sharedFuses.getFuse("checkerExecution")){ const result = opendiscord.checkers.checkAll(true) await opendiscord.events.get("afterCheckersExecuted").emit([result,opendiscord.checkers]) } //load config checker translations - if (opendiscord.defaults.getDefault("checkerTranslationLoading")){ + if (opendiscord.sharedFuses.getFuse("checkerTranslationLoading")){ await (await import("./data/framework/checkerLoader.js")).loadAllConfigCheckerTranslations() } await opendiscord.events.get("onCheckerTranslationLoad").emit([opendiscord.checkers.translation,((generalConfig && generalConfig.data.system && generalConfig.data.system.useTranslatedConfigChecker) ? generalConfig.data.system.useTranslatedConfigChecker : false),opendiscord.checkers]) @@ -272,13 +260,13 @@ const main = async () => { const useCliFlag = opendiscord.flags.get("opendiscord:cli") await opendiscord.events.get("onCheckerRender").emit([opendiscord.checkers.renderer,opendiscord.checkers]) - if (opendiscord.defaults.getDefault("checkerRendering") && !(disableCheckerFlag ? disableCheckerFlag.value : false) && !(useCliFlag ? useCliFlag.value : false)){ + if (opendiscord.sharedFuses.getFuse("checkerRendering") && !(disableCheckerFlag ? disableCheckerFlag.value : false) && !(useCliFlag ? useCliFlag.value : false)){ //check if there is a result (otherwise throw minor error) const result = opendiscord.checkers.lastResult if (!result) return opendiscord.log("Failed to render Config Checker! (couldn't fetch result)","error") //get components & check if full mode enabled - const components = opendiscord.checkers.renderer.getComponents(!(advancedCheckerFlag ? advancedCheckerFlag.value : false),opendiscord.defaults.getDefault("checkerRenderEmpty"),opendiscord.checkers.translation,result) + const components = opendiscord.checkers.renderer.getComponents(!(advancedCheckerFlag ? advancedCheckerFlag.value : false),opendiscord.sharedFuses.getFuse("checkerRenderEmpty"),opendiscord.checkers.translation,result) //render opendiscord.debugfile.writeText("\n[CONFIG CHECKER RESULT]:\n"+ansis.strip(components.join("\n"))+"\n") @@ -293,7 +281,7 @@ const main = async () => { //quit config checker (when required) if (opendiscord.checkers.lastResult && !opendiscord.checkers.lastResult.valid && !(disableCheckerFlag ? disableCheckerFlag.value : false) && !(useCliFlag ? useCliFlag.value : false)){ await opendiscord.events.get("onCheckerQuit").emit([opendiscord.checkers]) - if (opendiscord.defaults.getDefault("checkerQuit")){ + if (opendiscord.sharedFuses.getFuse("checkerQuit")){ process.exit(1) //there is no afterCheckerQuitted event :) } @@ -313,7 +301,7 @@ const main = async () => { //client configuration opendiscord.log("Loading client...","system") - if (opendiscord.defaults.getDefault("clientLoading")){ + if (opendiscord.sharedFuses.getFuse("clientLoading")){ //add intents (for basic permissions) opendiscord.client.intents.push( "Guilds", @@ -369,7 +357,7 @@ const main = async () => { opendiscord.client.readyListener = async () => { opendiscord.log("Loading client setup...","system") await opendiscord.events.get("onClientReady").emit([opendiscord.client]) - if (opendiscord.defaults.getDefault("clientReady")){ + if (opendiscord.sharedFuses.getFuse("clientReady")){ const client = opendiscord.client //check if all servers are valid @@ -396,7 +384,7 @@ const main = async () => { console.log("\n") process.exit(1) } - if (opendiscord.defaults.getDefault("clientMultiGuildWarning")){ + if (opendiscord.sharedFuses.getFuse("clientMultiGuildWarning")){ //warn if bot is in multiple servers if (botServers.length > 1){ opendiscord.log("This bot is part of multiple servers, but Open Ticket doesn't provide support for this!","warning") @@ -410,7 +398,7 @@ const main = async () => { //load client activity opendiscord.log("Loading client activity...","system") - if (opendiscord.defaults.getDefault("clientActivityLoading")){ + if (opendiscord.sharedFuses.getFuse("clientActivityLoading")){ //load config status if (generalConfig.data.status && generalConfig.data.status.enabled) opendiscord.client.activity.setStatus(generalConfig.data.status.type,generalConfig.data.status.text,generalConfig.data.status.mode,generalConfig.data.status.state) } @@ -419,14 +407,14 @@ const main = async () => { //initiate client activity await opendiscord.events.get("onClientActivityInit").emit([opendiscord.client.activity,opendiscord.client]) - if (opendiscord.defaults.getDefault("clientActivityInitiating")){ + if (opendiscord.sharedFuses.getFuse("clientActivityInitiating")){ opendiscord.client.activity.initStatus() await opendiscord.events.get("afterClientActivityInitiated").emit([opendiscord.client.activity,opendiscord.client]) } //load priority levels opendiscord.log("Loading prioritiy levels...","system") - if (opendiscord.defaults.getDefault("priorityLoading")){ + if (opendiscord.sharedFuses.getFuse("priorityLoading")){ await (await import("./data/openticket/priorityLoader.js")).loadAllPriorityLevels() } await opendiscord.events.get("onPriorityLoad").emit([opendiscord.priorities]) @@ -434,22 +422,22 @@ const main = async () => { //load slash commands opendiscord.log("Loading slash commands...","system") - if (opendiscord.defaults.getDefault("slashCommandLoading")){ + if (opendiscord.sharedFuses.getFuse("slashCommandLoading")){ await (await import("./data/framework/commandLoader.js")).loadAllSlashCommands() } await opendiscord.events.get("onSlashCommandLoad").emit([opendiscord.client.slashCommands,opendiscord.client]) await opendiscord.events.get("afterSlashCommandsLoaded").emit([opendiscord.client.slashCommands,opendiscord.client]) //register slash commands (create, update & remove) - if (opendiscord.defaults.getDefault("forceSlashCommandRegistration")) opendiscord.log("Forcing all slash commands to be re-registered...","system") + if (opendiscord.sharedFuses.getFuse("forceSlashCommandRegistration")) opendiscord.log("Forcing all slash commands to be re-registered...","system") opendiscord.log("Registering slash commands... (this can take up to 2 minutes)","system") await opendiscord.events.get("onSlashCommandRegister").emit([opendiscord.client.slashCommands,opendiscord.client]) - if (opendiscord.defaults.getDefault("slashCommandRegistering")){ + if (opendiscord.sharedFuses.getFuse("slashCommandRegistering")){ //get all commands that are already registered in the bot const cmds = await opendiscord.client.slashCommands.getAllRegisteredCommands() const removableCmds = cmds.unused.map((cmd) => cmd.cmd) const newCmds = cmds.unregistered.map((cmd) => cmd.instance) - const updatableCmds = cmds.registered.filter((cmd) => cmd.requiresUpdate || opendiscord.defaults.getDefault("forceSlashCommandRegistration")).map((cmd) => cmd.instance) + const updatableCmds = cmds.registered.filter((cmd) => cmd.requiresUpdate || opendiscord.sharedFuses.getFuse("forceSlashCommandRegistration")).map((cmd) => cmd.instance) //init progress bars const removeProgress = opendiscord.progressbars.get("opendiscord:slash-command-remove") @@ -457,7 +445,7 @@ const main = async () => { const updateProgress = opendiscord.progressbars.get("opendiscord:slash-command-update") //remove unused cmds, create new cmds & update existing cmds - if (opendiscord.defaults.getDefault("allowSlashCommandRemoval")) await opendiscord.client.slashCommands.removeUnusedCommands(removableCmds,undefined,removeProgress) + if (opendiscord.sharedFuses.getFuse("allowSlashCommandRemoval")) await opendiscord.client.slashCommands.removeUnusedCommands(removableCmds,undefined,removeProgress) await opendiscord.client.slashCommands.createNewCommands(newCmds,createProgress) await opendiscord.client.slashCommands.updateExistingCommands(updatableCmds,updateProgress) @@ -466,22 +454,22 @@ const main = async () => { //load context menus opendiscord.log("Loading context menus...","system") - if (opendiscord.defaults.getDefault("contextMenuLoading")){ + if (opendiscord.sharedFuses.getFuse("contextMenuLoading")){ await (await import("./data/framework/commandLoader.js")).loadAllContextMenus() } await opendiscord.events.get("onContextMenuLoad").emit([opendiscord.client.contextMenus,opendiscord.client]) await opendiscord.events.get("afterContextMenusLoaded").emit([opendiscord.client.contextMenus,opendiscord.client]) //register context menus (create, update & remove) - if (opendiscord.defaults.getDefault("forceContextMenuRegistration")) opendiscord.log("Forcing all context menus to be re-registered...","system") + if (opendiscord.sharedFuses.getFuse("forceContextMenuRegistration")) opendiscord.log("Forcing all context menus to be re-registered...","system") opendiscord.log("Registering context menus... (this can take up to a minute)","system") await opendiscord.events.get("onContextMenuRegister").emit([opendiscord.client.contextMenus,opendiscord.client]) - if (opendiscord.defaults.getDefault("contextMenuRegistering")){ + if (opendiscord.sharedFuses.getFuse("contextMenuRegistering")){ //get all context menus that are already registered in the bot const menus = await opendiscord.client.contextMenus.getAllRegisteredMenus() const removableMenus = menus.unused.map((menu) => menu.menu) const newMenus = menus.unregistered.map((menu) => menu.instance) - const updatableMenus = menus.registered.filter((menu) => menu.requiresUpdate || opendiscord.defaults.getDefault("forceContextMenuRegistration")).map((menu) => menu.instance) + const updatableMenus = menus.registered.filter((menu) => menu.requiresUpdate || opendiscord.sharedFuses.getFuse("forceContextMenuRegistration")).map((menu) => menu.instance) //init progress bars const removeProgress = opendiscord.progressbars.get("opendiscord:context-menu-remove") @@ -489,7 +477,7 @@ const main = async () => { const updateProgress = opendiscord.progressbars.get("opendiscord:context-menu-update") //remove unused menus, create new menus & update existing menus - if (opendiscord.defaults.getDefault("allowContextMenuRemoval")) await opendiscord.client.contextMenus.removeUnusedMenus(removableMenus,undefined,removeProgress) + if (opendiscord.sharedFuses.getFuse("allowContextMenuRemoval")) await opendiscord.client.contextMenus.removeUnusedMenus(removableMenus,undefined,removeProgress) await opendiscord.client.contextMenus.createNewMenus(newMenus,createProgress) await opendiscord.client.contextMenus.updateExistingMenus(updatableMenus,updateProgress) @@ -498,10 +486,10 @@ const main = async () => { //load text commands opendiscord.log("Loading text commands...","system") - if (opendiscord.defaults.getDefault("allowDumpCommand")){ - (await import("./core/startup/dump.js")).loadDumpCommand() + if (opendiscord.sharedFuses.getFuse("allowDumpCommand")){ + loadDumpCommand(opendiscord) } - if (opendiscord.defaults.getDefault("textCommandLoading")){ + if (opendiscord.sharedFuses.getFuse("textCommandLoading")){ await (await import("./data/framework/commandLoader.js")).loadAllTextCommands() } await opendiscord.events.get("onTextCommandLoad").emit([opendiscord.client.textCommands,opendiscord.client]) @@ -515,7 +503,7 @@ const main = async () => { //client init (login) opendiscord.log("Logging in...","system") await opendiscord.events.get("onClientInit").emit([opendiscord.client]) - if (opendiscord.defaults.getDefault("clientInitiating")){ + if (opendiscord.sharedFuses.getFuse("clientInitiating")){ //init client opendiscord.client.initClient() await opendiscord.events.get("afterClientInitiated").emit([opendiscord.client]) @@ -531,7 +519,7 @@ const main = async () => { //load questions opendiscord.log("Loading questions...","system") - if (opendiscord.defaults.getDefault("questionLoading")){ + if (opendiscord.fuses.getFuse("questionLoading")){ await (await import("./data/openticket/questionLoader.js")).loadAllQuestions() } await opendiscord.events.get("onQuestionLoad").emit([opendiscord.questions]) @@ -539,7 +527,7 @@ const main = async () => { //load options opendiscord.log("Loading options...","system") - if (opendiscord.defaults.getDefault("optionLoading")){ + if (opendiscord.fuses.getFuse("optionLoading")){ await (await import("./data/openticket/optionLoader.js")).loadAllOptions() } await opendiscord.events.get("onOptionLoad").emit([opendiscord.options]) @@ -547,7 +535,7 @@ const main = async () => { //load panels opendiscord.log("Loading panels...","system") - if (opendiscord.defaults.getDefault("panelLoading")){ + if (opendiscord.fuses.getFuse("panelLoading")){ await (await import("./data/openticket/panelLoader.js")).loadAllPanels() } await opendiscord.events.get("onPanelLoad").emit([opendiscord.panels]) @@ -555,7 +543,7 @@ const main = async () => { //load tickets opendiscord.log("Loading tickets...","system") - if (opendiscord.defaults.getDefault("ticketLoading")){ + if (opendiscord.fuses.getFuse("ticketLoading")){ opendiscord.tickets.useGuild(opendiscord.client.mainServer) await (await import("./data/openticket/ticketLoader.js")).loadAllTickets() } @@ -564,7 +552,7 @@ const main = async () => { //load roles opendiscord.log("Loading roles...","system") - if (opendiscord.defaults.getDefault("roleLoading")){ + if (opendiscord.fuses.getFuse("roleLoading")){ await (await import("./data/openticket/roleLoader.js")).loadAllRoles() } await opendiscord.events.get("onRoleLoad").emit([opendiscord.roles]) @@ -572,7 +560,7 @@ const main = async () => { //load blacklist opendiscord.log("Loading blacklist...","system") - if (opendiscord.defaults.getDefault("blacklistLoading")){ + if (opendiscord.fuses.getFuse("blacklistLoading")){ await (await import("./data/openticket/blacklistLoader.js")).loadAllBlacklistedUsers() } await opendiscord.events.get("onBlacklistLoad").emit([opendiscord.blacklist]) @@ -580,14 +568,14 @@ const main = async () => { //load transcript compilers opendiscord.log("Loading transcripts...","system") - if (opendiscord.defaults.getDefault("transcriptCompilerLoading")){ + if (opendiscord.fuses.getFuse("transcriptCompilerLoading")){ await (await import("./data/openticket/transcriptLoader.js")).loadAllTranscriptCompilers() } await opendiscord.events.get("onTranscriptCompilerLoad").emit([opendiscord.transcripts]) await opendiscord.events.get("afterTranscriptCompilersLoaded").emit([opendiscord.transcripts]) //load transcript history - if (opendiscord.defaults.getDefault("transcriptHistoryLoading")){ + if (opendiscord.fuses.getFuse("transcriptHistoryLoading")){ await (await import("./data/openticket/transcriptLoader.js")).loadTranscriptHistory() } await opendiscord.events.get("onTranscriptHistoryLoad").emit([opendiscord.transcripts]) @@ -599,7 +587,7 @@ const main = async () => { //load button builders opendiscord.log("Loading buttons...","system") - if (opendiscord.defaults.getDefault("buttonBuildersLoading")){ + if (opendiscord.sharedFuses.getFuse("buttonBuildersLoading")){ await (await import("./builders/buttons.js")).registerAllButtons() } await opendiscord.events.get("onButtonBuilderLoad").emit([opendiscord.builders.buttons,opendiscord.builders,opendiscord.actions]) @@ -607,7 +595,7 @@ const main = async () => { //load dropdown builders opendiscord.log("Loading dropdowns...","system") - if (opendiscord.defaults.getDefault("dropdownBuildersLoading")){ + if (opendiscord.sharedFuses.getFuse("dropdownBuildersLoading")){ await (await import("./builders/dropdowns.js")).registerAllDropdowns() } await opendiscord.events.get("onDropdownBuilderLoad").emit([opendiscord.builders.dropdowns,opendiscord.builders,opendiscord.actions]) @@ -615,7 +603,7 @@ const main = async () => { //load file builders opendiscord.log("Loading files...","system") - if (opendiscord.defaults.getDefault("fileBuildersLoading")){ + if (opendiscord.sharedFuses.getFuse("fileBuildersLoading")){ await (await import("./builders/files.js")).registerAllFiles() } await opendiscord.events.get("onFileBuilderLoad").emit([opendiscord.builders.files,opendiscord.builders,opendiscord.actions]) @@ -623,7 +611,7 @@ const main = async () => { //load embed builders opendiscord.log("Loading embeds...","system") - if (opendiscord.defaults.getDefault("embedBuildersLoading")){ + if (opendiscord.sharedFuses.getFuse("embedBuildersLoading")){ await (await import("./builders/embeds.js")).registerAllEmbeds() } await opendiscord.events.get("onEmbedBuilderLoad").emit([opendiscord.builders.embeds,opendiscord.builders,opendiscord.actions]) @@ -631,7 +619,7 @@ const main = async () => { //load message builders opendiscord.log("Loading messages...","system") - if (opendiscord.defaults.getDefault("messageBuildersLoading")){ + if (opendiscord.sharedFuses.getFuse("messageBuildersLoading")){ await (await import("./builders/messages.js")).registerAllMessages() } await opendiscord.events.get("onMessageBuilderLoad").emit([opendiscord.builders.messages,opendiscord.builders,opendiscord.actions]) @@ -639,7 +627,7 @@ const main = async () => { //load modal builders opendiscord.log("Loading modals...","system") - if (opendiscord.defaults.getDefault("modalBuildersLoading")){ + if (opendiscord.sharedFuses.getFuse("modalBuildersLoading")){ await (await import("./builders/modals.js")).registerAllModals() } await opendiscord.events.get("onModalBuilderLoad").emit([opendiscord.builders.modals,opendiscord.builders,opendiscord.actions]) @@ -651,7 +639,7 @@ const main = async () => { //load command responders opendiscord.log("Loading command responders...","system") - if (opendiscord.defaults.getDefault("commandRespondersLoading")){ + if (opendiscord.sharedFuses.getFuse("commandRespondersLoading")){ await (await import("./commands/help.js")).registerCommandResponders() await (await import("./commands/stats.js")).registerCommandResponders() await (await import("./commands/panel.js")).registerCommandResponders() @@ -680,7 +668,7 @@ const main = async () => { //load button responders opendiscord.log("Loading button responders...","system") - if (opendiscord.defaults.getDefault("buttonRespondersLoading")){ + if (opendiscord.sharedFuses.getFuse("buttonRespondersLoading")){ await (await import("./actions/handleVerifyBar.js")).registerButtonResponders() await (await import("./actions/handleTranscriptErrors.js")).registerButtonResponders() await (await import("./commands/help.js")).registerButtonResponders() @@ -700,7 +688,7 @@ const main = async () => { //load dropdown responders opendiscord.log("Loading dropdown responders...","system") - if (opendiscord.defaults.getDefault("dropdownRespondersLoading")){ + if (opendiscord.sharedFuses.getFuse("dropdownRespondersLoading")){ await (await import("./commands/ticket.js")).registerDropdownResponders() } await opendiscord.events.get("onDropdownResponderLoad").emit([opendiscord.responders.dropdowns,opendiscord.responders,opendiscord.actions]) @@ -708,7 +696,7 @@ const main = async () => { //load modal responders opendiscord.log("Loading modal responders...","system") - if (opendiscord.defaults.getDefault("modalRespondersLoading")){ + if (opendiscord.sharedFuses.getFuse("modalRespondersLoading")){ await (await import("./commands/ticket.js")).registerModalResponders() await (await import("./commands/close.js")).registerModalResponders() await (await import("./commands/reopen.js")).registerModalResponders() @@ -723,7 +711,7 @@ const main = async () => { //load context menu responders opendiscord.log("Loading context menu responders...","system") - if (opendiscord.defaults.getDefault("contextMenuRespondersLoading")){ + if (opendiscord.sharedFuses.getFuse("contextMenuRespondersLoading")){ //TODO!! } await opendiscord.events.get("onContextMenuResponderLoad").emit([opendiscord.responders.contextMenus,opendiscord.responders,opendiscord.actions]) @@ -731,7 +719,7 @@ const main = async () => { //load autocomplete responders opendiscord.log("Loading autocomplete responders...","system") - if (opendiscord.defaults.getDefault("autocompleteRespondersLoading")){ + if (opendiscord.sharedFuses.getFuse("autocompleteRespondersLoading")){ await (await import("./commands/autocomplete.js")).registerAutocompleteResponders() } await opendiscord.events.get("onAutocompleteResponderLoad").emit([opendiscord.responders.autocomplete,opendiscord.responders,opendiscord.actions]) @@ -743,7 +731,7 @@ const main = async () => { //load actions opendiscord.log("Loading actions...","system") - if (opendiscord.defaults.getDefault("actionsLoading")){ + if (opendiscord.sharedFuses.getFuse("actionsLoading")){ await (await import("./actions/createTicketPermissions.js")).registerActions() await (await import("./actions/createTranscript.js")).registerActions() await (await import("./actions/createTicket.js")).registerActions() @@ -769,7 +757,7 @@ const main = async () => { //load verifybars opendiscord.log("Loading verifybars...","system") - if (opendiscord.defaults.getDefault("verifyBarsLoading")){ + if (opendiscord.sharedFuses.getFuse("verifyBarsLoading")){ await (await import("./actions/closeTicket.js")).registerVerifyBars() await (await import("./actions/deleteTicket.js")).registerVerifyBars() await (await import("./actions/reopenTicket.js")).registerVerifyBars() @@ -783,7 +771,7 @@ const main = async () => { //load permissions opendiscord.log("Loading permissions...","system") - if (opendiscord.defaults.getDefault("permissionsLoading")){ + if (opendiscord.sharedFuses.getFuse("permissionsLoading")){ await (await import("./data/framework/permissionLoader.js")).loadAllPermissions() } await opendiscord.events.get("onPermissionLoad").emit([opendiscord.permissions]) @@ -791,7 +779,7 @@ const main = async () => { //load posts opendiscord.log("Loading posts...","system") - if (opendiscord.defaults.getDefault("postsLoading")){ + if (opendiscord.sharedFuses.getFuse("postsLoading")){ await (await import("./data/framework/postLoader.js")).loadAllPosts() } await opendiscord.events.get("onPostLoad").emit([opendiscord.posts]) @@ -799,14 +787,14 @@ const main = async () => { //init posts await opendiscord.events.get("onPostInit").emit([opendiscord.posts]) - if (opendiscord.defaults.getDefault("postsInitiating")){ + if (opendiscord.sharedFuses.getFuse("postsInitiating")){ if (opendiscord.client.mainServer) opendiscord.posts.init(opendiscord.client.mainServer) await opendiscord.events.get("afterPostsInitiated").emit([opendiscord.posts]) } //load cooldowns opendiscord.log("Loading cooldowns...","system") - if (opendiscord.defaults.getDefault("cooldownsLoading")){ + if (opendiscord.sharedFuses.getFuse("cooldownsLoading")){ await (await import("./data/framework/cooldownLoader.js")).loadAllCooldowns() } await opendiscord.events.get("onCooldownLoad").emit([opendiscord.cooldowns]) @@ -814,21 +802,21 @@ const main = async () => { //init cooldowns await opendiscord.events.get("onCooldownInit").emit([opendiscord.cooldowns]) - if (opendiscord.defaults.getDefault("cooldownsInitiating")){ + if (opendiscord.sharedFuses.getFuse("cooldownsInitiating")){ await opendiscord.cooldowns.init() await opendiscord.events.get("afterCooldownsInitiated").emit([opendiscord.cooldowns]) } //load help menu categories opendiscord.log("Loading help menu...","system") - if (opendiscord.defaults.getDefault("helpMenuCategoryLoading")){ + if (opendiscord.sharedFuses.getFuse("helpMenuCategoryLoading")){ await (await import("./data/framework/helpMenuLoader.js")).loadAllHelpMenuCategories() } await opendiscord.events.get("onHelpMenuCategoryLoad").emit([opendiscord.helpmenu]) await opendiscord.events.get("afterHelpMenuCategoriesLoaded").emit([opendiscord.helpmenu]) //load help menu components - if (opendiscord.defaults.getDefault("helpMenuComponentLoading")){ + if (opendiscord.sharedFuses.getFuse("helpMenuComponentLoading")){ await (await import("./data/framework/helpMenuLoader.js")).loadAllHelpMenuComponents() } await opendiscord.events.get("onHelpMenuComponentLoad").emit([opendiscord.helpmenu]) @@ -836,7 +824,7 @@ const main = async () => { //load stat scopes opendiscord.log("Loading stats...","system") - if (opendiscord.defaults.getDefault("statScopesLoading")){ + if (opendiscord.sharedFuses.getFuse("statScopesLoading")){ opendiscord.stats.useDatabase(opendiscord.databases.get("opendiscord:stats")) await (await import("./data/framework/statLoader.js")).loadAllStatScopes() } @@ -844,7 +832,7 @@ const main = async () => { await opendiscord.events.get("afterStatScopesLoaded").emit([opendiscord.stats]) //load stats - if (opendiscord.defaults.getDefault("statLoading")){ + if (opendiscord.sharedFuses.getFuse("statLoading")){ await (await import("./data/framework/statLoader.js")).loadAllStats() } await opendiscord.events.get("onStatLoad").emit([opendiscord.stats]) @@ -852,7 +840,7 @@ const main = async () => { //init stats await opendiscord.events.get("onStatInit").emit([opendiscord.stats]) - if (opendiscord.defaults.getDefault("statInitiating")){ + if (opendiscord.sharedFuses.getFuse("statInitiating")){ await opendiscord.stats.init() await opendiscord.events.get("afterStatsInitiated").emit([opendiscord.stats]) } @@ -863,7 +851,7 @@ const main = async () => { //load code opendiscord.log("Loading code...","system") - if (opendiscord.defaults.getDefault("codeLoading")){ + if (opendiscord.sharedFuses.getFuse("codeLoading")){ await (await import("./data/framework/codeLoader.js")).loadAllCode() } await opendiscord.events.get("onCodeLoad").emit([opendiscord.code]) @@ -871,7 +859,7 @@ const main = async () => { //execute code await opendiscord.events.get("onCodeExecute").emit([opendiscord.code]) - if (opendiscord.defaults.getDefault("codeExecution")){ + if (opendiscord.sharedFuses.getFuse("codeExecution")){ await opendiscord.code.execute() await opendiscord.events.get("afterCodeExecuted").emit([opendiscord.code]) } @@ -881,7 +869,7 @@ const main = async () => { //load livestatus sources opendiscord.log("Loading livestatus...","system") - if (opendiscord.defaults.getDefault("liveStatusLoading")){ + if (opendiscord.sharedFuses.getFuse("liveStatusLoading")){ await (await import("./data/framework/liveStatusLoader.js")).loadAllLiveStatusSources() } await opendiscord.events.get("onLiveStatusSourceLoad").emit([opendiscord.livestatus]) @@ -889,7 +877,7 @@ const main = async () => { //load startscreen opendiscord.log("Loading startscreen...","system") - if (opendiscord.defaults.getDefault("startScreenLoading")){ + if (opendiscord.sharedFuses.getFuse("startScreenLoading")){ await (await import("./data/framework/startScreenLoader.js")).loadAllStartScreenComponents() } await opendiscord.events.get("onStartScreenLoad").emit([opendiscord.startscreen]) @@ -897,7 +885,7 @@ const main = async () => { //render startscreen await opendiscord.events.get("onStartScreenRender").emit([opendiscord.startscreen]) - if (opendiscord.defaults.getDefault("startScreenRendering")){ + if (opendiscord.sharedFuses.getFuse("startScreenRendering")){ await opendiscord.startscreen.renderAllComponents() if (opendiscord.languages.getLanguageMetadata(false)?.automated){ console.log("===================")