@open-discord-bots/framework 0.0.1 → 0.0.2

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 (103) hide show
  1. package/LICENSE.md +713 -0
  2. package/README.md +104 -0
  3. package/dist/api/api.d.ts +26 -0
  4. package/dist/api/api.js +44 -0
  5. package/dist/api/main.d.ts +133 -0
  6. package/dist/api/main.js +87 -0
  7. package/dist/api/modules/action.d.ts +34 -0
  8. package/dist/api/modules/action.js +58 -0
  9. package/dist/api/modules/base.d.ts +329 -0
  10. package/dist/api/modules/base.js +804 -0
  11. package/dist/api/modules/builder.d.ts +647 -0
  12. package/dist/api/modules/builder.js +1441 -0
  13. package/dist/api/modules/checker.d.ts +648 -0
  14. package/dist/api/modules/checker.js +1324 -0
  15. package/dist/api/modules/client.d.ts +768 -0
  16. package/dist/api/modules/client.js +1859 -0
  17. package/dist/api/modules/code.d.ts +33 -0
  18. package/dist/api/modules/code.js +57 -0
  19. package/dist/api/modules/config.d.ts +70 -0
  20. package/dist/api/modules/config.js +206 -0
  21. package/dist/api/modules/console.d.ts +305 -0
  22. package/dist/api/modules/console.js +598 -0
  23. package/dist/api/modules/cooldown.d.ts +138 -0
  24. package/dist/api/modules/cooldown.js +359 -0
  25. package/dist/api/modules/database.d.ts +135 -0
  26. package/dist/api/modules/database.js +271 -0
  27. package/dist/api/modules/event.d.ts +43 -0
  28. package/dist/api/modules/event.js +100 -0
  29. package/dist/api/modules/flag.d.ts +40 -0
  30. package/dist/api/modules/flag.js +72 -0
  31. package/dist/api/modules/fuse.d.ts +218 -0
  32. package/dist/api/modules/fuse.js +123 -0
  33. package/dist/api/modules/helpmenu.d.ts +106 -0
  34. package/dist/api/modules/helpmenu.js +167 -0
  35. package/dist/api/modules/language.d.ts +85 -0
  36. package/dist/api/modules/language.js +195 -0
  37. package/dist/api/modules/permission.d.ts +121 -0
  38. package/dist/api/modules/permission.js +314 -0
  39. package/dist/api/modules/plugin.d.ts +128 -0
  40. package/dist/api/modules/plugin.js +168 -0
  41. package/dist/api/modules/post.d.ts +44 -0
  42. package/dist/api/modules/post.js +92 -0
  43. package/dist/api/modules/progressbar.d.ts +108 -0
  44. package/dist/api/modules/progressbar.js +233 -0
  45. package/dist/api/modules/responder.d.ts +506 -0
  46. package/dist/api/modules/responder.js +1468 -0
  47. package/dist/api/modules/session.d.ts +58 -0
  48. package/dist/api/modules/session.js +171 -0
  49. package/dist/api/modules/startscreen.d.ts +165 -0
  50. package/dist/api/modules/startscreen.js +293 -0
  51. package/dist/api/modules/stat.d.ts +142 -0
  52. package/dist/api/modules/stat.js +293 -0
  53. package/dist/api/modules/verifybar.d.ts +54 -0
  54. package/dist/api/modules/verifybar.js +60 -0
  55. package/dist/api/modules/worker.d.ts +41 -0
  56. package/dist/api/modules/worker.js +93 -0
  57. package/dist/api/utils.d.ts +61 -0
  58. package/dist/api/utils.js +254 -0
  59. package/dist/index.d.ts +4 -1
  60. package/dist/index.js +40 -0
  61. package/dist/startup/dump.d.ts +14 -0
  62. package/dist/startup/dump.js +79 -0
  63. package/dist/startup/errorHandling.d.ts +2 -0
  64. package/dist/startup/errorHandling.js +43 -0
  65. package/dist/startup/pluginLauncher.d.ts +2 -0
  66. package/dist/startup/pluginLauncher.js +202 -0
  67. package/package.json +9 -3
  68. package/src/api/api.ts +29 -0
  69. package/src/api/main.ts +189 -0
  70. package/src/api/modules/action.ts +58 -0
  71. package/src/api/modules/base.ts +811 -0
  72. package/src/api/modules/builder.ts +1554 -0
  73. package/src/api/modules/checker.ts +1549 -0
  74. package/src/api/modules/client.ts +2247 -0
  75. package/src/api/modules/code.ts +58 -0
  76. package/src/api/modules/config.ts +159 -0
  77. package/src/api/modules/console.ts +665 -0
  78. package/src/api/modules/cooldown.ts +348 -0
  79. package/src/api/modules/database.ts +278 -0
  80. package/src/api/modules/event.ts +99 -0
  81. package/src/api/modules/flag.ts +73 -0
  82. package/src/api/modules/fuse.ts +348 -0
  83. package/src/api/modules/helpmenu.ts +216 -0
  84. package/src/api/modules/language.ts +201 -0
  85. package/src/api/modules/permission.ts +340 -0
  86. package/src/api/modules/plugin.ts +242 -0
  87. package/src/api/modules/post.ts +90 -0
  88. package/src/api/modules/progressbar.ts +232 -0
  89. package/src/api/modules/responder.ts +1420 -0
  90. package/src/api/modules/session.ts +155 -0
  91. package/src/api/modules/startscreen.ts +320 -0
  92. package/src/api/modules/stat.ts +313 -0
  93. package/src/api/modules/verifybar.ts +61 -0
  94. package/src/api/modules/worker.ts +93 -0
  95. package/src/api/utils.ts +206 -0
  96. package/src/cli/cli.ts +151 -0
  97. package/src/cli/editConfig.ts +943 -0
  98. package/src/index.ts +6 -1
  99. package/src/startup/compilation.ts +186 -0
  100. package/src/startup/dump.ts +45 -0
  101. package/src/startup/errorHandling.ts +38 -0
  102. package/src/startup/pluginLauncher.ts +261 -0
  103. package/LICENSE +0 -21
@@ -0,0 +1,811 @@
1
+ ///////////////////////////////////////
2
+ //BASE MODULE
3
+ ///////////////////////////////////////
4
+ import * as fs from "fs"
5
+ import { ODConsoleWarningMessage, ODDebugger } from "./console"
6
+ import type { ODMain } from "../main"
7
+
8
+ /**## ODPromiseVoid `type`
9
+ * This is a simple type to represent a callback return value that could be a promise or not.
10
+ */
11
+ export type ODPromiseVoid = void|Promise<void>
12
+
13
+ /**## ODOptionalPromise `type`
14
+ * This is a simple type to represent a type as normal value or a promise value.
15
+ */
16
+ export type ODOptionalPromise<T> = T|Promise<T>
17
+
18
+
19
+ /**## ODValidButtonColor `type`
20
+ * This is a collection of all the possible button colors.
21
+ */
22
+ export type ODValidButtonColor = "gray"|"red"|"green"|"blue"
23
+
24
+ /**## ODProjectType `type`
25
+ * Valid project types for using Open Discord.
26
+ */
27
+ export type ODProjectType = "openticket"|"openmoderation"
28
+
29
+ /**## ODValidId `type`
30
+ * This is a valid Open Discord identifier. It can be an `ODId` or `string`!
31
+ *
32
+ * You will see this type in many functions from Open Discord.
33
+ */
34
+ export type ODValidId = string|ODId
35
+
36
+ /**## ODValidJsonType `type`
37
+ * This is a collection of all types that can be stored in a JSON file!
38
+ *
39
+ * list: `string`, `number`, `boolean`, `array`, `object`, `null`
40
+ */
41
+ export type ODValidJsonType = string|number|boolean|object|ODValidJsonType[]|null
42
+
43
+
44
+ /**## ODInterfaceWithPartialProperty `type`
45
+ * This is a utility type to create an interface where some properties are optional!
46
+ */
47
+ export type ODInterfaceWithPartialProperty<Interface,Key extends keyof Interface> = Omit<Interface,Key> & Partial<Pick<Interface,Key>>
48
+
49
+ /**## ODDiscordIdType `type`
50
+ * A list of all available discord ID types. Used in the config checker.
51
+ */
52
+ export type ODDiscordIdType = "role"|"server"|"channel"|"category"|"user"|"member"|"interaction"|"message"
53
+
54
+ /**## ODId `class`
55
+ * This is an Open Discord identifier.
56
+ *
57
+ * It can only contain the following characters: `a-z`, `A-Z`, `0-9`, `:`, `-` & `_`
58
+ *
59
+ * You can use this class to assign a unique id when creating configs, databases, languages & more!
60
+ */
61
+ export class ODId {
62
+ /**The full value of this `ODId` as a `string`. */
63
+ #value: string
64
+ /**The full value of this `ODId` as a `string`. */
65
+ set value(id:string){
66
+ this._change(this.#value,id)
67
+ this.#value = id
68
+ }
69
+ get value(){
70
+ return this.#value
71
+ }
72
+ /**The change listener for the parent `ODManager` of this `ODId`. */
73
+ #change: ((oldId:string,newId:string) => void)|null = null
74
+
75
+ constructor(id:ODValidId){
76
+ if (typeof id != "string" && !(id instanceof ODId)) throw new ODSystemError("Invalid constructor parameter => id:ODValidId")
77
+
78
+ if (typeof id == "string"){
79
+ //id is string
80
+ const result: string[] = []
81
+ const charregex = /[a-zA-Z0-9éèçàêâôûî\:\-\_]/
82
+
83
+ id.split("").forEach((char) => {
84
+ if (charregex.test(char)){
85
+ result.push(char)
86
+ }
87
+ })
88
+
89
+ if (result.length > 0) this.#value = result.join("")
90
+ else throw new ODSystemError("invalid ID at 'new ODID(id: "+id+")'")
91
+ }else{
92
+ //id is ODId
93
+ this.#value = id.#value
94
+ }
95
+ }
96
+
97
+ /**Returns a string representation of this id. (same as `this.value`) */
98
+ toString(){
99
+ return this.#value
100
+ }
101
+ /**The namespace of the id before `:`. (e.g. `opendiscord` for `opendiscord:autoclose-enabled`) */
102
+ getNamespace(){
103
+ const splitted = this.#value.split(":")
104
+ if (splitted.length > 1) return splitted[0]
105
+ else return ""
106
+ }
107
+ /**The identifier of the id after `:`. (e.g. `autoclose-enabled` for `opendiscord:autoclose-enabled`) */
108
+ getIdentifier(){
109
+ const splitted = this.#value.split(":")
110
+ if (splitted.length > 1){
111
+ splitted.shift()
112
+ return splitted.join(":")
113
+ }else return this.#value
114
+ }
115
+ /**Trigger an `onChange()` event in the parent `ODManager` of this class. */
116
+ protected _change(oldId:string,newId:string){
117
+ if (this.#change){
118
+ try{
119
+ this.#change(oldId,newId)
120
+ }catch(err){
121
+ process.emit("uncaughtException",err)
122
+ throw new ODSystemError("Failed to execute _change() callback!")
123
+ }
124
+ }
125
+ }
126
+ /****(❌ SYSTEM ONLY!!)** Set the callback executed when a value inside this class changes. */
127
+ changed(callback:((oldId:string,newId:string) => void)|null){
128
+ this.#change = callback
129
+ }
130
+ }
131
+
132
+ /**## ODManagerChangeHelper `class`
133
+ * This is an Open Discord manager change helper.
134
+ *
135
+ * It is used to let the "onChange" event in the `ODManager` class work.
136
+ * You can use this class when extending your own `ODManager`
137
+ */
138
+ export class ODManagerChangeHelper {
139
+ #change: (() => void)|null = null
140
+
141
+ /**Trigger an `onChange()` event in the parent `ODManager` of this class. */
142
+ protected _change(){
143
+ if (this.#change){
144
+ try{
145
+ this.#change()
146
+ }catch(err){
147
+ process.emit("uncaughtException",err)
148
+ throw new ODSystemError("Failed to execute _change() callback!")
149
+ }
150
+ }
151
+ }
152
+ /****(❌ SYSTEM ONLY!!)** Set the callback executed when a value inside this class changes. */
153
+ changed(callback:(() => void)|null){
154
+ this.#change = callback
155
+ }
156
+ }
157
+
158
+ /**## ODManagerData `class`
159
+ * This is Open Discord manager data.
160
+ *
161
+ * It provides a template for all classes that are used in the `ODManager`.
162
+ *
163
+ * There is an `id:ODId` property & also some events used in the manager.
164
+ */
165
+ export class ODManagerData extends ODManagerChangeHelper {
166
+ /**The id of this data. */
167
+ id: ODId
168
+
169
+ constructor(id:ODValidId){
170
+ if (typeof id != "string" && !(id instanceof ODId)) throw new ODSystemError("Invalid constructor parameter => id:ODValidId")
171
+ super()
172
+ this.id = new ODId(id)
173
+ }
174
+ }
175
+
176
+ /**## ODManagerCallback `type`
177
+ * This is a callback for the `onChange` and `onRemove` events in the `ODManager`
178
+ */
179
+ export type ODManagerCallback<DataType extends ODManagerData> = (data:DataType) => void
180
+ /**## ODManagerAddCallback `type`
181
+ * This is a callback for the `onAdd` event in the `ODManager`
182
+ */
183
+ export type ODManagerAddCallback<DataType extends ODManagerData> = (data:DataType, overwritten:boolean) => void
184
+
185
+ /**## ODManager `class`
186
+ * This is an Open Discord manager.
187
+ *
188
+ * It can be used to store & manage classes based on their `ODId`.
189
+ * It is somewhat the same as the default JS `Map()`.
190
+ * You can extend this class when creating your own classes & managers.
191
+ *
192
+ * This class has many useful functions based on `ODId` (add, get, remove, getAll, getFiltered, exists, loopAll, ...)
193
+ */
194
+ export class ODManager<DataType extends ODManagerData> extends ODManagerChangeHelper {
195
+ /**Alias to Open Discord debugger. */
196
+ #debug?: ODDebugger
197
+ /**The message to send when debugging this manager. */
198
+ #debugname?: string
199
+ /**The map storing all data classes in this manager. */
200
+ #data: Map<string,DataType> = new Map()
201
+ /**An array storing all listeners when data is added. */
202
+ #addListeners: ODManagerAddCallback<DataType>[] = []
203
+ /**An array storing all listeners when data has changed. */
204
+ #changeListeners: ODManagerCallback<DataType>[] = []
205
+ /**An array storing all listeners when data is removed. */
206
+ #removeListeners: ODManagerCallback<DataType>[] = []
207
+
208
+ constructor(debug?:ODDebugger, debugname?:string){
209
+ super()
210
+ this.#debug = debug
211
+ this.#debugname = debugname
212
+ }
213
+
214
+ /**Add data to the manager. The `ODId` in the data class will be used as identifier! You can optionally select to overwrite existing data!*/
215
+ add(data:DataType|DataType[], overwrite?:boolean): boolean {
216
+ //repeat same command when data is an array
217
+ if (Array.isArray(data)){
218
+ data.forEach((arrayData) => {
219
+ this.add(arrayData,overwrite)
220
+ })
221
+ return false
222
+ }
223
+
224
+ //add listener for data id change => transfer data within manager
225
+ data.id.changed((oldId,newId) => {
226
+ this.#data.delete(oldId)
227
+ this.#data.set(newId,data)
228
+ })
229
+
230
+ //add data
231
+ let didOverwrite: boolean
232
+ if (this.#data.has(data.id.value)){
233
+ if (!overwrite) throw new ODSystemError("Id '"+data.id.value+"' already exists in "+this.#debugname+" manager. Use 'overwrite:true' to allow overwriting!")
234
+ this.#data.set(data.id.value,data)
235
+ didOverwrite = true
236
+ if (this.#debug) this.#debug.debug("Added new "+this.#debugname+" to manager",[{key:"id",value:data.id.value},{key:"overwrite",value:"true"}])
237
+
238
+ }else{
239
+ this.#data.set(data.id.value,data)
240
+ didOverwrite = false
241
+ if (this.#debug) this.#debug.debug("Added new "+this.#debugname+" to manager",[{key:"id",value:data.id.value},{key:"overwrite",value:"false"}])
242
+
243
+ }
244
+
245
+ //emit change listeners
246
+ data.changed(() => {
247
+ //notify change in upper-manager (because data in this manager changed)
248
+ this._change()
249
+ this.#changeListeners.forEach((cb) => {
250
+ try{
251
+ cb(data)
252
+ }catch(err){
253
+ throw new ODSystemError("Failed to run manager onChange() listener.\n"+err)
254
+ }
255
+ })
256
+ })
257
+
258
+ //emit add listeners
259
+ this.#addListeners.forEach((cb) => {
260
+ try{
261
+ cb(data,didOverwrite)
262
+ }catch(err){
263
+ throw new ODSystemError("Failed to run manager onAdd() listener.\n"+err)
264
+ }
265
+ })
266
+
267
+ //notify change in upper-manager (because data added)
268
+ this._change()
269
+
270
+ return didOverwrite
271
+ }
272
+ /**Get data that matches the `ODId`. Returns the found data.*/
273
+ get(id:ODValidId): DataType|null {
274
+ const newId = new ODId(id)
275
+ const data = this.#data.get(newId.value)
276
+ if (data) return data
277
+ else return null
278
+ }
279
+ /**Remove data that matches the `ODId`. Returns the removed data. */
280
+ remove(id:ODValidId): DataType|null {
281
+ const newId = new ODId(id)
282
+ const data = this.#data.get(newId.value)
283
+
284
+ if (!data){
285
+ if (this.#debug) this.#debug.debug("Removed "+this.#debugname+" from manager",[{key:"id",value:newId.value},{key:"found",value:"false"}])
286
+ return null
287
+ }else{
288
+ this.#data.delete(newId.value)
289
+ if (this.#debug) this.#debug.debug("Removed "+this.#debugname+" from manager",[{key:"id",value:newId.value},{key:"found",value:"true"}])
290
+ }
291
+
292
+ //remove all listeners
293
+ data.id.changed(null)
294
+ data.changed(null)
295
+
296
+ //emit remove listeners
297
+ this.#removeListeners.forEach((cb) => {
298
+ try{
299
+ cb(data)
300
+ }catch(err){
301
+ throw new ODSystemError("Failed to run manager onRemove() listener.\n"+err)
302
+ }
303
+ })
304
+
305
+ //notify change in upper-manager (because data removed)
306
+ this._change()
307
+
308
+ return data
309
+ }
310
+ /**Check if data that matches the `ODId` exists. Returns a boolean. */
311
+ exists(id:ODValidId): boolean {
312
+ const newId = new ODId(id)
313
+ if (this.#data.has(newId.value)) return true
314
+ else return false
315
+ }
316
+ /**Get all data inside this manager*/
317
+ getAll(): DataType[] {
318
+ return Array.from(this.#data.values())
319
+ }
320
+ /**Get all data that matches inside the filter function*/
321
+ getFiltered(predicate:(value:DataType, index:number, array:DataType[]) => unknown): DataType[] {
322
+ return Array.from(this.#data.values()).filter(predicate)
323
+ }
324
+ /**Get all data where the `ODId` matches the provided RegExp. */
325
+ getRegex(regex:RegExp): DataType[] {
326
+ return Array.from(this.#data.values()).filter((data) => regex.test(data.id.value))
327
+ }
328
+ /**Get the length/size/amount of the data inside this manager. */
329
+ getLength(){
330
+ return this.#data.size
331
+ }
332
+ /**Get a list of all the ids inside this manager*/
333
+ getIds(): ODId[] {
334
+ const ids = Array.from(this.#data.keys())
335
+ return ids.map((id) => new ODId(id))
336
+ }
337
+ /**Run an iterator over all data in this manager. This method also supports async-await behaviour!*/
338
+ async loopAll(cb:(data:DataType,id:ODId) => ODPromiseVoid): Promise<void> {
339
+ for (const data of this.getAll()){
340
+ await cb(data,data.id)
341
+ }
342
+ }
343
+ /**Use the Open Discord debugger in this manager for logs*/
344
+ useDebug(debug?:ODDebugger, debugname?:string){
345
+ this.#debug = debug
346
+ this.#debugname = debugname
347
+ }
348
+ /**Listen for when data is added to this manager. */
349
+ onAdd(callback:ODManagerAddCallback<DataType>){
350
+ this.#addListeners.push(callback)
351
+ }
352
+ /**Listen for when data is changed in this manager. */
353
+ onChange(callback:ODManagerCallback<DataType>){
354
+ this.#changeListeners.push(callback)
355
+ }
356
+ /**Listen for when data is removed from this manager. */
357
+ onRemove(callback:ODManagerCallback<DataType>){
358
+ this.#removeListeners.push(callback)
359
+ }
360
+ }
361
+
362
+ /**## ODManagerWithSafety `class`
363
+ * This is an Open Discord safe manager.
364
+ *
365
+ * It functions exactly the same as a normal `ODManager`, but it has 1 function extra!
366
+ * The `getSafe()` function will always return data, because when it doesn't find an id, it returns pre-configured backup data.
367
+ */
368
+ export class ODManagerWithSafety<DataType extends ODManagerData> extends ODManager<DataType> {
369
+ /**The function that creates backup data returned in `getSafe()` when an id is missing in this manager. */
370
+ #backupCreator: () => DataType
371
+ /** Temporary storage for manager debug name. */
372
+ #debugname: string
373
+
374
+ constructor(backupCreator:() => DataType, debug?:ODDebugger, debugname?:string){
375
+ super(debug,debugname)
376
+ this.#backupCreator = backupCreator
377
+ this.#debugname = debugname ?? "unknown"
378
+ }
379
+
380
+ /**Get data that matches the `ODId`. Returns the backup data when not found.
381
+ *
382
+ * ### ⚠️ This should only be used when the data doesn't need to be written/edited
383
+ */
384
+ getSafe(id:ODValidId): DataType {
385
+ const data = super.get(id)
386
+ if (!data){
387
+ process.emit("uncaughtException",new ODSystemError("ODManagerWithSafety:getSafe(\""+id+"\") => Unknown Id => Used backup data ("+this.#debugname+" manager)"))
388
+ return this.#backupCreator()
389
+ }
390
+ else return data
391
+ }
392
+ }
393
+
394
+ /**## ODVersionManager `class`
395
+ * A Open Discord version manager.
396
+ *
397
+ * It is used to manage different `ODVersion`'s from the bot. You will use it to check which version of the bot is used.
398
+ */
399
+ export class ODVersionManager extends ODManager<ODVersion> {
400
+ constructor(){
401
+ super()
402
+ }
403
+ }
404
+
405
+ /**## ODVersion `class`
406
+ * This is an Open Discord version.
407
+ *
408
+ * It has many features like comparing versions & checking if they are compatible.
409
+ *
410
+ * You can use it in your own plugin, but most of the time you will use it to check the Open Discord version!
411
+ */
412
+ export class ODVersion extends ODManagerData {
413
+ /**The first number of the version (example: `v1.2.3` => `1`) */
414
+ primary: number
415
+ /**The second number of the version (example: `v1.2.3` => `2`) */
416
+ secondary: number
417
+ /**The third number of the version (example: `v1.2.3` => `3`) */
418
+ tertiary: number
419
+
420
+ constructor(id:ODValidId, primary:number, secondary:number, tertiary:number){
421
+ super(id)
422
+ if (typeof primary != "number") throw new ODSystemError("Invalid constructor parameter => primary:number")
423
+ if (typeof secondary != "number") throw new ODSystemError("Invalid constructor parameter => secondary:number")
424
+ if (typeof tertiary != "number") throw new ODSystemError("Invalid constructor parameter => tertiary:number")
425
+
426
+ this.primary = primary
427
+ this.secondary = secondary
428
+ this.tertiary = tertiary
429
+ }
430
+
431
+ /**Get the version from a string (also possible with `v` prefix)
432
+ * @example const version = api.ODVersion.fromString("id","v1.2.3") //creates version 1.2.3
433
+ */
434
+ static fromString(id:ODValidId, version:string){
435
+ if (typeof id != "string" && !(id instanceof ODId)) throw new ODSystemError("Invalid function parameter => id:ODValidId")
436
+ if (typeof version != "string") throw new ODSystemError("Invalid function parameter => version:string")
437
+
438
+ const versionCheck = (version.startsWith("v")) ? version.substring(1) : version
439
+ const splittedVersion = versionCheck.split(".")
440
+
441
+ return new this(id,Number(splittedVersion[0]),Number(splittedVersion[1]),Number(splittedVersion[2]))
442
+ }
443
+ /**Get the version as a string (`noprefix:true` => with `v` prefix)
444
+ * @example
445
+ * new api.ODVersion(1,0,0).toString(false) //returns "v1.0.0"
446
+ * new api.ODVersion(1,0,0).toString(true) //returns "1.0.0"
447
+ */
448
+ toString(noprefix?:boolean){
449
+ const prefix = noprefix ? "" : "v"
450
+ return prefix+[this.primary,this.secondary,this.tertiary].join(".")
451
+ }
452
+ /**Compare this version with another version and returns the result: `higher`, `lower` or `equal`
453
+ * @example
454
+ * new api.ODVersion(1,0,0).compare(new api.ODVersion(1,2,0)) //returns "lower"
455
+ * new api.ODVersion(1,3,0).compare(new api.ODVersion(1,2,0)) //returns "higher"
456
+ * new api.ODVersion(1,2,0).compare(new api.ODVersion(1,2,0)) //returns "equal"
457
+ */
458
+ compare(comparator:ODVersion): "higher"|"lower"|"equal" {
459
+ if (!(comparator instanceof ODVersion)) throw new ODSystemError("Invalid function parameter => comparator:ODVersion")
460
+
461
+ if (this.primary < comparator.primary) return "lower"
462
+ else if (this.primary > comparator.primary) return "higher"
463
+ else {
464
+ if (this.secondary < comparator.secondary) return "lower"
465
+ else if (this.secondary > comparator.secondary) return "higher"
466
+ else {
467
+ if (this.tertiary < comparator.tertiary) return "lower"
468
+ else if (this.tertiary > comparator.tertiary) return "higher"
469
+ else return "equal"
470
+ }
471
+ }
472
+ }
473
+ /**Check if this version is included in the list
474
+ * @example
475
+ * const list = [
476
+ * new api.ODVersion(1,0,0),
477
+ * new api.ODVersion(1,0,1),
478
+ * new api.ODVersion(1,0,2)
479
+ * ]
480
+ * new api.ODVersion(1,0,0).compatible(list) //returns true
481
+ * new api.ODVersion(1,0,1).compatible(list) //returns true
482
+ * new api.ODVersion(1,0,3).compatible(list) //returns false
483
+ */
484
+ compatible(list:ODVersion[]): boolean {
485
+ if (!Array.isArray(list)) throw new ODSystemError("Invalid function parameter => list:ODVersion[]")
486
+ if (!list.every((v) => (v instanceof ODVersion))) throw new ODSystemError("Invalid function parameter => list:ODVersion[]")
487
+
488
+ return list.some((v) => {
489
+ return (v.toString() === this.toString())
490
+ })
491
+ }
492
+ /**Check if this version is higher or equal to the provided `requirement`. */
493
+ min(requirement:string|ODVersion){
494
+ if (typeof requirement == "string") requirement = ODVersion.fromString("temp",requirement)
495
+
496
+ //skip when primary version is higher or lower than current one.
497
+ if (this.primary < requirement.primary) return false
498
+ else if (this.primary > requirement.primary) return true
499
+
500
+ //skip when secondary version is higher or lower than current one.
501
+ if (this.secondary < requirement.secondary) return false
502
+ else if (this.secondary > requirement.secondary) return true
503
+
504
+ //skip when tertiary version is higher or lower than current one.
505
+ if (this.tertiary < requirement.tertiary) return false
506
+ else if (this.tertiary > requirement.tertiary) return true
507
+
508
+ return true
509
+ }
510
+ /**Check if this version is lower or equal to the provided `requirement`. */
511
+ max(requirement:string|ODVersion){
512
+ if (typeof requirement == "string") requirement = ODVersion.fromString("temp",requirement)
513
+
514
+ //skip when primary version is higher or lower than current one.
515
+ if (this.primary < requirement.primary) return true
516
+ else if (this.primary > requirement.primary) return false
517
+
518
+ //skip when secondary version is higher or lower than current one.
519
+ if (this.secondary < requirement.secondary) return true
520
+ else if (this.secondary > requirement.secondary) return false
521
+
522
+ //skip when tertiary version is higher or lower than current one.
523
+ if (this.tertiary < requirement.tertiary) return true
524
+ else if (this.tertiary > requirement.tertiary) return false
525
+
526
+ return true
527
+ }
528
+ /**Check if this version is matches the major version (`vX.X`) of the provided `requirement`. */
529
+ major(requirement:string|ODVersion){
530
+ if (typeof requirement == "string") requirement = ODVersion.fromString("temp",requirement)
531
+ return (this.primary == requirement.primary && this.secondary == requirement.secondary)
532
+ }
533
+ /**Check if this version is matches the minor version (`vX.X.X`) of the provided `requirement`. */
534
+ minor(requirement:string|ODVersion){
535
+ if (typeof requirement == "string") requirement = ODVersion.fromString("temp",requirement)
536
+ return (this.primary == requirement.primary && this.secondary == requirement.secondary && this.tertiary == requirement.tertiary)
537
+ }
538
+ }
539
+
540
+ /**## ODVersionMigration `class`
541
+ * This class is used to manage data migration between Open Ticket versions.
542
+ *
543
+ * It shouldn't be used by plugins because this is an internal API feature!
544
+ */
545
+ export class ODVersionMigration {
546
+ /**The version to migrate data to */
547
+ version: ODVersion
548
+ /**The migration function */
549
+ #func: () => void|Promise<void>
550
+ /**The migration function */
551
+ #afterInitFunc: () => void|Promise<void>
552
+
553
+ constructor(version:ODVersion,func:() => void|Promise<void>,afterInitFunc:() => void|Promise<void>){
554
+ this.version = version
555
+ this.#func = func
556
+ this.#afterInitFunc = afterInitFunc
557
+ }
558
+ /**Run this version migration as a plugin. Returns `false` when something goes wrong. */
559
+ async migrate(): Promise<boolean> {
560
+ try{
561
+ await this.#func()
562
+ return true
563
+ }catch(err){
564
+ process.emit("uncaughtException",err)
565
+ return false
566
+ }
567
+ }
568
+ /**Run this version migration as a plugin (after other plugins have loaded). Returns `false` when something goes wrong. */
569
+ async migrateAfterInit(): Promise<boolean> {
570
+ try{
571
+ await this.#afterInitFunc()
572
+ return true
573
+ }catch(err){
574
+ process.emit("uncaughtException",err)
575
+ return false
576
+ }
577
+ }
578
+ }
579
+
580
+ /**## ODHTTPGetRequest `class`
581
+ * This is a class that can help you with creating simple HTTP GET requests.
582
+ *
583
+ * It works using the native node.js fetch() method. You can configure all options in the constructor!
584
+ * @example
585
+ * const request = new api.ODHTTPGetRequest("https://www.example.com/abc.txt",false,{})
586
+ *
587
+ * const result = await request.run()
588
+ * result.body //the response body (string)
589
+ * result.status //the response code (number)
590
+ * result.response //the full response (object)
591
+ */
592
+ export class ODHTTPGetRequest {
593
+ /**The url used in the request */
594
+ url: string
595
+ /**The request config for additional options */
596
+ config: RequestInit
597
+ /**Throw on error OR return http code 500 */
598
+ throwOnError: boolean
599
+
600
+ constructor(main:ODMain,url:string,throwOnError:boolean,config?:RequestInit){
601
+ if (typeof url != "string") throw new ODSystemError("Invalid constructor parameter => url:string")
602
+ if (typeof throwOnError != "boolean") throw new ODSystemError("Invalid constructor parameter => throwOnError:boolean")
603
+ if (typeof config != "undefined" && typeof config != "object") throw new ODSystemError("Invalid constructor parameter => config?:RequestInit")
604
+
605
+ this.url = url
606
+ this.throwOnError = throwOnError
607
+ const newConfig = config ?? {}
608
+ newConfig.method = "GET"
609
+ const userAgent = ((main.project == "openticket") ? "OpenDiscordBots-OpenTicket" : "OpenDiscordBots-OpenModeration") +"/"+(main.versions.get("opendiscord:version")?.toString(true) ?? "<OD:UNKNOWN_VERSION>")
610
+ if (newConfig.headers) Object.assign(newConfig.headers,{"User-Agent":userAgent})
611
+ else newConfig.headers = {"User-Agent":userAgent}
612
+ this.config = newConfig
613
+ }
614
+
615
+ /**Execute the GET request.*/
616
+ run(): Promise<{status:number, body:string, response?:Response}> {
617
+ return new Promise(async (resolve,reject) => {
618
+ try{
619
+ const response = await fetch(this.url,this.config)
620
+ resolve({
621
+ status:response.status,
622
+ body:(await response.text()),
623
+ response:response
624
+ })
625
+ }catch(err){
626
+ if (this.throwOnError) return reject("[OPENTICKET ERROR]: ODHTTPGetRequest => Unknown fetch() error: "+err)
627
+ else return resolve({
628
+ status:500,
629
+ body:"Open Discord Error: Unknown fetch() error: "+err,
630
+ })
631
+ }
632
+ })
633
+ }
634
+ }
635
+
636
+ /**## ODHTTPPostRequest `class`
637
+ * This is a class that can help you with creating simple HTTP POST requests.
638
+ *
639
+ * It works using the native node.js fetch() method. You can configure all options in the constructor!
640
+ * @example
641
+ * const request = new api.ODHTTPPostRequest("https://www.example.com/abc.txt",false,{})
642
+ *
643
+ * const result = await request.run()
644
+ * result.body //the response body (string)
645
+ * result.status //the response code (number)
646
+ * result.response //the full response (object)
647
+ */
648
+ export class ODHTTPPostRequest {
649
+ /**The url used in the request */
650
+ url: string
651
+ /**The request config for additional options */
652
+ config: RequestInit
653
+ /**Throw on error OR return http code 500 */
654
+ throwOnError: boolean
655
+
656
+ constructor(main:ODMain,url:string,throwOnError:boolean,config?:RequestInit){
657
+ if (typeof url != "string") throw new ODSystemError("Invalid constructor parameter => url:string")
658
+ if (typeof throwOnError != "boolean") throw new ODSystemError("Invalid constructor parameter => throwOnError:boolean")
659
+ if (typeof config != "undefined" && typeof config != "object") throw new ODSystemError("Invalid constructor parameter => config?:RequestInit")
660
+
661
+ this.url = url
662
+ this.throwOnError = throwOnError
663
+ const newConfig = config ?? {}
664
+ newConfig.method = "POST"
665
+ const userAgent = ((main.project == "openticket") ? "OpenDiscordBots-OpenTicket" : "OpenDiscordBots-OpenModeration") +"/"+(main.versions.get("opendiscord:version")?.toString(true) ?? "<OD:UNKNOWN_VERSION>")
666
+ if (newConfig.headers) Object.assign(newConfig.headers,{"User-Agent":userAgent})
667
+ else newConfig.headers = {"User-Agent":userAgent}
668
+ this.config = newConfig
669
+ }
670
+
671
+ /**Execute the POST request.*/
672
+ run(): Promise<{status:number, body:string, response?:Response}> {
673
+ return new Promise(async (resolve,reject) => {
674
+ try{
675
+ const response = await fetch(this.url,this.config)
676
+ resolve({
677
+ status:response.status,
678
+ body:(await response.text()),
679
+ response:response
680
+ })
681
+ }catch(err){
682
+ if (this.throwOnError) return reject("[OPENTICKET ERROR]: ODHTTPPostRequest => Unknown fetch() error: "+err)
683
+ else return resolve({
684
+ status:500,
685
+ body:"Open Discord Error: Unknown fetch() error!",
686
+ })
687
+ }
688
+ })
689
+ }
690
+ }
691
+
692
+ /**## ODEnvHelper `class`
693
+ * This is a utility class that helps you with reading the ENV.
694
+ *
695
+ * It has support for the built-in `process.env` & `.env` file
696
+ * @example
697
+ * const envHelper = new api.ODEnvHelper()
698
+ *
699
+ * const variableA = envHelper.getVariable("value-a")
700
+ * const variableB = envHelper.getVariable("value-b","dotenv") //only get from .env
701
+ * const variableA = envHelper.getVariable("value-c","env") //only get from process.env
702
+ */
703
+ export class ODEnvHelper {
704
+ /**All variables found in the `.env` file */
705
+ dotenv: object
706
+ /**All variables found in `process.env` */
707
+ env: object
708
+
709
+ constructor(customEnvPath?:string){
710
+ if (typeof customEnvPath != "undefined" && typeof customEnvPath != "string") throw new ODSystemError("Invalid constructor parameter => customEnvPath?:string")
711
+
712
+ const path = customEnvPath ? customEnvPath : ".env"
713
+ this.dotenv = fs.existsSync(path) ? this.#readDotEnv(fs.readFileSync(path)) : {}
714
+ this.env = process.env
715
+ }
716
+
717
+ /**Get a variable from the env */
718
+ getVariable(name:string,source?:"dotenv"|"env"): any|undefined {
719
+ if (typeof name != "string") throw new ODSystemError("Invalid function parameter => name:string")
720
+ if ((typeof source != "undefined" && typeof source != "string") || (source && !["env","dotenv"].includes(source))) throw new ODSystemError("Invalid function parameter => source:'dotenv'|'env'")
721
+
722
+ if (source == "dotenv"){
723
+ return this.dotenv[name]
724
+ }else if (source == "env"){
725
+ return this.env[name]
726
+ }else{
727
+ //when no source specified => .env has priority over process.env
728
+ if (this.dotenv[name]) return this.dotenv[name]
729
+ else return this.env[name]
730
+ }
731
+ }
732
+
733
+ //THIS CODE IS COPIED FROM THE DODENV-LIB
734
+ //Repo: https://github.com/motdotla/dotenv
735
+ //Source: https://github.com/motdotla/dotenv/blob/master/lib/main.js#L12
736
+ #readDotEnv(src:Buffer){
737
+ const LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg
738
+ const obj = {}
739
+
740
+ // Convert buffer to string
741
+ let lines = src.toString()
742
+
743
+ // Convert line breaks to same format
744
+ lines = lines.replace(/\r\n?/mg, '\n')
745
+
746
+ let match
747
+ while ((match = LINE.exec(lines)) != null) {
748
+ const key = match[1]
749
+
750
+ // Default undefined or null to empty string
751
+ let value = (match[2] || '')
752
+
753
+ // Remove whitespace
754
+ value = value.trim()
755
+
756
+ // Check if double quoted
757
+ const maybeQuote = value[0]
758
+
759
+ // Remove surrounding quotes
760
+ value = value.replace(/^(['"`])([\s\S]*)\1$/mg, '$2')
761
+
762
+ // Expand newlines if double quoted
763
+ if (maybeQuote === '"') {
764
+ value = value.replace(/\\n/g, '\n')
765
+ value = value.replace(/\\r/g, '\r')
766
+ }
767
+
768
+ // Add to object
769
+ obj[key] = value
770
+ }
771
+ return obj
772
+ }
773
+ }
774
+
775
+ /**## ODSystemError `class`
776
+ * A wrapper for the node.js `Error` class that makes the error look better in the console!
777
+ *
778
+ * This wrapper is made for Open Discord system errors! **It can only be used by Open Discord itself!**
779
+ */
780
+ export class ODSystemError extends Error {
781
+ /**This variable gets detected by the error handling system to know how to render it */
782
+ _ODErrorType = "system"
783
+
784
+ /**Create an `ODSystemError` directly from an `Error` class */
785
+ static fromError(err:Error){
786
+ err["_ODErrorType"] = "system"
787
+ return err as ODSystemError
788
+ }
789
+ }
790
+
791
+ /**## ODPluginError `class`
792
+ * A wrapper for the node.js `Error` class that makes the error look better in the console!
793
+ *
794
+ * This wrapper is made for Open Discord plugin errors! **It can only be used by plugins!**
795
+ */
796
+ export class ODPluginError extends Error {
797
+ /**This variable gets detected by the error handling system to know how to render it */
798
+ _ODErrorType = "plugin"
799
+
800
+ /**Create an `ODPluginError` directly from an `Error` class */
801
+ static fromError(err:Error){
802
+ err["_ODErrorType"] = "plugin"
803
+ return err as ODPluginError
804
+ }
805
+ }
806
+
807
+ /**Oh, what could this be `¯\_(ツ)_/¯` */
808
+ export interface ODEasterEggs {
809
+ creator:string,
810
+ translators:string[]
811
+ }