From bf6a7e3024e45f767deb9d3417efe192da6a7435 Mon Sep 17 00:00:00 2001 From: shnimlz Date: Wed, 17 Sep 2025 13:33:10 -0500 Subject: [PATCH] Version Estable --- .gitignore | 5 + .idea/.gitignore | 8 + .idea/amayo.iml | 12 + .idea/jsLibraryMappings.xml | 6 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + .npmrc | 1 + package-lock.json | 989 ++++++++++++++++++ package.json | 25 + prisma/dev.db | Bin 0 -> 69632 bytes .../20250917001309_modals/migration.sql | 62 ++ .../20250917002041_modals/migration.sql | 33 + .../20250917044008_modals/migration.sql | 13 + prisma/migrations/migration_lock.toml | 3 + prisma/schema.prisma | 133 +++ src/commands/messages/alliaces/createEmbed.ts | 292 ++++++ src/commands/messages/alliaces/editEmbed.ts | 276 +++++ src/commands/messages/alliaces/embedDelete.ts | 34 + src/commands/messages/alliaces/embedList.ts | 75 ++ src/commands/messages/net/ping.ts | 11 + src/commands/messages/others/embedtested.ts | 45 + .../messages/settings-server/settings.ts | 51 + src/commands/splashcmd/net/ping.ts | 12 + src/components/buttons/prefixSettings.ts | 22 + src/components/modals/prefixSettingsModal.ts | 10 + src/core/api/discordAPI.ts | 41 + src/core/client.ts | 49 + src/core/components.ts | 49 + src/core/lib/vars.ts | 12 + src/core/loader.ts | 43 + src/core/loaderEvents.ts | 32 + src/core/redis.ts | 13 + src/core/types/commands.ts | 19 + src/core/types/components.ts | 7 + src/events/interactionCreate.ts | 53 + src/events/messageCreate.ts | 40 + src/events/ready.ts | 6 + src/main.ts | 28 + tsconfig.json | 13 + 39 files changed, 2537 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/amayo.iml create mode 100644 .idea/jsLibraryMappings.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 .npmrc create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 prisma/dev.db create mode 100644 prisma/migrations/20250917001309_modals/migration.sql create mode 100644 prisma/migrations/20250917002041_modals/migration.sql create mode 100644 prisma/migrations/20250917044008_modals/migration.sql create mode 100644 prisma/migrations/migration_lock.toml create mode 100644 prisma/schema.prisma create mode 100644 src/commands/messages/alliaces/createEmbed.ts create mode 100644 src/commands/messages/alliaces/editEmbed.ts create mode 100644 src/commands/messages/alliaces/embedDelete.ts create mode 100644 src/commands/messages/alliaces/embedList.ts create mode 100644 src/commands/messages/net/ping.ts create mode 100644 src/commands/messages/others/embedtested.ts create mode 100644 src/commands/messages/settings-server/settings.ts create mode 100644 src/commands/splashcmd/net/ping.ts create mode 100644 src/components/buttons/prefixSettings.ts create mode 100644 src/components/modals/prefixSettingsModal.ts create mode 100644 src/core/api/discordAPI.ts create mode 100644 src/core/client.ts create mode 100644 src/core/components.ts create mode 100644 src/core/lib/vars.ts create mode 100644 src/core/loader.ts create mode 100644 src/core/loaderEvents.ts create mode 100644 src/core/redis.ts create mode 100644 src/core/types/commands.ts create mode 100644 src/core/types/components.ts create mode 100644 src/events/interactionCreate.ts create mode 100644 src/events/messageCreate.ts create mode 100644 src/events/ready.ts create mode 100644 src/main.ts create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..126419d --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +node_modules +# Keep environment variables out of version control +.env + +/src/generated/prisma diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/amayo.iml b/.idea/amayo.iml new file mode 100644 index 0000000..24643cc --- /dev/null +++ b/.idea/amayo.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml new file mode 100644 index 0000000..d23208f --- /dev/null +++ b/.idea/jsLibraryMappings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..7af7187 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..449691b --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +save-exact=true \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..85ec1ec --- /dev/null +++ b/package-lock.json @@ -0,0 +1,989 @@ +{ + "name": "amayo", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "amayo", + "version": "0.0.1", + "license": "ISC", + "dependencies": { + "@prisma/client": "6.16.2", + "discord-api-types": "0.38.24", + "discord.js": "14.22.1", + "prisma": "6.16.2", + "redis": "5.8.2" + }, + "devDependencies": { + "@types/node": "24.3.1", + "ts-node": "10.9.2", + "typescript": "5.9.2" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@discordjs/builders": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.11.3.tgz", + "integrity": "sha512-p3kf5eV49CJiRTfhtutUCeivSyQ/l2JlKodW1ZquRwwvlOWmG9+6jFShX6x8rUiYhnP6wKI96rgN/SXMy5e5aw==", + "license": "Apache-2.0", + "dependencies": { + "@discordjs/formatters": "^0.6.1", + "@discordjs/util": "^1.1.1", + "@sapphire/shapeshift": "^4.0.0", + "discord-api-types": "^0.38.16", + "fast-deep-equal": "^3.1.3", + "ts-mixer": "^6.0.4", + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=16.11.0" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@discordjs/collection": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz", + "integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/formatters": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.6.1.tgz", + "integrity": "sha512-5cnX+tASiPCqCWtFcFslxBVUaCetB0thvM/JyavhbXInP1HJIEU+Qv/zMrnuwSsX3yWH2lVXNJZeDK3EiP4HHg==", + "license": "Apache-2.0", + "dependencies": { + "discord-api-types": "^0.38.1" + }, + "engines": { + "node": ">=16.11.0" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@discordjs/rest": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.6.0.tgz", + "integrity": "sha512-RDYrhmpB7mTvmCKcpj+pc5k7POKszS4E2O9TYc+U+Y4iaCP+r910QdO43qmpOja8LRr1RJ0b3U+CqVsnPqzf4w==", + "license": "Apache-2.0", + "dependencies": { + "@discordjs/collection": "^2.1.1", + "@discordjs/util": "^1.1.1", + "@sapphire/async-queue": "^1.5.3", + "@sapphire/snowflake": "^3.5.3", + "@vladfrangu/async_event_emitter": "^2.4.6", + "discord-api-types": "^0.38.16", + "magic-bytes.js": "^1.10.0", + "tslib": "^2.6.3", + "undici": "6.21.3" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@discordjs/rest/node_modules/@discordjs/collection": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.1.1.tgz", + "integrity": "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg==", + "license": "Apache-2.0", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@discordjs/util": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.1.1.tgz", + "integrity": "sha512-eddz6UnOBEB1oITPinyrB2Pttej49M9FZQY8NxgEvc3tq6ZICZ19m70RsmzRdDHk80O9NoYN/25AqJl8vPVf/g==", + "license": "Apache-2.0", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@discordjs/ws": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.2.3.tgz", + "integrity": "sha512-wPlQDxEmlDg5IxhJPuxXr3Vy9AjYq5xCvFWGJyD7w7Np8ZGu+Mc+97LCoEc/+AYCo2IDpKioiH0/c/mj5ZR9Uw==", + "license": "Apache-2.0", + "dependencies": { + "@discordjs/collection": "^2.1.0", + "@discordjs/rest": "^2.5.1", + "@discordjs/util": "^1.1.0", + "@sapphire/async-queue": "^1.5.2", + "@types/ws": "^8.5.10", + "@vladfrangu/async_event_emitter": "^2.2.4", + "discord-api-types": "^0.38.1", + "tslib": "^2.6.2", + "ws": "^8.17.0" + }, + "engines": { + "node": ">=16.11.0" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@discordjs/ws/node_modules/@discordjs/collection": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.1.1.tgz", + "integrity": "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg==", + "license": "Apache-2.0", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@prisma/client": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.16.2.tgz", + "integrity": "sha512-E00PxBcalMfYO/TWnXobBVUai6eW/g5OsifWQsQDzJYm7yaY+IRLo7ZLsaefi0QkTpxfuhFcQ/w180i6kX3iJw==", + "hasInstallScript": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "prisma": "*", + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@prisma/config": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.16.2.tgz", + "integrity": "sha512-mKXSUrcqXj0LXWPmJsK2s3p9PN+aoAbyMx7m5E1v1FufofR1ZpPoIArjjzOIm+bJRLLvYftoNYLx1tbHgF9/yg==", + "license": "Apache-2.0", + "dependencies": { + "c12": "3.1.0", + "deepmerge-ts": "7.1.5", + "effect": "3.16.12", + "empathic": "2.0.0" + } + }, + "node_modules/@prisma/debug": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.16.2.tgz", + "integrity": "sha512-bo4/gA/HVV6u8YK2uY6glhNsJ7r+k/i5iQ9ny/3q5bt9ijCj7WMPUwfTKPvtEgLP+/r26Z686ly11hhcLiQ8zA==", + "license": "Apache-2.0" + }, + "node_modules/@prisma/engines": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.16.2.tgz", + "integrity": "sha512-7yf3AjfPUgsg/l7JSu1iEhsmZZ/YE00yURPjTikqm2z4btM0bCl2coFtTGfeSOWbQMmq45Jab+53yGUIAT1sjA==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.16.2", + "@prisma/engines-version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", + "@prisma/fetch-engine": "6.16.2", + "@prisma/get-platform": "6.16.2" + } + }, + "node_modules/@prisma/engines-version": { + "version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43.tgz", + "integrity": "sha512-ThvlDaKIVrnrv97ujNFDYiQbeMQpLa0O86HFA2mNoip4mtFqM7U5GSz2ie1i2xByZtvPztJlNRgPsXGeM/kqAA==", + "license": "Apache-2.0" + }, + "node_modules/@prisma/fetch-engine": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.16.2.tgz", + "integrity": "sha512-wPnZ8DMRqpgzye758ZvfAMiNJRuYpz+rhgEBZi60ZqDIgOU2694oJxiuu3GKFeYeR/hXxso4/2oBC243t/whxQ==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.16.2", + "@prisma/engines-version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", + "@prisma/get-platform": "6.16.2" + } + }, + "node_modules/@prisma/get-platform": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.16.2.tgz", + "integrity": "sha512-U/P36Uke5wS7r1+omtAgJpEB94tlT4SdlgaeTc6HVTTT93pXj7zZ+B/cZnmnvjcNPfWddgoDx8RLjmQwqGDYyA==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.16.2" + } + }, + "node_modules/@redis/bloom": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-5.8.2.tgz", + "integrity": "sha512-855DR0ChetZLarblio5eM0yLwxA9Dqq50t8StXKp5bAtLT0G+rZ+eRzzqxl37sPqQKjUudSYypz55o6nNhbz0A==", + "license": "MIT", + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@redis/client": "^5.8.2" + } + }, + "node_modules/@redis/client": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-5.8.2.tgz", + "integrity": "sha512-WtMScno3+eBpTac1Uav2zugXEoXqaU23YznwvFgkPwBQVwEHTDgOG7uEAObtZ/Nyn8SmAMbqkEubJaMOvnqdsQ==", + "license": "MIT", + "dependencies": { + "cluster-key-slot": "1.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@redis/json": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-5.8.2.tgz", + "integrity": "sha512-uxpVfas3I0LccBX9rIfDgJ0dBrUa3+0Gc8sEwmQQH0vHi7C1Rx1Qn8Nv1QWz5bohoeIXMICFZRcyDONvum2l/w==", + "license": "MIT", + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@redis/client": "^5.8.2" + } + }, + "node_modules/@redis/search": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-5.8.2.tgz", + "integrity": "sha512-cNv7HlgayavCBXqPXgaS97DRPVWFznuzsAmmuemi2TMCx5scwLiP50TeZvUS06h/MG96YNPe6A0Zt57yayfxwA==", + "license": "MIT", + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@redis/client": "^5.8.2" + } + }, + "node_modules/@redis/time-series": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-5.8.2.tgz", + "integrity": "sha512-g2NlHM07fK8H4k+613NBsk3y70R2JIM2dPMSkhIjl2Z17SYvaYKdusz85d7VYOrZBWtDrHV/WD2E3vGu+zni8A==", + "license": "MIT", + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@redis/client": "^5.8.2" + } + }, + "node_modules/@sapphire/async-queue": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.5.tgz", + "integrity": "sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg==", + "license": "MIT", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@sapphire/shapeshift": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-4.0.0.tgz", + "integrity": "sha512-d9dUmWVA7MMiKobL3VpLF8P2aeanRTu6ypG2OIaEv/ZHH/SUQ2iHOVyi5wAPjQ+HmnMuL0whK9ez8I/raWbtIg==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=v16" + } + }, + "node_modules/@sapphire/snowflake": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.3.tgz", + "integrity": "sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ==", + "license": "MIT", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "license": "MIT" + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.3.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.1.tgz", + "integrity": "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.10.0" + } + }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@vladfrangu/async_event_emitter": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.4.6.tgz", + "integrity": "sha512-RaI5qZo6D2CVS6sTHFKg1v5Ohq/+Bo2LZ5gzUEwZ/WkHhwtGTCB/sVLw8ijOkAUxasZ+WshN/Rzj4ywsABJ5ZA==", + "license": "MIT", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/c12": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz", + "integrity": "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==", + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.3", + "confbox": "^0.2.2", + "defu": "^6.1.4", + "dotenv": "^16.6.1", + "exsolve": "^1.0.7", + "giget": "^2.0.0", + "jiti": "^2.4.2", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^1.0.0", + "pkg-types": "^2.2.0", + "rc9": "^2.1.2" + }, + "peerDependencies": { + "magicast": "^0.3.5" + }, + "peerDependenciesMeta": { + "magicast": { + "optional": true + } + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "license": "MIT", + "dependencies": { + "consola": "^3.2.3" + } + }, + "node_modules/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge-ts": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", + "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "license": "MIT" + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "license": "MIT" + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/discord-api-types": { + "version": "0.38.24", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.38.24.tgz", + "integrity": "sha512-P7/DkcFIiIoaBogStnhhcGRX7KR+gIFp0SpmwsZUIM0bgDkYMEUx+8l+t3quYc/KSgg92wvE9w/4mabO57EMug==", + "license": "MIT", + "workspaces": [ + "scripts/actions/documentation" + ] + }, + "node_modules/discord.js": { + "version": "14.22.1", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.22.1.tgz", + "integrity": "sha512-3k+Kisd/v570Jr68A1kNs7qVhNehDwDJAPe4DZ2Syt+/zobf9zEcuYFvsfIaAOgCa0BiHMfOOKQY4eYINl0z7w==", + "license": "Apache-2.0", + "dependencies": { + "@discordjs/builders": "^1.11.2", + "@discordjs/collection": "1.5.3", + "@discordjs/formatters": "^0.6.1", + "@discordjs/rest": "^2.6.0", + "@discordjs/util": "^1.1.1", + "@discordjs/ws": "^1.2.3", + "@sapphire/snowflake": "3.5.3", + "discord-api-types": "^0.38.16", + "fast-deep-equal": "3.1.3", + "lodash.snakecase": "4.1.1", + "magic-bytes.js": "^1.10.0", + "tslib": "^2.6.3", + "undici": "6.21.3" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/effect": { + "version": "3.16.12", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.16.12.tgz", + "integrity": "sha512-N39iBk0K71F9nb442TLbTkjl24FLUzuvx2i1I2RsEAQsdAdUTuUoW0vlfUXgkMTUOnYqKnWcFfqw4hK4Pw27hg==", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "fast-check": "^3.23.1" + } + }, + "node_modules/empathic": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz", + "integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/exsolve": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz", + "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==", + "license": "MIT" + }, + "node_modules/fast-check": { + "version": "3.23.2", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", + "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "pure-rand": "^6.1.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/giget": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", + "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==", + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.0", + "defu": "^6.1.4", + "node-fetch-native": "^1.6.6", + "nypm": "^0.6.0", + "pathe": "^2.0.3" + }, + "bin": { + "giget": "dist/cli.mjs" + } + }, + "node_modules/jiti": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", + "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", + "license": "MIT" + }, + "node_modules/magic-bytes.js": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.12.1.tgz", + "integrity": "sha512-ThQLOhN86ZkJ7qemtVRGYM+gRgR8GEXNli9H/PMvpnZsE44Xfh3wx9kGJaldg314v85m+bFW6WBMaVHJc/c3zA==", + "license": "MIT" + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "license": "MIT" + }, + "node_modules/nypm": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.2.tgz", + "integrity": "sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g==", + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.2", + "pathe": "^2.0.3", + "pkg-types": "^2.3.0", + "tinyexec": "^1.0.1" + }, + "bin": { + "nypm": "dist/cli.mjs" + }, + "engines": { + "node": "^14.16.0 || >=16.10.0" + } + }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "license": "MIT" + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "license": "MIT" + }, + "node_modules/pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, + "node_modules/prisma": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.16.2.tgz", + "integrity": "sha512-aRvldGE5UUJTtVmFiH3WfNFNiqFlAtePUxcI0UEGlnXCX7DqhiMT5TRYwncHFeA/Reca5W6ToXXyCMTeFPdSXA==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/config": "6.16.2", + "@prisma/engines": "6.16.2" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/rc9": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", + "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", + "license": "MIT", + "dependencies": { + "defu": "^6.1.4", + "destr": "^2.0.3" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/redis": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/redis/-/redis-5.8.2.tgz", + "integrity": "sha512-31vunZj07++Y1vcFGcnNWEf5jPoTkGARgfWI4+Tk55vdwHxhAvug8VEtW7Cx+/h47NuJTEg/JL77zAwC6E0OeA==", + "license": "MIT", + "dependencies": { + "@redis/bloom": "5.8.2", + "@redis/client": "5.8.2", + "@redis/json": "5.8.2", + "@redis/search": "5.8.2", + "@redis/time-series": "5.8.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/tinyexec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", + "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", + "license": "MIT" + }, + "node_modules/ts-mixer": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz", + "integrity": "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==", + "license": "MIT" + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici": { + "version": "6.21.3", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.3.tgz", + "integrity": "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==", + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/undici-types": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", + "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", + "license": "MIT" + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..0a0dd38 --- /dev/null +++ b/package.json @@ -0,0 +1,25 @@ +{ + "name": "amayo", + "version": "0.0.1", + "description": "", + "main": "src/main.ts", + "scripts": { + "dev": "npx tsx watch src/main.ts" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "commonjs", + "dependencies": { + "@prisma/client": "6.16.2", + "discord-api-types": "0.38.24", + "discord.js": "14.22.1", + "prisma": "6.16.2", + "redis": "5.8.2" + }, + "devDependencies": { + "@types/node": "24.3.1", + "ts-node": "10.9.2", + "typescript": "5.9.2" + } +} diff --git a/prisma/dev.db b/prisma/dev.db new file mode 100644 index 0000000000000000000000000000000000000000..e160da733616ffb3d704e863390088f02b32aadb GIT binary patch literal 69632 zcmWFz^vNtqRY=P(%1ta$FlG>7U}R))P*7lCV31^BU=UU+c{>yDHU7;!hj~RfH}EvEXL8oFEMqli$!C7VYs%w#9ieX88n62 z#BIeH88Y)yQY(rJb23X(;}c6u^1=Lgu%qG)!4!WZmms^it1@GwC0G(Exx}Y~eCC-F z4~pIR?9@smIUcAtL;XAhLtPa-{ajol6qJw@U}#oS@b^Pep`@V%wLnQnK?!7slBTHu zo4BVkE_WjvZ-~SZEaGJsx0GdUlm>gjF()T8F)ukaJ~y?vI59odGX>;$m?$4sm&0UH z^+4PVlT*@Af}5zM$^U~vR$N(`vAqzS5+KfD6Ji5r#TI>jc93L;Dv~5P4?@&|nP~YB zNrp-ZW*Fr?NUDbx1duF=tsqFtOwCCthA38m=ZxrBb*N5QfD>D=2|8mXd-7sOZ!LC3_cF zAJ-69g&^19kRVUz5Rg!4fD5SXb#@GPc64#&(rgjtWEYo}Wo)kmrx;k8gV9{jR0}Pu zVZtOOl;n)Wyu8#LPxSH};(esFjV*MPl8aIkOHxxDOOzBqE)Vhab;T@%oI`_xT>V1g zL9)Rij=lj;b!h^#Q#^P@EXJ;4J)n)7o1Sg|_#G;bC)S}{y%!1&O#FAokJ_l;DLYIao zuaf+d#GHWq%)F9fB?V8v5Lb8CAk5e|fCQORd1`8QP9@RGbMx~`GDuLLlUQ654z?mF zwK$cm^awJ-7h)~hW|S7E;!3mdiVZy{fm=&R%_jv7C8#kv3UE!DkYGekdFT-n57C7+ z`9Y*8O?yPR0h+0?Isz((<_dBOMtcr6@nBtCSpXwo4ADh6{aM+?MMW7K8NoRMlnFtY z4K?M1gy5+iZ;O{pQ=N@X+*%Zui$EsD8-hsoMiC))adB~2V-f6oFfp)=#1z)%C`NX1 zLqo>4cyO4+7Zha{=O)JIW~LVkYvYIn6uyUrECz+WTrl#nc8(1Xjnpjv`=vrE)BS^Er<$i)7+aC-zn;DszC7ChK4E@RJX=GqzYG7$-ZeU_!U|@)WR~^IMLKR#lYAkDKX8| zJk8kD$S@@>Db>K#!o)bq#KgqH(7?hxIWg5RF~!2z(#+Dr$js0p4df#3rZ~8Z42%p+ z3=uBkZnACUXGFLtEzQKtG|?nQ*C^2>S=YqGAWhfO*uq#h(ZJj!)iA|0DLE<4Fflnb zHO(k3*~mD_GR4?1#VpOxI4LD5H8I)L!qPZ3(K0C|Ey=|)xy%4ab_sX?1cyy85$c{B3#5WJA(_<|L1RG;9t+*#(x7}{Eo_vhQMeDjE2By z2#kinXb6mkz-S1JhQMeDjE2By2#kinXb4ai0vgPrjKmC?FoP5lGm^oi&K$}~%m4#u z{-2TmF$4c&%6u@Ydo%<_Ltr!nMnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU1V%$(Ktn*9 zk=a<>(Adz-)Y8b<$iNb`hQh$m#Ka*uBQF!`GSFUrxCEsAES%U^E0qLtr!n zMnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU1V{`4(Ek6?{y&LH{|~VU8+Gnz2#kinXb6mkz-S1JhQMeDjE2By z2#kinXb6mkz-S1N5dx$0|6~N(sFu+X7!85Z5Eu=C(GVC7fzc2c4S~@R7!85Z5Eu=C z(GVD7Auu}sKg1$z)VZS}Fd71*Aut*OqaiRF0;3@?8UmvsFd71*Aut*Oqai>>2#n7E zlM!g6T1G=)Gz3ONU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0qLtu!702lvL24?<#2L99h z{rszknBzyCI~oF`Aut*OqaiRF0;3@?8UmvsFd71*Aut*OqaiRF0z)$dq*;uG8L?c` zmzY$>BF|zhja4ouGcm6!ky(<(m>;V=69WT-G`7qClJZMH>;D<~A2RSi9GU?(>gv%D z7!85Z5Eu=C(GVC7fzc2c4S~@R7!85Z5Eu=C(GVC70R{#JSw;d6|l% z>;Fen$!G|ShQMeDjE2By2#kinXb6mkz-S1JhQMeDjE2By2n_!a0QLVF`Cl^dzhnR{ z1>hO}J|6YqXb6mkz-S1JhQMeDjE2By2#kinXb6mkz-S1JhQMeD4C4?GV>ZUN1pw6P zXXZ^};Pc>3;#V5R{vY+)Xb6mkz-S1JhQMeDjE2By2#kinXb6mkz-S22JOmn(nFZ~o zrENhLH99gdgfa*kC+DW+rQ}p)=NK3m806-snHpy0=T#KtH { + if (!message.member?.permissions.has("Administrator")) { + return message.reply("❌ No tienes permisos de Administrador."); + } + + const embedName: string | null = args[0] ?? null; + if (!embedName) { + return message.reply( + "Debes proporcionar un nombre para el embed. Uso: `!embedcreate `" + ); + } + + const nameIsValid = await client.prisma.embedConfig.findFirst({ where: { + //@ts-ignore + guildId: message.guild.id, + name: embedName + }}) + if(nameIsValid) return message.reply("❌ Nombre del embed ya fue tomado!") + + // 📌 Estado independiente + let embedState: { + title?: string; + description?: string; + color?: number; + footer?: string; + } = { + title: `Editor de Embed: ${embedName}`, + description: + "Usa los botones de abajo para configurar este embed.\n\n_Ejemplo de variable: `{user.name}`_", + color: 0x5865f2, + footer: "Haz clic en Guardar cuando termines.", + }; + + // 📌 Función para construir un embed a partir del estado + const renderPreview = async () => { + const preview = new EmbedBuilder() + .setColor(embedState.color ?? 0x5865f2); + + if (embedState.title) + preview.setTitle( + //@ts-ignore + await replaceVars(embedState.title, message.member) + ); + if (embedState.description) + preview.setDescription( + //@ts-ignore + await replaceVars(embedState.description, message.member) + ); + if (embedState.footer) + preview.setFooter({ + //@ts-ignore + text: await replaceVars(embedState.footer, message.member), + }); + + return preview; + }; + + // 📌 Botones + const generateButtonRows = (disabled = false) => { + const primaryRow = new ActionRowBuilder().addComponents( + new ButtonBuilder() + .setCustomId("edit_title") + .setLabel("Título") + .setStyle(ButtonStyle.Primary) + .setDisabled(disabled), + new ButtonBuilder() + .setCustomId("edit_description") + .setLabel("Descripción") + .setStyle(ButtonStyle.Primary) + .setDisabled(disabled), + new ButtonBuilder() + .setCustomId("edit_color") + .setLabel("Color") + .setStyle(ButtonStyle.Primary) + .setDisabled(disabled) + ); + + const secondaryRow = new ActionRowBuilder().addComponents( + new ButtonBuilder() + .setCustomId("edit_footer") + .setLabel("Footer") + .setStyle(ButtonStyle.Secondary) + .setDisabled(disabled) + ); + + const controlRow = new ActionRowBuilder().addComponents( + new ButtonBuilder() + .setCustomId("save_embed") + .setLabel("Guardar") + .setStyle(ButtonStyle.Success) + .setDisabled(disabled), + new ButtonBuilder() + .setCustomId("cancel_embed") + .setLabel("Cancelar") + .setStyle(ButtonStyle.Danger) + .setDisabled(disabled) + ); + + return [primaryRow, secondaryRow, controlRow]; + }; + + if (message.channel.type === ChannelType.GuildText) { + const channel = message.channel as TextChannel; + + const editorMessage = await channel.send({ + embeds: [await renderPreview()], + components: generateButtonRows(), + }); + + const collector = editorMessage.createMessageComponentCollector({ + componentType: ComponentType.Button, + time: 300000, + }); + + collector.on("collect", async (i) => { + if (i.user.id !== message.author.id) { + await i.reply({ + content: "No puedes usar este menú.", + ephemeral: true, + }); + return; + } + await i.deferUpdate(); + await editorMessage.edit({ components: generateButtonRows(true) }); + + // Guardar + if (i.customId === "save_embed") { + try { + const dataForDb = { + title: embedState.title, + description: embedState.description, + color: embedState.color ? `#${embedState.color.toString(16).padStart(6, '0')}` : null, + footerText: embedState.footer, + }; + + await client.prisma.embedConfig.upsert({ + where: { + guildId_name: { + guildId: message.guildId!, + name: embedName, + }, + }, + update: dataForDb, + create: { + name: embedName, + ...dataForDb, + // ✅ ESTA ES LA SOLUCIÓN: + // Le decimos a Prisma que se conecte al Guild o lo cree si no existe. + guild: { + connectOrCreate: { + where: { id: message.guildId! }, + create: { + id: message.guildId!, + name: message.guild!.name, // Asegura que el nombre del servidor se guarde + }, + }, + }, + }, + }); + + const saved = new EmbedBuilder() + .setColor(0x00ff00) + .setTitle(`✅ Guardado: ${embedName}`) + .setDescription("La configuración se guardó en la base de datos."); + + await editorMessage.edit({ + embeds: [saved], + components: [], + }); + } catch (e) { + const errorEmbed = new EmbedBuilder() + .setColor(0xff0000) + .setTitle("❌ Error al Guardar") + .setDescription("No se pudo guardar en la base de datos. Revisa la consola."); + await editorMessage.edit({ + embeds: [errorEmbed], + components: [], + }); + console.error("Error de Prisma al guardar el embed:", e); + } + collector.stop(); + return; + } + // Cancelar + if (i.customId === "cancel_embed") { + await editorMessage.delete(); + collector.stop(); + return; + } + + // Edición + let promptContent = ""; + let fieldToEdit: "title" | "description" | "color" | "footer" | null = + null; + + switch (i.customId) { + case "edit_title": + promptContent = + "Escribe el nuevo **título** (puedes usar variables como `{user.name}`)."; + fieldToEdit = "title"; + break; + case "edit_description": + promptContent = + "Escribe la nueva **descripción** (puedes usar variables)."; + fieldToEdit = "description"; + break; + case "edit_color": + promptContent = + "Escribe el nuevo **color** en formato hexadecimal (ej: `#FF0000`)."; + fieldToEdit = "color"; + break; + case "edit_footer": + promptContent = + "Escribe el nuevo **texto del footer** (puedes usar variables)."; + fieldToEdit = "footer"; + break; + } + + //@ts-ignore + const promptMessage = await i.channel.send(promptContent); + + //@ts-ignore + const messageCollector = i.channel!.createMessageCollector({ + //@ts-ignore + filter: (m: Message) => m.author.id === i.user.id, + max: 1, + time: 60000, + }); + //@ts-ignore + messageCollector.on("collect", async (collectedMessage) => { + const newValue = collectedMessage.content; + + if (fieldToEdit === "title") embedState.title = newValue; + if (fieldToEdit === "description") embedState.description = newValue; + if (fieldToEdit === "footer") embedState.footer = newValue; + + if (fieldToEdit === "color") { + try { + const hex = newValue.replace("#", ""); + embedState.color = parseInt(hex, 16); + } catch { + embedState.color = 0x5865f2; + } + } + + await collectedMessage.delete(); + await promptMessage.delete(); + + await editorMessage.edit({ + embeds: [await renderPreview()], + components: generateButtonRows(false), + }); + }); + //@ts-ignore + messageCollector.on("end", async (collected) => { + if (collected.size === 0) { + await promptMessage.delete(); + await editorMessage.edit({ + components: generateButtonRows(false), + }); + } + }); + }); + + collector.on("end", async (_, reason) => { + if (reason === "time") { + const timeoutEmbed = new EmbedBuilder() + .setColor(0xff0000) + .setTitle("Editor finalizado por inactividad."); + + await editorMessage.edit({ + embeds: [timeoutEmbed], + components: [], + }); + } + }); + } + }, +}; diff --git a/src/commands/messages/alliaces/editEmbed.ts b/src/commands/messages/alliaces/editEmbed.ts new file mode 100644 index 0000000..ea2d5d2 --- /dev/null +++ b/src/commands/messages/alliaces/editEmbed.ts @@ -0,0 +1,276 @@ +import { CommandMessage } from "../../../core/types/commands"; +// @ts-ignore +import { EmbedBuilder, ActionRowBuilder, ButtonBuilder, TextChannel, ChannelType } from "discord.js"; +//@ts-ignore +import { ButtonStyle, ComponentType } from "discord.js"; +import { replaceVars } from "../../../core/lib/vars"; + +export const command: CommandMessage = { + name: "editembed", + type: "message", + aliases: ["modembed", "updateembed"], + cooldown: 20, + // @ts-ignore + run: async (message, args, client) => { + if (!message.member?.permissions.has("Administrator")) { + return message.reply("❌ No tienes permisos de Administrador."); + } + + const embedName: string | null = args[0] ?? null; + if (!embedName) { + return message.reply( + "Debes proporcionar un nombre para el embed. Uso: `!editembed `" + ); + } + + // 📌 Buscar en la base de datos + const existing = await client.prisma.embedConfig.findUnique({ + where: { + guildId_name: { + guildId: message.guildId!, + name: embedName, + }, + }, + }); + + if (!existing) { + return message.reply("❌ No encontré un embed con ese nombre."); + } + + // 📌 Estado inicial desde DB + let embedState: { + title?: string; + description?: string; + color?: number; + footer?: string; + } = { + title: existing.title ?? undefined, + description: existing.description ?? undefined, + color: existing.color ? parseInt(existing.color.replace("#", ""), 16) : 0x5865f2, + footer: existing.footerText ?? undefined, + }; + + // 📌 Función para renderizar preview + const renderPreview = async () => { + const preview = new EmbedBuilder().setColor(embedState.color ?? 0x5865f2); + + if (embedState.title) + //@ts-ignore + preview.setTitle(await replaceVars(embedState.title, message.member)); + if (embedState.description) + //@ts-ignore + preview.setDescription(await replaceVars(embedState.description, message.member)); + if (embedState.footer) + preview.setFooter({ + //@ts-ignore + text: await replaceVars(embedState.footer, message.member), + }); + + return preview; + }; + + const generateButtonRows = (disabled = false) => { + const primaryRow = new ActionRowBuilder().addComponents( + new ButtonBuilder() + .setCustomId("edit_title") + .setLabel("Título") + .setStyle(ButtonStyle.Primary) + .setDisabled(disabled), + new ButtonBuilder() + .setCustomId("edit_description") + .setLabel("Descripción") + .setStyle(ButtonStyle.Primary) + .setDisabled(disabled), + new ButtonBuilder() + .setCustomId("edit_color") + .setLabel("Color") + .setStyle(ButtonStyle.Primary) + .setDisabled(disabled) + ); + + const secondaryRow = new ActionRowBuilder().addComponents( + new ButtonBuilder() + .setCustomId("edit_footer") + .setLabel("Footer") + .setStyle(ButtonStyle.Secondary) + .setDisabled(disabled) + ); + + const controlRow = new ActionRowBuilder().addComponents( + new ButtonBuilder() + .setCustomId("save_embed") + .setLabel("Guardar cambios") + .setStyle(ButtonStyle.Success) + .setDisabled(disabled), + new ButtonBuilder() + .setCustomId("cancel_embed") + .setLabel("Cancelar") + .setStyle(ButtonStyle.Danger) + .setDisabled(disabled) + ); + + return [primaryRow, secondaryRow, controlRow]; + }; + + if (message.channel.type === ChannelType.GuildText) { + const channel = message.channel as TextChannel; + + const editorMessage = await channel.send({ + embeds: [await renderPreview()], + components: generateButtonRows(), + }); + + const collector = editorMessage.createMessageComponentCollector({ + componentType: ComponentType.Button, + time: 300000, + }); + + collector.on("collect", async (i) => { + if (i.user.id !== message.author.id) { + await i.reply({ + content: "No puedes usar este menú.", + ephemeral: true, + }); + return; + } + await i.deferUpdate(); + await editorMessage.edit({ components: generateButtonRows(true) }); + + // Guardar cambios + if (i.customId === "save_embed") { + try { + const dataForDb = { + title: embedState.title, + description: embedState.description, + color: embedState.color ? `#${embedState.color.toString(16).padStart(6, '0')}` : null, + footerText: embedState.footer, + }; + + await client.prisma.embedConfig.update({ + where: { + guildId_name: { + guildId: message.guildId!, + name: embedName, + }, + }, + data: dataForDb, + }); + + const saved = new EmbedBuilder() + .setColor(0x00ff00) + .setTitle(`✅ Actualizado: ${embedName}`) + .setDescription("Los cambios fueron guardados en la base de datos."); + + await editorMessage.edit({ + embeds: [saved], + components: [], + }); + } catch (e) { + const errorEmbed = new EmbedBuilder() + .setColor(0xff0000) + .setTitle("❌ Error al Guardar") + .setDescription("No se pudo guardar en la base de datos. Revisa la consola."); + await editorMessage.edit({ + embeds: [errorEmbed], + components: [], + }); + console.error("Error de Prisma al actualizar el embed:", e); + } + collector.stop(); + return; + } + + // Cancelar + if (i.customId === "cancel_embed") { + await editorMessage.delete(); + collector.stop(); + return; + } + + // Edición + let promptContent = ""; + let fieldToEdit: "title" | "description" | "color" | "footer" | null = + null; + + switch (i.customId) { + case "edit_title": + promptContent = "Escribe el nuevo **título** (puedes usar variables)."; + fieldToEdit = "title"; + break; + case "edit_description": + promptContent = "Escribe la nueva **descripción**."; + fieldToEdit = "description"; + break; + case "edit_color": + promptContent = "Escribe el nuevo **color** en formato hexadecimal (ej: `#FF0000`)."; + fieldToEdit = "color"; + break; + case "edit_footer": + promptContent = "Escribe el nuevo **texto del footer**."; + fieldToEdit = "footer"; + break; + } + + //@ts-ignore + const promptMessage = await i.channel.send(promptContent); + + //@ts-ignore + const messageCollector = i.channel!.createMessageCollector({ + //@ts-ignore + filter: (m: Message) => m.author.id === i.user.id, + max: 1, + time: 60000, + }); + + //@ts-ignore + messageCollector.on("collect", async (collectedMessage) => { + const newValue = collectedMessage.content; + + if (fieldToEdit === "title") embedState.title = newValue; + if (fieldToEdit === "description") embedState.description = newValue; + if (fieldToEdit === "footer") embedState.footer = newValue; + + if (fieldToEdit === "color") { + try { + const hex = newValue.replace("#", ""); + embedState.color = parseInt(hex, 16); + } catch { + embedState.color = 0x5865f2; + } + } + + await collectedMessage.delete(); + await promptMessage.delete(); + + await editorMessage.edit({ + embeds: [await renderPreview()], + components: generateButtonRows(false), + }); + }); + + //@ts-ignore + messageCollector.on("end", async (collected) => { + if (collected.size === 0) { + await promptMessage.delete(); + await editorMessage.edit({ + components: generateButtonRows(false), + }); + } + }); + }); + + collector.on("end", async (_, reason) => { + if (reason === "time") { + const timeoutEmbed = new EmbedBuilder() + .setColor(0xff0000) + .setTitle("Editor finalizado por inactividad."); + + await editorMessage.edit({ + embeds: [timeoutEmbed], + components: [], + }); + } + }); + } + }, +}; diff --git a/src/commands/messages/alliaces/embedDelete.ts b/src/commands/messages/alliaces/embedDelete.ts new file mode 100644 index 0000000..c033abd --- /dev/null +++ b/src/commands/messages/alliaces/embedDelete.ts @@ -0,0 +1,34 @@ +import { CommandMessage } from "../../../core/types/commands"; + +export const command: CommandMessage = { + name: "embeddelete", + type: "message", + aliases: ["delembed", "removeembed"], + cooldown: 10, + //@ts-ignore + run: async (message, args, client) => { + if (!message.member?.permissions.has("Administrator")) { + return message.reply("❌ No tienes permisos de Administrador."); + } + + const embedName = args[0]; + if (!embedName) { + return message.reply("Debes proporcionar el nombre del embed a eliminar. Uso: `!embeddelete `"); + } + + try { + await client.prisma.embedConfig.delete({ + where: { + guildId_name: { + guildId: message.guildId!, + name: embedName, + }, + }, + }); + + return message.reply(`✅ El embed **${embedName}** fue eliminado con éxito.`); + } catch { + return message.reply("❌ No encontré un embed con ese nombre."); + } + }, +}; diff --git a/src/commands/messages/alliaces/embedList.ts b/src/commands/messages/alliaces/embedList.ts new file mode 100644 index 0000000..e4d13cb --- /dev/null +++ b/src/commands/messages/alliaces/embedList.ts @@ -0,0 +1,75 @@ +import {CommandMessage} from "../../../core/types/commands"; +import { + //@ts-ignore + ChannelType, + ContainerBuilder, + //@ts-ignore + MessageFlags, + SectionBuilder, + SeparatorBuilder, + //@ts-ignore + SeparatorSpacingSize, + TextChannel, + TextDisplayBuilder +} from "discord.js"; + +export const command: CommandMessage = { + name: "embedlist", + type: "message", + aliases: ["listembeds", "embeds"], + cooldown: 10, + //@ts-ignore + run: async (message, args, client) => { + if (!message.member?.permissions.has("Administrator")) { + return message.reply("❌ No tienes permisos de Administrador."); + } + + const embeds = await client.prisma.embedConfig.findMany({ + where: { guildId: message.guildId! }, + }); + + if (embeds.length === 0) { + return message.reply("📭 No hay ningún embed guardado en este servidor."); + } + + const title = new TextDisplayBuilder() + .setContent('﹒⌒    Embed List    ╰୧﹒'); + + // Combina la lista de embeds en la misma sección que la miniatura + // para un mejor diseño. + //@ts-ignore + const embedListContent = embeds.map((e, i) => `**${i + 1}.** ${e.name}`).join("\n"); + + // Obtenemos la URL del icono de forma segura + const guildIconURL = message.guild?.iconURL({ forceStatic: false }); + + // Creamos la sección que contendrá el texto Y la miniatura + const mainSection = new SectionBuilder() + .addTextDisplayComponents(text => text.setContent(embedListContent)); // <--- Componente principal requerido + + // Solo añadimos la miniatura si la URL existe + if (guildIconURL) { + //@ts-ignore + mainSection.setThumbnailAccessory(thumbnail => thumbnail + .setURL(guildIconURL) + .setDescription('Icono del servidor') + ); + } + + const separator = new SeparatorBuilder() + .setSpacing(SeparatorSpacingSize.Large) + .setDivider(false); + + const container = new ContainerBuilder() + .setAccentColor(0x49225B) + .addTextDisplayComponents(title) + .addSeparatorComponents(separator) + .addSectionComponents(mainSection); // <--- Añadimos la sección ya completa + + + if (message.channel.type === ChannelType.GuildText) { + const channel = message.channel as TextChannel; + await channel.send({ components: [container], flags: MessageFlags.IsComponentsV2}); + } + }, +}; \ No newline at end of file diff --git a/src/commands/messages/net/ping.ts b/src/commands/messages/net/ping.ts new file mode 100644 index 0000000..d27315f --- /dev/null +++ b/src/commands/messages/net/ping.ts @@ -0,0 +1,11 @@ +import {CommandMessage} from "../../../core/types/commands"; + +export const command: CommandMessage = { + name: 'ping', + type: "message", + aliases: ['latency', 'pong'], + cooldown: 5, + run: async (message, args) => { + await message.reply('pong!') + } +} \ No newline at end of file diff --git a/src/commands/messages/others/embedtested.ts b/src/commands/messages/others/embedtested.ts new file mode 100644 index 0000000..023c371 --- /dev/null +++ b/src/commands/messages/others/embedtested.ts @@ -0,0 +1,45 @@ +import {CommandMessage} from "../../../core/types/commands"; + +export const command: CommandMessage = { + name: 'test1', + type: "message", + cooldown: 5, + run: async (message, args) => { + //@ts-ignore + await message.channel.send({ + "flags": 32768, + "components": [ + { + "type": 17, + "components": [ + { + "type": 10, + "content": "## ﹒⌒    🌹 Navegacion 🌹    ╰୧﹒" + }, + { + "type": 14, + "spacing": 2, + "divider": false + }, + { + "type": 9, + "components": [ + { + "type": 10, + "content": "### Reglas dentro del Servidor" + } + ], + "accessory": { + "style": 2, + "type": 5, + "label": "Ver", + "url": "https://discord.com/channels/1316592320954630144/1417682278762676264/1417901305434734656", + } + } + ], + "accent_color": 4393549 + } + ] + }) + } +} \ No newline at end of file diff --git a/src/commands/messages/settings-server/settings.ts b/src/commands/messages/settings-server/settings.ts new file mode 100644 index 0000000..4138df0 --- /dev/null +++ b/src/commands/messages/settings-server/settings.ts @@ -0,0 +1,51 @@ +import {CommandMessage} from "../../../core/types/commands"; +//@ts-ignore +import { + ButtonStyle, ChannelType, + ContainerBuilder, + MessageFlags, + SectionBuilder, SeparatorBuilder, SeparatorSpacingSize, TextChannel, + TextDisplayBuilder, + UserSelectMenuBuilder +} from "discord.js"; + +export const command: CommandMessage = { + name: 'settings', + type: "message", + aliases: ['options', 'stts'], + cooldown: 5, + run: async (message, args, client) => { + const server = await client.prisma.guild.findFirst({ where: { id: message.guild!.id } }); + const title = new TextDisplayBuilder() + .setContent("## ﹒⌒    Settings Seɾveɾ    ╰୧﹒") + const description = new TextDisplayBuilder() + .setContent("Panel de Administracion del bot dentro del servidor.") + const sect = new TextDisplayBuilder() + .setContent("**Prefix del bot:** " + ` \`\`\`${server.prefix}\`\`\``) + + const section = new SectionBuilder() + .addTextDisplayComponents(sect) + //@ts-ignore + .setButtonAccessory(button => button + .setCustomId('prefixsettings') + .setLabel('Prefix') + .setStyle(ButtonStyle.Primary), + ) + + const separator = new SeparatorBuilder() + .setSpacing(SeparatorSpacingSize.Large) + .setDivider(false); + + const main = new ContainerBuilder() + .addTextDisplayComponents(title, description) + .addSeparatorComponents(separator) + .addSectionComponents(section) + + + //@ts-ignore + if (message.channel.type === ChannelType.GuildText) { + const channel = message.channel as TextChannel; + await channel.send({ components: [main], flags: MessageFlags.IsComponentsV2}); + } + } +} \ No newline at end of file diff --git a/src/commands/splashcmd/net/ping.ts b/src/commands/splashcmd/net/ping.ts new file mode 100644 index 0000000..1d12a13 --- /dev/null +++ b/src/commands/splashcmd/net/ping.ts @@ -0,0 +1,12 @@ +import {CommandSlash} from "../../../core/types/commands"; + + +export const command: CommandSlash = { + name: 'ping', + description: 'Ping', + type: "slash", + cooldown: 10, + run: async (interaction, client) => { + await interaction.reply('pong!') + } +} \ No newline at end of file diff --git a/src/components/buttons/prefixSettings.ts b/src/components/buttons/prefixSettings.ts new file mode 100644 index 0000000..d183cbb --- /dev/null +++ b/src/components/buttons/prefixSettings.ts @@ -0,0 +1,22 @@ +import type {ButtonInteraction} from "discord.js"; +//@ts-ignore +import { ActionRowBuilder, Events, ModalBuilder, TextInputBuilder, TextInputStyle } from 'discord.js' + +export default { + customId: "prefixsettings", + run: async(interaction: ButtonInteraction) => { + const modal = new ModalBuilder() + .setCustomId('prefixsettingsmodal') + .setTitle('Prefix'); + + const prefixInput = new TextInputBuilder() + .setCustomId('prefixInput') + .setLabel("Change Prefix") + .setStyle(TextInputStyle.Short); + + const secondActionRow = new ActionRowBuilder().addComponents(prefixInput); + modal.addComponents(secondActionRow); + + await interaction.showModal(modal); + } +} \ No newline at end of file diff --git a/src/components/modals/prefixSettingsModal.ts b/src/components/modals/prefixSettingsModal.ts new file mode 100644 index 0000000..eb6b24f --- /dev/null +++ b/src/components/modals/prefixSettingsModal.ts @@ -0,0 +1,10 @@ +import {ModalSubmitInteraction} from "discord.js"; + +export default { + customId: "prefixsettingsmodal", + run: async (interaction: ModalSubmitInteraction) => { + const newPrefix = interaction.fields.getTextInputValue("prefixInput") + + + } +} \ No newline at end of file diff --git a/src/core/api/discordAPI.ts b/src/core/api/discordAPI.ts new file mode 100644 index 0000000..5717ab2 --- /dev/null +++ b/src/core/api/discordAPI.ts @@ -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 { + 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); + } +} + diff --git a/src/core/client.ts b/src/core/client.ts new file mode 100644 index 0000000..ad90ad5 --- /dev/null +++ b/src/core/client.ts @@ -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; \ No newline at end of file diff --git a/src/core/components.ts b/src/core/components.ts new file mode 100644 index 0000000..fdc1a6a --- /dev/null +++ b/src/core/components.ts @@ -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 = new Collection(); +export const modals = new Collection(); +export const selectmenus = new Collection(); +export const contextmenus = new Collection(); + +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}`); + } + } +} diff --git a/src/core/lib/vars.ts b/src/core/lib/vars.ts new file mode 100644 index 0000000..7578e36 --- /dev/null +++ b/src/core/lib/vars.ts @@ -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 })) +} \ No newline at end of file diff --git a/src/core/loader.ts b/src/core/loader.ts new file mode 100644 index 0000000..23e3284 --- /dev/null +++ b/src/core/loader.ts @@ -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(); + +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}`); + } +} diff --git a/src/core/loaderEvents.ts b/src/core/loaderEvents.ts new file mode 100644 index 0000000..cc03550 --- /dev/null +++ b/src/core/loaderEvents.ts @@ -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}`); + } +} diff --git a/src/core/redis.ts b/src/core/redis.ts new file mode 100644 index 0000000..f46ace6 --- /dev/null +++ b/src/core/redis.ts @@ -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(); +} diff --git a/src/core/types/commands.ts b/src/core/types/commands.ts new file mode 100644 index 0000000..3ddd524 --- /dev/null +++ b/src/core/types/commands.ts @@ -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; +} + +export interface CommandSlash { + name: string; + description: string; + type: 'slash'; + options?: string[]; + cooldown?: number; + run: (i: ChatInputCommandInteraction, client: Client) => Promise; +} \ No newline at end of file diff --git a/src/core/types/components.ts b/src/core/types/components.ts new file mode 100644 index 0000000..1474bd2 --- /dev/null +++ b/src/core/types/components.ts @@ -0,0 +1,7 @@ +import type {ButtonInteraction} from "discord.js"; + + +export interface button { + customId: string; + run: (interaction: ButtonInteraction) => Promise; +} \ No newline at end of file diff --git a/src/events/interactionCreate.ts b/src/events/interactionCreate.ts new file mode 100644 index 0000000..85dc4cf --- /dev/null +++ b/src/events/interactionCreate.ts @@ -0,0 +1,53 @@ +import { bot } from "../main"; +import type { BaseInteraction } from "discord.js"; +import { Events } from "discord.js"; +import { redis } from "../core/redis"; +import { commands } from "../core/loader"; +import { buttons, modals, selectmenus } from "../core/components"; + +bot.on(Events.InteractionCreate, async (interaction: BaseInteraction) => { + try { + // 🔹 Slash commands + if (interaction.isChatInputCommand()) { + const cmd = commands.get(interaction.commandName); + if (!cmd) return; + + const cooldown = Math.floor(Number(cmd.cooldown) || 0); + + if (cooldown > 0) { + const key = `cooldown:${cmd.name}:${interaction.user.id}`; + const ttl = await redis.ttl(key); + if (ttl > 0) { + return interaction.reply(`⏳ Espera ${ttl}s antes de volver a usar **${cmd.name}**.`); + } + await redis.set(key, "1", { EX: cooldown }); + } + + await cmd.run(interaction, bot); + } + + // 🔹 Botones + if (interaction.isButton()) { + //@ts-ignore + const btn = buttons.get(interaction.customId); + if (btn) await btn.run(interaction, bot); + } + + // 🔹 Select menus + if (interaction.isStringSelectMenu()) { + const menu = selectmenus.get(interaction.customId); + if (menu) await menu.run(interaction, bot); + } + + // 🔹 Modales + if (interaction.isModalSubmit()) { + const modal = modals.get(interaction.customId); + if (modal) await modal.run(interaction, bot); + } + } catch (error) { + console.error(error); + if (interaction.isRepliable()) { + await interaction.reply({ content: "❌ Hubo un error ejecutando la interacción.", ephemeral: true }); + } + } +}); diff --git a/src/events/messageCreate.ts b/src/events/messageCreate.ts new file mode 100644 index 0000000..f64d63f --- /dev/null +++ b/src/events/messageCreate.ts @@ -0,0 +1,40 @@ +import {bot} from "../main"; +import {Events} from "discord.js"; +import {redis} from "../core/redis"; +import {commands} from "../core/loader"; + + +bot.on(Events.MessageCreate, async (message) => { + if (message.author.bot) return; + const server = await bot.prisma.guild.findFirst({ where: { id: message.guild!.id } }) || "!"; + const PREFIX = server.prefix + if (!message.content.startsWith(PREFIX)) return; + + const [cmdName, ...args] = message.content.slice(PREFIX.length).trim().split(/\s+/); + console.log(cmdName); + const command = commands.get(cmdName); + if (!command) return; + + const cooldown = Math.floor(Number(command.cooldown) || 0); + + if (cooldown > 0) { + const key = `cooldown:${command.name}:${message.author.id}`; + const ttl = await redis.ttl(key); + console.log(`Key: ${key}, TTL: ${ttl}`); + + if (ttl > 0) { + return message.reply(`⏳ Espera ${ttl}s antes de volver a usar **${command.name}**.`); + } + + // SET con expiración correcta para redis v4+ + await redis.set(key, "1", { EX: cooldown }); + } + + + try { + await command.run(message, args, message.client); + } catch (error) { + console.error(error); + await message.reply("❌ Hubo un error ejecutando el comando."); + } +}) \ No newline at end of file diff --git a/src/events/ready.ts b/src/events/ready.ts new file mode 100644 index 0000000..27763b2 --- /dev/null +++ b/src/events/ready.ts @@ -0,0 +1,6 @@ +import {bot} from "../main"; +import {Events} from "discord.js"; + +bot.on(Events.ClientReady, () => { + console.log("Ready!"); +}) \ No newline at end of file diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..6f5e289 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,28 @@ +import Amayo from "./core/client"; +import { loadCommands } from "./core/loader"; +import { loadEvents } from "./core/loaderEvents"; +import { redisConnect } from "./core/redis"; +import { registeringCommands } from "./core/api/discordAPI"; +import {loadComponents} from "./core/components"; + +export const bot = new Amayo(); + +async function bootstrap() { + console.log("🚀 Iniciando bot..."); + + loadCommands(); // 1️⃣ Cargar comandos en la Collection + loadComponents() + loadEvents(); // 2️⃣ Cargar eventos + + await registeringCommands(); // 3️⃣ Registrar los slash en Discord + + await redisConnect(); // 4️⃣ Conectar Redis + + await bot.play(); + console.log("✅ Bot conectado a Discord"); +} + +bootstrap().catch((err) => { + console.error("❌ Error en el arranque:", err); + process.exit(1); +}); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..0e2c6a7 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "ES2024", + "module": "ESNext", + "moduleResolution": "nodenext", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + }, + "include": ["src"] +}