UNPKG

@guildedts/framework

Version:

A framework for creating a Guilded bot.

173 lines 6.9 kB
"use strict"; 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