Create initial bot framework (#7)
#1 Reviewed-on: https://gitea.vylpes.xyz/External/card-drop/pulls/7 Co-authored-by: Ethan Lane <ethan@vylpes.com> Co-committed-by: Ethan Lane <ethan@vylpes.com>
This commit is contained in:
parent
cb548898ce
commit
c706737369
35 changed files with 5876 additions and 0 deletions
36
src/bot.ts
Normal file
36
src/bot.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
import * as dotenv from "dotenv";
|
||||
import { CoreClient } from "./client/client";
|
||||
import { IntentsBitField } from "discord.js";
|
||||
import Registry from "./registry";
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const requiredConfigs: string[] = [
|
||||
"BOT_TOKEN",
|
||||
"BOT_VER",
|
||||
"BOT_AUTHOR",
|
||||
"BOT_OWNERID",
|
||||
"BOT_CLIENTID",
|
||||
"DB_HOST",
|
||||
"DB_PORT",
|
||||
"DB_AUTH_USER",
|
||||
"DB_AUTH_PASS",
|
||||
"DB_SYNC",
|
||||
"DB_LOGGING",
|
||||
]
|
||||
|
||||
requiredConfigs.forEach(config => {
|
||||
if (!process.env[config]) {
|
||||
throw `${config} is required in .env`;
|
||||
}
|
||||
});
|
||||
|
||||
const client = new CoreClient([
|
||||
IntentsBitField.Flags.Guilds,
|
||||
IntentsBitField.Flags.GuildMembers,
|
||||
]);
|
||||
|
||||
Registry.RegisterCommands();
|
||||
Registry.RegisterEvents();
|
||||
|
||||
client.start();
|
75
src/client/client.ts
Normal file
75
src/client/client.ts
Normal file
|
@ -0,0 +1,75 @@
|
|||
import { Client } from "discord.js";
|
||||
import * as dotenv from "dotenv";
|
||||
import { EventType } from "../constants/EventType";
|
||||
import ICommandItem from "../contracts/ICommandItem";
|
||||
import IEventItem from "../contracts/IEventItem";
|
||||
import { Command } from "../type/command";
|
||||
|
||||
import { Events } from "./events";
|
||||
import { Util } from "./util";
|
||||
import AppDataSource from "../database/dataSources/appDataSource";
|
||||
|
||||
export class CoreClient extends Client {
|
||||
private static _commandItems: ICommandItem[];
|
||||
private static _eventItems: IEventItem[];
|
||||
|
||||
private _events: Events;
|
||||
private _util: Util;
|
||||
|
||||
public static get commandItems(): ICommandItem[] {
|
||||
return this._commandItems;
|
||||
}
|
||||
|
||||
public static get eventItems(): IEventItem[] {
|
||||
return this._eventItems;
|
||||
}
|
||||
|
||||
constructor(intents: number[]) {
|
||||
super({ intents: intents });
|
||||
dotenv.config();
|
||||
|
||||
CoreClient._commandItems = [];
|
||||
CoreClient._eventItems = [];
|
||||
|
||||
this._events = new Events();
|
||||
this._util = new Util();
|
||||
}
|
||||
|
||||
public async start() {
|
||||
if (!process.env.BOT_TOKEN) {
|
||||
console.error("BOT_TOKEN is not defined in .env");
|
||||
return;
|
||||
}
|
||||
|
||||
await AppDataSource.initialize()
|
||||
.then(() => console.log("Data Source Initialized"))
|
||||
.catch((err) => console.error("Error Initialising Data Source", err));
|
||||
|
||||
super.on("interactionCreate", this._events.onInteractionCreate);
|
||||
super.on("ready", this._events.onReady);
|
||||
|
||||
await super.login(process.env.BOT_TOKEN);
|
||||
|
||||
this._util.loadEvents(this, CoreClient._eventItems);
|
||||
this._util.loadSlashCommands(this);
|
||||
}
|
||||
|
||||
public static RegisterCommand(name: string, command: Command, serverId?: string) {
|
||||
const item: ICommandItem = {
|
||||
Name: name,
|
||||
Command: command,
|
||||
ServerId: serverId,
|
||||
};
|
||||
|
||||
CoreClient._commandItems.push(item);
|
||||
}
|
||||
|
||||
public static RegisterEvent(eventType: EventType, func: Function) {
|
||||
const item: IEventItem = {
|
||||
EventType: eventType,
|
||||
ExecutionFunction: func,
|
||||
};
|
||||
|
||||
CoreClient._eventItems.push(item);
|
||||
}
|
||||
}
|
33
src/client/events.ts
Normal file
33
src/client/events.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import { Interaction } from "discord.js";
|
||||
import ICommandItem from "../contracts/ICommandItem";
|
||||
import { CoreClient } from "./client";
|
||||
|
||||
export class Events {
|
||||
public async onInteractionCreate(interaction: Interaction) {
|
||||
if (!interaction.isChatInputCommand()) return;
|
||||
if (!interaction.guildId) return;
|
||||
|
||||
const item = CoreClient.commandItems.find(x => x.Name == interaction.commandName && !x.ServerId);
|
||||
const itemForServer = CoreClient.commandItems.find(x => x.Name == interaction.commandName && x.ServerId == interaction.guildId);
|
||||
|
||||
let itemToUse: ICommandItem;
|
||||
|
||||
if (!itemForServer) {
|
||||
if (!item) {
|
||||
await interaction.reply('Command not found');
|
||||
return;
|
||||
}
|
||||
|
||||
itemToUse = item;
|
||||
} else {
|
||||
itemToUse = itemForServer;
|
||||
}
|
||||
|
||||
itemToUse.Command.execute(interaction);
|
||||
}
|
||||
|
||||
// Emit when bot is logged in and ready to use
|
||||
public onReady() {
|
||||
console.log("Ready");
|
||||
}
|
||||
}
|
95
src/client/util.ts
Normal file
95
src/client/util.ts
Normal file
|
@ -0,0 +1,95 @@
|
|||
import { Client, REST, Routes, SlashCommandBuilder } from "discord.js";
|
||||
import { EventType } from "../constants/EventType";
|
||||
import IEventItem from "../contracts/IEventItem";
|
||||
import { CoreClient } from "./client";
|
||||
|
||||
export class Util {
|
||||
public loadSlashCommands(client: Client) {
|
||||
const registeredCommands = CoreClient.commandItems;
|
||||
|
||||
const globalCommands = registeredCommands.filter(x => !x.ServerId);
|
||||
const guildCommands = registeredCommands.filter(x => x.ServerId);
|
||||
|
||||
const globalCommandData: SlashCommandBuilder[] = globalCommands
|
||||
.filter(x => x.Command.CommandBuilder)
|
||||
.flatMap(x => x.Command.CommandBuilder);
|
||||
|
||||
const guildIds: string[] = [];
|
||||
|
||||
for (let command of guildCommands) {
|
||||
if (!guildIds.find(x => x == command.ServerId)) {
|
||||
guildIds.push(command.ServerId!);
|
||||
}
|
||||
}
|
||||
|
||||
const rest = new REST({ version: '10' }).setToken(process.env.BOT_TOKEN!);
|
||||
|
||||
rest.put(
|
||||
Routes.applicationCommands(process.env.BOT_CLIENTID!),
|
||||
{
|
||||
body: globalCommandData
|
||||
}
|
||||
);
|
||||
|
||||
for (let guild of guildIds) {
|
||||
const guildCommandData = guildCommands.filter(x => x.ServerId == guild)
|
||||
.filter(x => x.Command.CommandBuilder)
|
||||
.flatMap(x => x.Command.CommandBuilder);
|
||||
|
||||
if (!client.guilds.cache.has(guild)) continue;
|
||||
|
||||
rest.put(
|
||||
Routes.applicationGuildCommands(process.env.BOT_CLIENTID!, guild),
|
||||
{
|
||||
body: guildCommandData
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Load the events
|
||||
loadEvents(client: Client, events: IEventItem[]) {
|
||||
events.forEach((e) => {
|
||||
switch(e.EventType) {
|
||||
case EventType.ChannelCreate:
|
||||
client.on('channelCreate', (channel) => e.ExecutionFunction(channel));
|
||||
break;
|
||||
case EventType.ChannelDelete:
|
||||
client.on('channelDelete', (channel) => e.ExecutionFunction(channel));
|
||||
break;
|
||||
case EventType.ChannelUpdate:
|
||||
client.on('channelUpdate', (channel) => e.ExecutionFunction(channel));
|
||||
break;
|
||||
case EventType.GuildBanAdd:
|
||||
client.on('guildBanAdd', (ban) => e.ExecutionFunction(ban));
|
||||
break;
|
||||
case EventType.GuildBanRemove:
|
||||
client.on('guildBanRemove', (ban) => e.ExecutionFunction(ban));
|
||||
break;
|
||||
case EventType.GuildCreate:
|
||||
client.on('guildCreate', (guild) => e.ExecutionFunction(guild));
|
||||
break;
|
||||
case EventType.GuildMemberAdd:
|
||||
client.on('guildMemberAdd', (member) => e.ExecutionFunction(member));
|
||||
break;
|
||||
case EventType.GuildMemberRemove:
|
||||
client.on('guildMemberRemove', (member) => e.ExecutionFunction(member));
|
||||
break;
|
||||
case EventType.GuildMemberUpdate:
|
||||
client.on('guildMemberUpdate', (oldMember, newMember) => e.ExecutionFunction(oldMember, newMember));
|
||||
break;
|
||||
case EventType.MessageCreate:
|
||||
client.on('messageCreate', (message) => e.ExecutionFunction(message));
|
||||
break;
|
||||
case EventType.MessageDelete:
|
||||
client.on('messageDelete', (message) => e.ExecutionFunction(message));
|
||||
break;
|
||||
case EventType.MessageUpdate:
|
||||
client.on('messageUpdate', (oldMessage, newMessage) => e.ExecutionFunction(oldMessage, newMessage));
|
||||
break;
|
||||
default:
|
||||
console.error('Event not implemented.');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
56
src/commands/about.ts
Normal file
56
src/commands/about.ts
Normal file
|
@ -0,0 +1,56 @@
|
|||
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, CommandInteraction, EmbedBuilder, SlashCommandBuilder } from "discord.js";
|
||||
import EmbedColours from "../constants/EmbedColours";
|
||||
import { Command } from "../type/command";
|
||||
|
||||
export default class About extends Command {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
super.CommandBuilder = new SlashCommandBuilder()
|
||||
.setName('about')
|
||||
.setDescription('About Bot');
|
||||
}
|
||||
|
||||
public override async execute(interaction: CommandInteraction) {
|
||||
const fundingLink = process.env.ABOUT_FUNDING;
|
||||
const repoLink = process.env.ABOUT_REPO;
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor(EmbedColours.Ok)
|
||||
.setTitle("About")
|
||||
.setDescription("Discord Bot made by Vylpes");
|
||||
|
||||
embed.addFields([
|
||||
{
|
||||
name: "Version",
|
||||
value: process.env.BOT_VER!,
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: "Author",
|
||||
value: process.env.BOT_AUTHOR!,
|
||||
inline: true,
|
||||
},
|
||||
]);
|
||||
|
||||
const row = new ActionRowBuilder<ButtonBuilder>();
|
||||
|
||||
if (repoLink) {
|
||||
row.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setURL(repoLink)
|
||||
.setLabel("Repo")
|
||||
.setStyle(ButtonStyle.Link));
|
||||
}
|
||||
|
||||
if (fundingLink) {
|
||||
row.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setURL(fundingLink)
|
||||
.setLabel("Funding")
|
||||
.setStyle(ButtonStyle.Link));
|
||||
}
|
||||
|
||||
await interaction.reply({ embeds: [ embed ], components: row.components.length > 0 ? [ row ] : [] });
|
||||
}
|
||||
}
|
3
src/constants/EmbedColours.ts
Normal file
3
src/constants/EmbedColours.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export default class EmbedColours {
|
||||
public static readonly Ok = 0x3050ba;
|
||||
}
|
15
src/constants/EventType.ts
Normal file
15
src/constants/EventType.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
export enum EventType {
|
||||
ChannelCreate,
|
||||
ChannelDelete,
|
||||
ChannelUpdate,
|
||||
GuildBanAdd,
|
||||
GuildBanRemove,
|
||||
GuildCreate,
|
||||
GuildMemberAdd,
|
||||
GuildMemberRemove,
|
||||
GuildMemberUpdate,
|
||||
MessageCreate,
|
||||
MessageDelete,
|
||||
MessageUpdate,
|
||||
Ready,
|
||||
}
|
59
src/contracts/BaseEntity.ts
Normal file
59
src/contracts/BaseEntity.ts
Normal file
|
@ -0,0 +1,59 @@
|
|||
import { Column, DeepPartial, EntityTarget, PrimaryColumn, ObjectLiteral, FindOptionsWhere } from "typeorm";
|
||||
import { v4 } from "uuid";
|
||||
import AppDataSource from "../database/dataSources/appDataSource";
|
||||
|
||||
export default class BaseEntity {
|
||||
constructor() {
|
||||
this.Id = v4();
|
||||
|
||||
this.WhenCreated = new Date();
|
||||
this.WhenUpdated = new Date();
|
||||
}
|
||||
|
||||
@PrimaryColumn()
|
||||
Id: string;
|
||||
|
||||
@Column()
|
||||
WhenCreated: Date;
|
||||
|
||||
@Column()
|
||||
WhenUpdated: Date;
|
||||
|
||||
public async Save<T extends BaseEntity>(target: EntityTarget<T>, entity: DeepPartial<T>): Promise<void> {
|
||||
this.WhenUpdated = new Date();
|
||||
|
||||
const repository = AppDataSource.getRepository<T>(target);
|
||||
|
||||
await repository.save(entity);
|
||||
}
|
||||
|
||||
public static async Remove<T extends BaseEntity>(target: EntityTarget<T>, entity: T): Promise<void> {
|
||||
const repository = AppDataSource.getRepository<T>(target);
|
||||
|
||||
await repository.remove(entity);
|
||||
}
|
||||
|
||||
public static async FetchAll<T extends BaseEntity>(target: EntityTarget<T>, relations?: string[]): Promise<T[]> {
|
||||
const repository = AppDataSource.getRepository<T>(target);
|
||||
|
||||
const all = await repository.find({ relations: relations || [] });
|
||||
|
||||
return all;
|
||||
}
|
||||
|
||||
public static async FetchOneById<T extends BaseEntity>(target: EntityTarget<T>, id: string, relations?: string[]): Promise<T | null> {
|
||||
const repository = AppDataSource.getRepository<T>(target);
|
||||
|
||||
const single = await repository.findOne({ where: ({ Id: id } as FindOptionsWhere<T>), relations: relations || {} });
|
||||
|
||||
return single;
|
||||
}
|
||||
|
||||
public static async Any<T extends ObjectLiteral>(target: EntityTarget<T>): Promise<boolean> {
|
||||
const repository = AppDataSource.getRepository<T>(target);
|
||||
|
||||
const any = await repository.find();
|
||||
|
||||
return any.length > 0;
|
||||
}
|
||||
}
|
4
src/contracts/IBaseResponse.ts
Normal file
4
src/contracts/IBaseResponse.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export interface IBaseResponse {
|
||||
valid: boolean;
|
||||
message?: string;
|
||||
}
|
7
src/contracts/ICommandItem.ts
Normal file
7
src/contracts/ICommandItem.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { Command } from "../type/command";
|
||||
|
||||
export default interface ICommandItem {
|
||||
Name: string,
|
||||
Command: Command,
|
||||
ServerId?: string,
|
||||
}
|
7
src/contracts/IEventItem.ts
Normal file
7
src/contracts/IEventItem.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
|
||||
import { EventType } from "../constants/EventType";
|
||||
|
||||
export default interface IEventItem {
|
||||
EventType: EventType,
|
||||
ExecutionFunction: Function,
|
||||
}
|
26
src/database/dataSources/appDataSource.ts
Normal file
26
src/database/dataSources/appDataSource.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { DataSource } from "typeorm";
|
||||
import * as dotenv from "dotenv";
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const AppDataSource = new DataSource({
|
||||
type: "mysql",
|
||||
host: process.env.DB_HOST,
|
||||
port: Number(process.env.DB_PORT),
|
||||
username: process.env.DB_AUTH_USER,
|
||||
password: process.env.DB_AUTH_PASS,
|
||||
database: process.env.DB_NAME,
|
||||
synchronize: process.env.DB_SYNC == "true",
|
||||
logging: process.env.DB_LOGGING == "true",
|
||||
entities: [
|
||||
"dist/database/entities/**/*.js",
|
||||
],
|
||||
migrations: [
|
||||
"dist/database/migrations/**/*.js",
|
||||
],
|
||||
subscribers: [
|
||||
"dist/database/subscribers/**/*.js",
|
||||
],
|
||||
});
|
||||
|
||||
export default AppDataSource;
|
0
src/database/entities/.gitkeep
Normal file
0
src/database/entities/.gitkeep
Normal file
0
src/database/migrations/.gitkeep
Normal file
0
src/database/migrations/.gitkeep
Normal file
20
src/helpers/MigrationHelper.ts
Normal file
20
src/helpers/MigrationHelper.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { readFileSync } from "fs";
|
||||
import { QueryRunner } from "typeorm";
|
||||
|
||||
export default class MigrationHelper {
|
||||
public static Up(migrationName: string, version: string, queryFiles: string[], queryRunner: QueryRunner) {
|
||||
for (let path of queryFiles) {
|
||||
const query = readFileSync(`${process.cwd()}/database/${version}/${migrationName}/Up/${path}.sql`).toString();
|
||||
|
||||
queryRunner.query(query);
|
||||
}
|
||||
}
|
||||
|
||||
public static Down(migrationName: string, version: string, queryFiles: string[], queryRunner: QueryRunner) {
|
||||
for (let path of queryFiles) {
|
||||
const query = readFileSync(`${process.cwd()}/database/${version}/${migrationName}/Down/${path}.sql`).toString();
|
||||
|
||||
queryRunner.query(query);
|
||||
}
|
||||
}
|
||||
}
|
42
src/helpers/StringTools.ts
Normal file
42
src/helpers/StringTools.ts
Normal file
|
@ -0,0 +1,42 @@
|
|||
export default class StringTools {
|
||||
public static Capitalise(str: string): string {
|
||||
const words = str.split(" ");
|
||||
let result: string[] = [];
|
||||
|
||||
words.forEach(word => {
|
||||
const firstLetter = word.substring(0, 1).toUpperCase();
|
||||
const rest = word.substring(1);
|
||||
|
||||
result.push(firstLetter + rest);
|
||||
});
|
||||
|
||||
return result.join(" ");
|
||||
}
|
||||
|
||||
public static CapitaliseArray(str: string[]): string[] {
|
||||
const res: string[] = [];
|
||||
|
||||
str.forEach(s => {
|
||||
res.push(StringTools.Capitalise(s));
|
||||
});
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public static RandomString(length: number) {
|
||||
let result = "";
|
||||
|
||||
const characters = 'abcdefghkmnpqrstuvwxyz23456789';
|
||||
const charactersLength = characters.length;
|
||||
|
||||
for ( var i = 0; i < length; i++ ) {
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static ReplaceAll(str: string, find: string, replace: string) {
|
||||
return str.replace(new RegExp(find, 'g'), replace);
|
||||
}
|
||||
}
|
121
src/helpers/TimeLengthInput.ts
Normal file
121
src/helpers/TimeLengthInput.ts
Normal file
|
@ -0,0 +1,121 @@
|
|||
import StringTools from "./StringTools";
|
||||
|
||||
export default class TimeLengthInput {
|
||||
public readonly value: string;
|
||||
|
||||
constructor(input: string) {
|
||||
this.value = StringTools.ReplaceAll(input, ',', '');
|
||||
}
|
||||
|
||||
public GetDays(): number {
|
||||
return this.GetValue('d');
|
||||
}
|
||||
|
||||
public GetHours(): number {
|
||||
return this.GetValue('h');
|
||||
}
|
||||
|
||||
public GetMinutes(): number {
|
||||
return this.GetValue('m');
|
||||
}
|
||||
|
||||
public GetSeconds(): number {
|
||||
return this.GetValue('s');
|
||||
}
|
||||
|
||||
public GetMilliseconds(): number {
|
||||
const days = this.GetDays();
|
||||
const hours = this.GetHours();
|
||||
const minutes = this.GetMinutes();
|
||||
const seconds = this.GetSeconds();
|
||||
|
||||
let milliseconds = 0;
|
||||
|
||||
milliseconds += seconds * 1000;
|
||||
milliseconds += minutes * 60 * 1000;
|
||||
milliseconds += hours * 60 * 60 * 1000;
|
||||
milliseconds += days * 24 * 60 * 60 * 1000;
|
||||
|
||||
return milliseconds;
|
||||
}
|
||||
|
||||
public GetDateFromNow(): Date {
|
||||
const now = Date.now();
|
||||
|
||||
const dateFromNow = now
|
||||
+ (1000 * this.GetSeconds())
|
||||
+ (1000 * 60 * this.GetMinutes())
|
||||
+ (1000 * 60 * 60 * this.GetHours())
|
||||
+ (1000 * 60 * 60 * 24 * this.GetDays());
|
||||
|
||||
return new Date(dateFromNow);
|
||||
}
|
||||
|
||||
public GetLength(): string {
|
||||
const days = this.GetDays();
|
||||
const hours = this.GetHours();
|
||||
const minutes = this.GetMinutes();
|
||||
const seconds = this.GetSeconds();
|
||||
|
||||
const value = [];
|
||||
|
||||
if (days) {
|
||||
value.push(`${days} days`);
|
||||
}
|
||||
|
||||
if (hours) {
|
||||
value.push(`${hours} hours`);
|
||||
}
|
||||
|
||||
if (minutes) {
|
||||
value.push(`${minutes} minutes`);
|
||||
}
|
||||
|
||||
if (seconds) {
|
||||
value.push(`${seconds} seconds`);
|
||||
}
|
||||
|
||||
return value.join(", ");
|
||||
}
|
||||
|
||||
public GetLengthShort(): string {
|
||||
const days = this.GetDays();
|
||||
const hours = this.GetHours();
|
||||
const minutes = this.GetMinutes();
|
||||
const seconds = this.GetSeconds();
|
||||
|
||||
const value = [];
|
||||
|
||||
if (days) {
|
||||
value.push(`${days}d`);
|
||||
}
|
||||
|
||||
if (hours) {
|
||||
value.push(`${hours}h`);
|
||||
}
|
||||
|
||||
if (minutes) {
|
||||
value.push(`${minutes}m`);
|
||||
}
|
||||
|
||||
if (seconds) {
|
||||
value.push(`${seconds}s`);
|
||||
}
|
||||
|
||||
return value.join(" ");
|
||||
}
|
||||
|
||||
private GetValue(designation: string): number {
|
||||
const valueSplit = this.value.split(' ');
|
||||
|
||||
const desString = valueSplit.find(x => x.charAt(x.length - 1) == designation);
|
||||
|
||||
if (!desString) return 0;
|
||||
|
||||
const desNumber = Number(desString.substring(0, desString.length - 1));
|
||||
|
||||
if (!desNumber) return 0;
|
||||
|
||||
return desNumber;
|
||||
}
|
||||
}
|
13
src/registry.ts
Normal file
13
src/registry.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { CoreClient } from "./client/client";
|
||||
|
||||
import About from "./commands/about";
|
||||
|
||||
export default class Registry {
|
||||
public static RegisterCommands() {
|
||||
CoreClient.RegisterCommand('about', new About());
|
||||
}
|
||||
|
||||
public static RegisterEvents() {
|
||||
|
||||
}
|
||||
}
|
9
src/type/command.ts
Normal file
9
src/type/command.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import { CommandInteraction } from "discord.js";
|
||||
|
||||
export class Command {
|
||||
public CommandBuilder: any;
|
||||
|
||||
public execute(interaction: CommandInteraction) {
|
||||
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue