@open-discord-bots/framework 0.3.14 → 0.3.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/api/main.js +1 -1
  2. package/dist/api/modules/responder.js +50 -26
  3. package/package.json +1 -1
  4. package/src/api/index.ts +0 -31
  5. package/src/api/main.ts +0 -203
  6. package/src/api/modules/action.ts +0 -89
  7. package/src/api/modules/base.ts +0 -845
  8. package/src/api/modules/builder.ts +0 -1755
  9. package/src/api/modules/checker.ts +0 -1826
  10. package/src/api/modules/client.ts +0 -2345
  11. package/src/api/modules/code.ts +0 -84
  12. package/src/api/modules/component.ts +0 -2000
  13. package/src/api/modules/config.ts +0 -264
  14. package/src/api/modules/console.ts +0 -697
  15. package/src/api/modules/cooldown.ts +0 -369
  16. package/src/api/modules/database.ts +0 -321
  17. package/src/api/modules/event.ts +0 -123
  18. package/src/api/modules/flag.ts +0 -99
  19. package/src/api/modules/fuse.ts +0 -365
  20. package/src/api/modules/helpmenu.ts +0 -273
  21. package/src/api/modules/language.ts +0 -230
  22. package/src/api/modules/permission.ts +0 -363
  23. package/src/api/modules/plugin.ts +0 -294
  24. package/src/api/modules/post.ts +0 -137
  25. package/src/api/modules/progressbar.ts +0 -370
  26. package/src/api/modules/responder.ts +0 -1625
  27. package/src/api/modules/session.ts +0 -181
  28. package/src/api/modules/startscreen.ts +0 -345
  29. package/src/api/modules/state.ts +0 -298
  30. package/src/api/modules/statistic.ts +0 -380
  31. package/src/api/modules/verifybar.ts +0 -68
  32. package/src/api/modules/worker.ts +0 -119
  33. package/src/cli/editConfig.ts +0 -930
  34. package/src/cli/index.ts +0 -152
  35. package/src/index.ts +0 -8
  36. package/src/startup/compilation.ts +0 -204
  37. package/src/startup/dump.ts +0 -46
  38. package/src/startup/errorHandling.ts +0 -42
  39. package/src/startup/pluginLauncher.ts +0 -265
  40. package/src/utilities/index.ts +0 -229
  41. package/tools/cleanup.js +0 -2
package/src/cli/index.ts DELETED
@@ -1,152 +0,0 @@
1
- import * as api from "../api/index.js"
2
- import * as utilities from "../utilities/index.js"
3
- import {Terminal, terminal} from "terminal-kit"
4
- import * as discord from "discord.js"
5
- import ansis from "ansis"
6
- import crypto from "crypto"
7
-
8
- export * from "./editConfig.js"
9
-
10
- /**## ODCliHeaderOpts `interface`
11
- * All metadata required for rendering the Interactive Setup CLI header.
12
- */
13
- export interface ODCliHeaderOpts {
14
- /**The main logo to display (multiple lines splitted in string array). */
15
- logo:string[],
16
- /**The main color of the project. */
17
- projectColor:discord.HexColorString,
18
- /**The version of the project. */
19
- projectVersion:api.ODVersion,
20
- /**The name of the project in display style (e.g. `Open Ticket`) */
21
- projectName:string
22
- }
23
-
24
- /**## ODCliStartFunction `type`
25
- * A function used to start a sub-system of the interactive setup CLI.
26
- */
27
- export type ODCliStartFunction = (backFn:() => api.ODPromiseVoid) => Promise<void>
28
-
29
- /**A utility function to center text to a certain width. */
30
- export function centerText(text:string,width:number){
31
- if (width < text.length) return text
32
- let newWidth = width-ansis.strip(text).length+1
33
- let final = " ".repeat(newWidth/2)+text
34
- return final
35
- }
36
-
37
- /**A utility function to terminate the interactive CLI. */
38
- export async function terminate(opts:ODCliHeaderOpts){
39
- terminal.grabInput(false)
40
- terminal.clear()
41
- terminal.green("👋 Exited the "+opts.projectName+" Interactive Setup CLI.\n")
42
- process.exit(0)
43
- }
44
-
45
- /**A utility function generate a unique config ID based on a user-named input. */
46
- export function generateUniqueIdFromName(name:string){
47
- //id only allows a-z, 0-9 & dash characters (& replace spaces with dashes)
48
- const filteredChars = name.toLowerCase().replaceAll(" ","-").split("").filter((ch) => /^[a-zA-Z0-9-]{1}$/.test(ch))
49
- const randomSuffix = "-"+crypto.randomBytes(4).toString("hex")
50
- return filteredChars.join("")+randomSuffix
51
- }
52
-
53
- /**Render the header of the interactive setup CLI. */
54
- export function renderHeader(opts:ODCliHeaderOpts,path:(string|number)[]|string){
55
- terminal.grabInput(true)
56
- terminal.clear().moveTo(1,1)
57
- terminal(ansis.hex("#f8ba00")(opts.logo.join("\n")+"\n"))
58
- terminal.bold(centerText("Interactive Setup CLI - Version: "+opts.projectVersion.toString()+" - Support: https://discord.dj-dj.be\n",88))
59
- if (typeof path == "string") terminal.cyan(centerText(path+"\n\n",88))
60
- else if (path.length < 1) terminal.cyan(centerText("👋 Hi! Welcome to the "+opts.projectName+" Interactive Setup CLI! 👋\n\n",88))
61
- else terminal.cyan(centerText("🌐 Current Location: "+path.map((v,i) => {
62
- if (i == 0) return v.toString()
63
- else if (typeof v == "string") return ".\""+v+"\""
64
- else if (typeof v == "number") return "."+v
65
- }).join("")+"\n\n",88))
66
- }
67
-
68
- /**Render the mode selector for the interactive setup CLI */
69
- async function renderCliModeSelector(opts:ODCliHeaderOpts,backFn:(() => api.ODPromiseVoid),renderEditConfig:ODCliStartFunction|null,renderQuickSetup:ODCliStartFunction|null){
70
- renderHeader(opts,[])
71
- terminal(ansis.bold.green("Please select what CLI module you want to use.\n")+ansis.italic.gray("(use arrow keys to navigate, exit using escape)\n"))
72
-
73
- const answer = await terminal.singleColumnMenu([
74
- "✏️ Edit Config "+ansis.gray("=> Edit the current config, add/remove settings & more!"),
75
- "⏱️ Quick Setup "+ansis.gray("=> A quick and easy way of setting up the bot in your Discord server."),
76
- ],{
77
- leftPadding:"> ",
78
- style:terminal.cyan,
79
- selectedStyle:terminal.bgDefaultColor.bold,
80
- submittedStyle:terminal.bgBlue,
81
- extraLines:2,
82
- cancelable:true
83
- }).promise
84
-
85
- if (answer.canceled) return await backFn()
86
- else if (answer.selectedIndex == 0 && renderEditConfig) await renderEditConfig(async () => {await renderCliModeSelector(opts,backFn,renderEditConfig,renderQuickSetup)})
87
- else if (answer.selectedIndex == 1 && renderQuickSetup) await renderQuickSetup(async () => {await renderCliModeSelector(opts,backFn,renderEditConfig,renderQuickSetup)})
88
- else return await backFn()
89
- }
90
-
91
- /**Execute/start the Interactive Setup CLI. Make sure no other processes disturb the flow. */
92
- export async function execute(opts:ODCliHeaderOpts,renderEditConfig:ODCliStartFunction|null,renderQuickSetup:ODCliStartFunction|null){
93
- terminal.on("key",(name:string) => {
94
- if (name == "CTRL_C") terminate(opts)
95
- })
96
-
97
- if (terminal.width < 100 || terminal.height < 35){
98
- terminal(ansis.red.bold("\n\nMake sure your console, terminal or CMD window has a "+ansis.cyan("minimum width & height")+" of "+ansis.cyan("100x35")+" characters."))
99
- terminal(ansis.red.bold("\nOtherwise the "+opts.projectName+" Interactive Setup CLI will be rendered incorrectly."))
100
- terminal(ansis.red.bold("\nThe current terminal dimensions are: "+ansis.cyan(terminal.width+"x"+terminal.height)+"."))
101
- }else await renderCliModeSelector(opts,async () => {await terminate(opts)},renderEditConfig,renderQuickSetup)
102
- }
103
-
104
- /**A basic style template for select menu's in the interactive setup CLI. */
105
- export const autoCompleteMenuOpts: Terminal.SingleLineMenuOptions = {
106
- style:terminal.white,
107
- selectedStyle:terminal.bgBlue.white
108
- }
109
-
110
- /**A set of preset colors to be used when auto-filling colors in the interactive setup CLI. */
111
- export const presetColors = new Map<string,string>([
112
- ["dark red","#992d22"],
113
- ["red","#ff0000"],
114
- ["light red","#f06c6c"],
115
- ["dark orange","#ed510e"],
116
- ["orange","#ed6f0e"],
117
- ["light orange","#f0b06c"],
118
- ["openticket","#f8ba00"],
119
- ["dark yellow","#deb100"],
120
- ["yellow","#ffff00"],
121
- ["light yellow","#ffff8c"],
122
- ["banana","#ffe896"],
123
- ["lime","#a8e312"],
124
- ["dark green","#009600"],
125
- ["green","#00ff00"],
126
- ["light green","#76f266"],
127
- ["dark cyan","#00abab"],
128
- ["cyan","#00ffff"],
129
- ["light cyan","#63ffff"],
130
- ["aquamarine","#7fffd4"],
131
- ["dark skyblue","#006bc9"],
132
- ["skyblue","#0095ff"],
133
- ["light skyblue","#40bfff"],
134
- ["dark blue","#00006e"],
135
- ["blue","#0000ff"],
136
- ["light blue","#5353fc"],
137
- ["blurple","#5865F2"],
138
- ["dark purple","#3f009e"],
139
- ["purple","#8000ff"],
140
- ["light purple","#9257eb"],
141
- ["dark pink","#b82ab0"],
142
- ["pink","#ff6bf8"],
143
- ["light pink","#ff9cfa"],
144
- ["magenta","#ff00ff"],
145
- ["black","#000000"],
146
- ["brown","#806050"],
147
- ["dark gray","#4f4f4f"],
148
- ["gray","#808080"],
149
- ["light gray","#b3b3b3"],
150
- ["white","#ffffff"],
151
- ["invisible","#393A41"]
152
- ])
package/src/index.ts DELETED
@@ -1,8 +0,0 @@
1
- export { loadDumpCommand } from "./startup/dump.js"
2
- export { loadAllPlugins } from "./startup/pluginLauncher.js"
3
- export { frameworkStartup } from "./startup/compilation.js"
4
- export { loadErrorHandling } from "./startup/errorHandling.js"
5
- import { checkFrameworkAllowed } from "./startup/compilation.js"
6
-
7
- //check directory structure
8
- checkFrameworkAllowed()
@@ -1,204 +0,0 @@
1
- import fs from "fs"
2
- import ts from "typescript"
3
- import { createHash, Hash } from "crypto"
4
- import nodepath from "path"
5
- import ansis from "ansis"
6
- import type { ODPluginData, ODProjectType } from "../api/index.js"
7
-
8
- /** ## What is this?
9
- * This is a function which compares `./src/` with a hash stored in `./dist/hash.txt`.
10
- * The hash is based on the modified date & file metadata of all files in `./src/`.
11
- *
12
- * If the hash is different, the bot will automatically re-compile.
13
- * This will help you save CPU resources because the bot shouldn't re-compile when nothing has been changed :)
14
- */
15
- function computeSourceHash(dir:string,upperHash?:Hash){
16
- const hash = upperHash ? upperHash : createHash("sha256")
17
- const info = fs.readdirSync(dir,{withFileTypes:true})
18
-
19
- for (const file of info) {
20
- const fullPath = nodepath.join(dir,file.name)
21
- if (file.isFile() && [".js",".ts",".jsx",".tsx"].some((ext) => file.name.endsWith(ext))){
22
- const statInfo = fs.statSync(fullPath)
23
- //compute hash using file metadata
24
- const fileInfo = `${fullPath}:${statInfo.size}:${statInfo.mtimeMs}`
25
- hash.update(fileInfo)
26
-
27
- }else if (file.isDirectory()){
28
- //recursively compute all folders
29
- computeSourceHash(fullPath,hash)
30
- }
31
- }
32
- //return when not being called recursively
33
- if (!upperHash){
34
- return hash.digest("hex")
35
- }
36
- }
37
-
38
- function requiresCompilation(project:ODProjectType){
39
- const logTitle = (project == "openticket") ? "OT" : "OM"
40
-
41
- //check hashes when not using "--compile-only" flag
42
- if (process.argv.includes("--compile-only")) return true
43
-
44
- console.log(logTitle+": Comparing prebuilds with source...")
45
- const sourceHash = computeSourceHash("./src/")
46
- const pluginHash = computeSourceHash("./plugins/")
47
- const hash = sourceHash+":"+pluginHash
48
-
49
- if (fs.existsSync("./dist/hash.txt")){
50
- const distHash = fs.readFileSync("./dist/hash.txt").toString()
51
- if (distHash === hash) return false
52
- else return true
53
- }else return true
54
- }
55
-
56
- function saveNewCompilationHash(){
57
- const sourceHash = computeSourceHash("./src/")
58
- const pluginHash = computeSourceHash("./plugins/")
59
- const hash = sourceHash+":"+pluginHash
60
- fs.writeFileSync("./dist/hash.txt",hash)
61
- }
62
-
63
- export function checkFrameworkAllowed(project?:ODProjectType){
64
- const logTitle = (project) ? ((project == "openticket") ? "OT" : "OM") : "OD"
65
- const requiredStructures: string[] = [
66
- "index.js",
67
- "./package.json",
68
- "./README.md",
69
- "./LICENSE.md",
70
- "./tsconfig.json",
71
- "./src/",
72
- "./src/index.ts",
73
- "./languages/",
74
- "./config/",
75
- "./plugins/",
76
- ]
77
- for (const path of requiredStructures){
78
- if (!fs.existsSync(path)) throw new Error(logTitle+": Project uses invalid structure for Open Discord! (missing: "+path+")")
79
- }
80
-
81
- const licenseContents = fs.readFileSync("./LICENSE.md").toString()
82
- const readmeContents = fs.readFileSync("./README.md").toString()
83
-
84
- if (
85
- !licenseContents.includes("DJj123dj & Contributors") ||
86
- !licenseContents.includes("GNU GENERAL PUBLIC LICENSE") ||
87
- !licenseContents.includes("DJdj Development. <https://www.dj-dj.be/>") ||
88
- !licenseContents.includes("Additional Terms")
89
- ) throw new Error(logTitle+": Please do not use this framework in third party bots or outside Open Ticket/Moderation! (1)")
90
-
91
- if (
92
- !readmeContents.includes(`<img src="https://apis.dj-dj.be/cdn/openticket/logo.png" alt="Open Ticket" width="650px">`) &&
93
- !readmeContents.includes(`<img src="https://apis.dj-dj.be/cdn/openmoderation/logo.png" alt="Open Moderation" width="650px">`)
94
- ) throw new Error(logTitle+": Please do not use this framework in third party bots or outside Open Ticket/Moderation! (2)")
95
- if (!readmeContents.includes("DJdj Development") || !readmeContents.includes("DJj123dj")) throw new Error(logTitle+": Please do not use this framework in third party bots or outside Open Ticket/Moderation! (3)")
96
- }
97
-
98
- export function frameworkStartup(startupFlags:string[],project:ODProjectType,startCallback:() => void){
99
- const logTitle = (project == "openticket") ? "OT" : "OM"
100
-
101
- //push additional startup flags (for pterodactyl panels)
102
- process.argv.push(...startupFlags)
103
-
104
- //check directory structure
105
- checkFrameworkAllowed(project)
106
-
107
- //start compilation
108
- if (!process.argv.includes("--no-compile")){
109
- const requiredDependencies: Set<string> = new Set()
110
- if (fs.existsSync("./plugins")){
111
- console.log(logTitle+": Reading plugin.json files...")
112
- for (const pluginDir of fs.readdirSync("./plugins")){
113
- if (pluginDir === ".DS_Store") continue
114
- const pluginPath = nodepath.join("./plugins", pluginDir)
115
- if (!fs.statSync(pluginPath).isDirectory()) continue
116
-
117
- const pluginJsonPath = nodepath.join(pluginPath, "plugin.json")
118
- if (fs.existsSync(pluginJsonPath)){
119
- try{
120
- const pluginData: ODPluginData = JSON.parse(fs.readFileSync(pluginJsonPath).toString())
121
- if (pluginData.npmDependencies && Array.isArray(pluginData.npmDependencies)){
122
- pluginData.npmDependencies.forEach((dep) => {
123
- if (typeof dep === "string" && dep.trim()){
124
- requiredDependencies.add(dep.trim())
125
- }
126
- })
127
- }
128
- }catch(err){
129
- // skip invalid plugin.json files, will be caught later
130
- }
131
- }
132
- }
133
-
134
- if (requiredDependencies.size > 0){
135
- console.log(logTitle+": Checking plugin npm dependencies...")
136
- const missingDeps: string[] = []
137
- for (const dep of requiredDependencies){
138
- try{
139
- import.meta.resolve(dep)
140
- }catch(err){
141
- missingDeps.push(dep)
142
- }
143
- }
144
-
145
- if (missingDeps.length > 0){
146
- console.log(ansis.red(logTitle+": ❌ Fatal Error --> Missing npm dependencies required by plugins:\n\n")+ansis.cyan(missingDeps.map((dep) => " - "+dep).join("\n")+"\n"))
147
- console.log(logTitle+": Please install missing dependencies using the following command:\n> "+ansis.bold.green("npm install " + missingDeps.join(" "))+"\n")
148
- process.exit(1)
149
- }
150
- }
151
- }
152
-
153
- if (requiresCompilation(project)){
154
- console.log(logTitle+": Compilation Required...")
155
-
156
- //REMOVE EXISTING BUILDS
157
- console.log(logTitle+": Removing Prebuilds...")
158
- fs.rmSync("./dist",{recursive:true,force:true})
159
-
160
- //COMPILE TYPESCRIPT
161
- console.log(logTitle+": Compiling Typescript...")
162
- const configPath = nodepath.resolve('./tsconfig.json')
163
- const configFile = ts.readConfigFile(configPath,ts.sys.readFile)
164
-
165
- //check for tsconfig errors
166
- if (configFile.error){
167
- const message = ts.formatDiagnosticsWithColorAndContext([configFile.error],ts.createCompilerHost({}))
168
- console.error(message)
169
- process.exit(1)
170
- }
171
-
172
- //parse tsconfig file
173
- const parsedConfig = ts.parseJsonConfigFileContent(configFile.config,ts.sys,nodepath.dirname(configPath))
174
-
175
- //create program/compiler
176
- const program = ts.createProgram({
177
- rootNames:parsedConfig.fileNames,
178
- options:parsedConfig.options
179
- })
180
-
181
- //emit all compiled files
182
- const emitResult = program.emit()
183
-
184
- //print emit errors/warnings (type errors)
185
- const allDiagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics)
186
- const formattedDiagnostics = ts.formatDiagnosticsWithColorAndContext(allDiagnostics, ts.createCompilerHost(parsedConfig.options))
187
- console.log(formattedDiagnostics)
188
-
189
- if (emitResult.emitSkipped || allDiagnostics.find((d) => d.category == ts.DiagnosticCategory.Error || d.category == ts.DiagnosticCategory.Warning)){
190
- console.log(logTitle+": Compilation Failed!")
191
- process.exit(1)
192
- }
193
- }else console.log(logTitle+": No Compilation Required...")
194
-
195
- //save new compilation hash
196
- saveNewCompilationHash()
197
- }
198
-
199
- //START BOT
200
- console.log(logTitle+": Compilation Succeeded!")
201
- if (process.argv.includes("--compile-only")) process.exit(0) //exit when no startup is required!
202
- console.log(logTitle+": Starting Bot!")
203
- startCallback()
204
- }
@@ -1,46 +0,0 @@
1
- import * as api from "../api/index.js"
2
- import * as utilities from "../utilities/index.js"
3
- import * as discord from "discord.js"
4
- import * as fs from "fs"
5
-
6
-
7
- /** ### What is this?
8
- * This is the `!OPENTICKET:dump` command.
9
- * It's a utility command which can only be used by the creator of Open Discord/Ticket/Moderation or the owner of the bot.
10
- * This command will send the `debug.txt` file in DM. It's not dangerous as the `debug.txt` file doesn't contain any sensitive data (only logs).
11
- *
12
- * ### Why does it exist?
13
- * This command can be used to quickly get the `debug.txt` file without having access to the hosting
14
- * in case you're helping someone with setting up (or debugging) Open Discord/Ticket/Moderation.
15
- *
16
- * ### Can I disable it?
17
- * If you want to turn it off, you turn off the fuse using `opendiscord.sharedFuses.setFuse("allowDumpCommand",false)`
18
- */
19
-
20
- export const loadDumpCommand = (opendiscord:api.ODMain) => {
21
- if (!opendiscord.sharedFuses.getFuse("allowDumpCommand")) return
22
- opendiscord.client.textCommands.add(new api.ODTextCommand("opendiscord:dump",{
23
- allowBots:false,
24
- guildPermission:true,
25
- dmPermission:true,
26
- name:"dump",
27
- prefix:"!OPENTICKET:"
28
- }))
29
-
30
- opendiscord.client.textCommands.onInteraction("!OPENTICKET:","dump",async (msg) => {
31
- if (msg.author.id == "779742674932072469" || opendiscord.permissions.hasPermissions("developer",await opendiscord.permissions.getPermissions(msg.author,msg.channel,null))){
32
- //user is bot owner OR creator of Open Discord/Ticket/Moderation :)
33
- opendiscord.log("Dumped "+opendiscord.debugfile.filename+"!","system",[
34
- {key:"user",value:msg.author.username},
35
- {key:"id",value:msg.author.id}
36
- ])
37
- const debug = fs.readFileSync(opendiscord.debugfile.path)
38
-
39
- if (msg.channel.type != discord.ChannelType.GroupDM) msg.channel.send({content:"## The `"+opendiscord.debugfile.filename+"` dump is available!",files:[
40
- new discord.AttachmentBuilder(debug)
41
- .setName(opendiscord.debugfile.filename)
42
- .setDescription("The Open Discord debug dump!")
43
- ]})
44
- }
45
- })
46
- }
@@ -1,42 +0,0 @@
1
- import * as api from "../api/index.js"
2
- import * as utilities from "../utilities/index.js"
3
-
4
- export function loadErrorHandling(opendiscord:api.ODMain,project:api.ODProjectType){
5
- //increase error stack trace
6
- Error.stackTraceLimit = 50
7
-
8
- process.on("uncaughtException",async (error,origin) => {
9
- try{
10
- const beforeEvent = opendiscord.events.get("onErrorHandling")
11
- if (beforeEvent) await beforeEvent.emit([error,origin])
12
-
13
- if (opendiscord.sharedFuses.getFuse("errorHandling")){
14
- //custom error messages for known errors
15
- if (error.message.toLowerCase().includes("used disallowed intents")){
16
- //invalid intents
17
- opendiscord.log(((project === "openticket") ? "Open Ticket" : "Open Moderation")+" doesn't work without Privileged Gateway Intents enabled!","error")
18
- opendiscord.log("Enable them in the discord developer portal!","info")
19
- console.log("\n")
20
- process.exit(1)
21
- }else if (error.message.toLowerCase().includes("invalid discord bot token provided")){
22
- //invalid token
23
- opendiscord.log("An invalid discord auth token was provided!","error")
24
- opendiscord.log("Check the config if you have inserted the bot token correctly!","info")
25
- console.log("\n")
26
- process.exit(1)
27
- }else{
28
- //unknown error
29
- const errmsg = new api.ODError(error,origin)
30
- opendiscord.log(errmsg)
31
- if (opendiscord.sharedFuses.getFuse("crashOnError")) process.exit(1)
32
-
33
- const afterEvent = opendiscord.events.get("afterErrorHandling")
34
- if (afterEvent) await afterEvent.emit([error,origin,errmsg])
35
- }
36
- }
37
-
38
- }catch(err){
39
- console.log("[ERROR HANDLER ERROR]:",err)
40
- }
41
- })
42
- }