@guildedts/framework
Version:
A framework for creating a Guilded bot.
173 lines • 6.9 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ClientConfigSchema = exports.Client = void 0;
const collection_1 = require("@discordjs/collection");
const fast_glob_1 = __importDefault(require("fast-glob"));
const guilded_ts_1 = __importDefault(require("guilded.ts"));
const commands_1 = __importDefault(require("../handlers/commands"));
const joi_1 = __importDefault(require("joi"));
const fs_1 = require("fs");
const Logger_1 = require("./Logger");
const yaml_1 = require("yaml");
const promises_1 = require("fs/promises");
const path_1 = require("path");
/**
* The main hub for interacting with the Guilded API.
* @example
* // Start the client
* new Client();
* // Start the client in development mode
* new Client({ dev: true });
*/
class Client extends guilded_ts_1.default {
options;
/** The commands that belong to the client. */
commands = new collection_1.Collection();
/** The prefixes per server. */
prefixes = new collection_1.Collection();
/** The config for the client. */
config;
/** The glob pattern for configs. */
configGlob = `**/gtsconfig.{js,ts,json,yml,yaml}`;
/** The glob pattern for command directories. */
commandDirGlob = `**/commands`;
/** The glob pattern for event directories. */
eventDirGlob = `**/events`;
/** The glob pattern for command files. */
commandGlob = `${this.commandDirGlob}/**/*.{js,ts}`;
/** The glob pattern for event files. */
eventGlob = `${this.eventDirGlob}/**/*.{js,ts}`;
/** The options for glob. */
globOptions = {
ignore: ['**/node_modules', '**/*.d.ts'],
onlyFiles: false,
};
/** @param options The options for the client. */
constructor(options = {}) {
super(options);
this.options = options;
this.init();
}
/** Initialize the client. */
async init() {
await this.loadConfig();
await this.loadCommands();
await this.loadEvents();
if (this.options.dev)
this.devMode();
await this.login(this.config.token);
Logger_1.Logger.ready(`Logged in as ${this.user?.name}`);
process.on('uncaughtException', console.log);
}
/** Handle dev mode. */
async devMode() {
let timeout;
const commandDirs = await (0, fast_glob_1.default)(this.commandDirGlob, this.globOptions);
const eventDirs = await (0, fast_glob_1.default)(this.eventDirGlob, this.globOptions);
for (const dirs of [commandDirs, eventDirs])
for (const dir of dirs)
(0, fs_1.watch)(dir, { recursive: true }, () => {
if (!timeout)
dir.endsWith('commands') ? this.loadCommands() : this.loadEvents();
timeout = setTimeout(() => (timeout = undefined), 1000);
});
}
/** Load config. */
async loadConfig() {
const startedTimestamp = Date.now();
Logger_1.Logger.wait('Loading config...');
const path = (await (0, fast_glob_1.default)(this.configGlob, this.globOptions))[0];
if (!path) {
Logger_1.Logger.error('No gtsconfig found');
process.exit(1);
}
const file = await this.import(path);
try {
this.config = await exports.ClientConfigSchema.validateAsync(file.default ?? file);
}
catch (error) {
Logger_1.Logger.error(`Invalid gtsconfig: ${error.message}`);
process.exit(1);
}
Logger_1.Logger.event(`Loaded config from ${path} in ${Date.now() - startedTimestamp}ms`);
}
/** Load commands. */
async loadCommands() {
const startedTimestamp = Date.now();
Logger_1.Logger.wait('Loading commands...');
this.commands.clear();
const paths = await (0, fast_glob_1.default)(this.commandGlob, this.globOptions);
let loadedCommands = 0;
for (const path of paths) {
const command = await this.createStructure(path);
if (!command)
continue;
loadedCommands++;
command.name = command.name ?? (0, path_1.basename)(path, (0, path_1.extname)(path));
this.commands.set(command.name, command);
}
Logger_1.Logger.event(`Loaded ${loadedCommands} commands in ${Date.now() - startedTimestamp}ms`);
}
/** Load events. */
async loadEvents() {
const startedTimestamp = Date.now();
Logger_1.Logger.wait('Loading events...');
this.removeAllListeners();
const paths = await (0, fast_glob_1.default)(this.eventGlob, this.globOptions);
let loadedEvents = 0;
for (const path of paths) {
const event = await this.createStructure(path);
if (!event)
continue;
loadedEvents++;
event.name = event.name ?? (0, path_1.basename)(path, (0, path_1.extname)(path));
this[event.once ? 'once' : 'on'](event.name, event.execute.bind(event));
}
const commandHandler = new commands_1.default(this);
this.on(commandHandler.name, commandHandler.execute.bind(commandHandler));
Logger_1.Logger.event(`Loaded ${loadedEvents} events in ${Date.now() - startedTimestamp}ms`);
}
/**
* Import a module.
* @param path The path to the module.
* @returns The module.
* @example client.import('./path/to/module');
*/
async import(path) {
path = `${process.cwd()}/${path}`;
if (['.yml', '.yaml'].some((ext) => path.endsWith(ext))) {
const raw = await (0, promises_1.readFile)(path, 'utf8');
return (0, yaml_1.parse)(raw);
}
delete require.cache[require.resolve(path)];
return require(path);
}
/**
* Create a structure from a file.
* @param path The path to the file.
* @returns The structure.
* @example client.createStructure('./path/to/file');
*/
async createStructure(path) {
const file = await this.import(path);
return typeof file.default === 'function'
? new file.default(this)
: typeof file === 'function'
? new file()
: undefined;
}
}
exports.Client = Client;
/** The schema for the client config. */
exports.ClientConfigSchema = joi_1.default
.object({
token: joi_1.default.string().required().description('The token for the client.'),
commandCooldown: joi_1.default.number().default(0).description('The default cooldown for commands.'),
prefix: joi_1.default.string().required().description('The default prefix for commands.'),
})
.required()
.unknown(true);
//# sourceMappingURL=Client.js.map