Version Estable

This commit is contained in:
2025-09-17 13:33:10 -05:00
commit bf6a7e3024
39 changed files with 2537 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
import { REST } from "discord.js";
// @ts-ignore
import { Routes } from "discord-api-types/v10";
import { commands } from "../loader";
export async function registeringCommands(): Promise<void> {
const commandsToRegister: any[] = [];
// Recorremos la Collection que ya cargó loadCommands()
for (const [name, cmd] of commands) {
if (cmd.type === "slash") {
commandsToRegister.push({
name: cmd.name,
description: cmd.description ?? "Sin descripción",
type: 1, // CHAT_INPUT
options: cmd.options ?? []
});
console.log(`✅ Preparado para registrar: ${cmd.name}`);
}
}
const rest = new REST().setToken(process.env.TOKEN ?? "");
try {
console.log(`🚀 Registrando ${commandsToRegister.length} comandos slash...`);
const data: any = await rest.put(
Routes.applicationGuildCommands(
process.env.CLIENT!,
process.env.guildTest!
),
{ body: commandsToRegister }
);
console.log(`${data.length} comandos registrados correctamente.`);
} catch (error) {
console.error("❌ Error registrando comandos:", error);
}
}

49
src/core/client.ts Normal file
View File

@@ -0,0 +1,49 @@
// @ts-ignore
import { Client, GatewayIntentBits } from 'discord.js';
// 1. Importa PrismaClient
// @ts-ignore
import { PrismaClient } from '@prisma/client';
process.loadEnvFile();
class Amayo extends Client {
public key: string;
// 2. Declara la propiedad prisma
public prisma: PrismaClient;
constructor() {
super({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMembers,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
GatewayIntentBits.GuildMessageTyping
],
rest: {
retries: 10
}
});
this.key = process.env.TOKEN ?? '';
// 3. Instancia PrismaClient en el constructor
this.prisma = new PrismaClient();
}
async play () {
if(!this.key) {
return console.error('No key provided');
} else {
// Ejemplo de cómo usarías prisma antes de iniciar sesión
try {
await this.prisma.$connect();
console.log('Successfully connected to the database.');
await this.login(this.key);
} catch (error) {
console.error('Failed to connect to the database:', error);
}
}
}
}
export default Amayo;

49
src/core/components.ts Normal file
View File

@@ -0,0 +1,49 @@
import * as fs from "node:fs";
import * as path from "node:path";
import { Collection } from "discord.js";
export const buttons: Collection<string, any> = new Collection<string, any>();
export const modals = new Collection<string, any>();
export const selectmenus = new Collection<string, any>();
export const contextmenus = new Collection<string, any>();
export function loadComponents(dir: string = path.join(__dirname, "..", "components")) {
const files = fs.readdirSync(dir);
for (const file of files) {
const fullPath = path.join(dir, file);
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
loadComponents(fullPath); // recursivo
continue;
}
if (!file.endsWith(".ts") && !file.endsWith(".js")) continue;
const imported = require(fullPath);
const component = imported.default ?? imported;
if (!component?.customId) {
console.warn(`⚠️ Archivo ignorado: ${file} (no tiene "customId")`);
continue;
}
// Detectamos el tipo según la carpeta en la que está
if (fullPath.includes("buttons")) {
buttons.set(component.customId, component);
console.log(`🔘 Botón cargado: ${component.customId}`);
} else if (fullPath.includes("modals")) {
modals.set(component.customId, component);
console.log(`📄 Modal cargado: ${component.customId}`);
} else if (fullPath.includes("selectmenus")) {
selectmenus.set(component.customId, component);
console.log(`📜 SelectMenu cargado: ${component.customId}`);
} else if (fullPath.includes("contextmenu")) {
contextmenus.set(component.customId, component);
console.log(`📑 ContextMenu cargado: ${component.customId}`);
} else {
console.log(`⚠️ Componente desconocido: ${component.customId}`);
}
}
}

12
src/core/lib/vars.ts Normal file
View File

@@ -0,0 +1,12 @@
import {Guild, User} from "discord.js";
export async function replaceVars(text: string, user: User | undefined, guild:
Guild | undefined, stats: any) {
if(!text) return;
return text
.replace(/(user.name)/g, user!.username ?? '')
.replace(/(user.id)/g, user!.id ?? '')
.replace(/(user.mention)/g, `<@${user!.id}>`)
.replace(/(user.avatar)/g, user!.displayAvatarURL({ forceStatic: false }))
}

43
src/core/loader.ts Normal file
View File

@@ -0,0 +1,43 @@
import * as fs from "node:fs";
import path from "node:path";
import { Collection } from "discord.js";
export const commands = new Collection<string, any>();
export function loadCommands(dir: string = path.join(__dirname, '..', 'commands')) {
const files = fs.readdirSync(dir);
for (const file of files) {
const fullPath = path.join(dir, file);
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
loadCommands(fullPath); // recursivo
continue;
}
if (!file.endsWith('.ts')) continue;
const imported = require(fullPath);
const command = imported.command ?? imported.default ?? imported;
if (!command?.data?.name && !command?.name) {
console.warn(`⚠️ Archivo ignorado: ${file} (no es un comando válido)`);
continue;
}
const name = command.data?.name ?? command.name;
console.log(`📦 Loading command: ${name}`);
// @ts-ignore
commands.set(name, command);
if (command.aliases?.length) {
for (const alias of command.aliases) {
commands.set(alias, command);
}
}
console.log(`✅ Cargado comando: ${name}`);
}
}

32
src/core/loaderEvents.ts Normal file
View File

@@ -0,0 +1,32 @@
import { bot } from "../main";
import path from "node:path";
import * as fs from "node:fs";
export function loadEvents(dir: string = path.join(__dirname, "../events")) {
const files = fs.readdirSync(dir);
for (const file of files) {
const fullPath = path.join(dir, file);
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
loadEvents(fullPath); // recursión para subcarpetas
continue;
}
if (!file.endsWith(".ts") && !file.endsWith(".js")) continue;
const imported = require(fullPath);
const event = imported.default ?? imported;
if (!event?.name || !event?.execute) continue;
if (event.once) {
bot.once(event.name, (...args: any[]) => event.execute(...args));
} else {
bot.on(event.name, (...args: any[]) => event.execute(...args));
}
console.log(`Evento cargado: ${event.name}`);
}
}

13
src/core/redis.ts Normal file
View File

@@ -0,0 +1,13 @@
import { createClient } from "redis";
export const redis = createClient({
url: process.env.REDIS_URL,
})
redis.on("error", (err: any) => console.error("Redis error:", err));
redis.on("connect", () => console.log("✅ Conectado a Redis"));
redis.on("reconnecting", () => console.warn("♻️ Reintentando conexión Redis"));
export async function redisConnect () {
if (!redis.isOpen) await redis.connect();
}

View File

@@ -0,0 +1,19 @@
import type {ChatInputCommandInteraction, Client, Message} from "discord.js";
import Amayo from "../client";
export interface CommandMessage {
name: string;
type: 'message';
aliases?: string[];
cooldown?: number;
run: (message: Message, args: string[], client: Amayo) => Promise<void>;
}
export interface CommandSlash {
name: string;
description: string;
type: 'slash';
options?: string[];
cooldown?: number;
run: (i: ChatInputCommandInteraction, client: Client) => Promise<void>;
}

View File

@@ -0,0 +1,7 @@
import type {ButtonInteraction} from "discord.js";
export interface button {
customId: string;
run: (interaction: ButtonInteraction) => Promise<void>;
}