From 06ae61f8bedcd240f42ac9f9b0201aefa7caef0b Mon Sep 17 00:00:00 2001 From: Jack Date: Tue, 3 Sep 2024 20:18:41 +0000 Subject: [PATCH] Initial commit --- example.env | 5 + lib/utilities/commandModules.js | 46 + package-lock.json | 1925 ++++++++++++++++++++++++++ package.json | 28 + src/commands/lookup/domain.js | 56 + src/commands/lookup/imdb.js | 71 + src/commands/lookup/plant.js | 75 + src/commands/memes/2020.js | 14 + src/commands/memes/8ball.js | 45 + src/commands/memes/birthday.js | 60 + src/commands/memes/corrupt.js | 16 + src/commands/memes/eyecandy.js | 40 + src/commands/memes/kanye.js | 139 ++ src/commands/memes/reminder.js | 14 + src/commands/memes/taylor.js | 184 +++ src/commands/utilities/countdown.js | 24 + src/commands/utilities/servertime.js | 14 + src/commands/work/payday.js | 111 ++ src/index.js | 45 + src/register-slash-commands.js | 25 + 20 files changed, 2937 insertions(+) create mode 100644 example.env create mode 100644 lib/utilities/commandModules.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/commands/lookup/domain.js create mode 100644 src/commands/lookup/imdb.js create mode 100644 src/commands/lookup/plant.js create mode 100644 src/commands/memes/2020.js create mode 100644 src/commands/memes/8ball.js create mode 100644 src/commands/memes/birthday.js create mode 100644 src/commands/memes/corrupt.js create mode 100644 src/commands/memes/eyecandy.js create mode 100644 src/commands/memes/kanye.js create mode 100644 src/commands/memes/reminder.js create mode 100644 src/commands/memes/taylor.js create mode 100644 src/commands/utilities/countdown.js create mode 100644 src/commands/utilities/servertime.js create mode 100644 src/commands/work/payday.js create mode 100644 src/index.js create mode 100644 src/register-slash-commands.js diff --git a/example.env b/example.env new file mode 100644 index 0000000..eafc879 --- /dev/null +++ b/example.env @@ -0,0 +1,5 @@ +DISCORD_TOKEN=MTI4MDQ0NDY1MjUyODQ2Nz... +DISCORD_APPLICATION_ID=12804446... +GIPHY_API_KEY=mg7MHuxn42R4TE33... +PLANTNET_API_KEY=2b10p4Zb7K... +OMDB_API_KEY=96e... \ No newline at end of file diff --git a/lib/utilities/commandModules.js b/lib/utilities/commandModules.js new file mode 100644 index 0000000..050d7ae --- /dev/null +++ b/lib/utilities/commandModules.js @@ -0,0 +1,46 @@ +import path from 'path'; +import { glob } from 'glob'; +import { ApplicationCommand } from 'discord.js'; + +/** + * Get all command modules from the commands directory. + * @returns {Promise} The file paths of all command modules. + */ +async function getCommandModulePaths() { + return await glob(path.join(process.cwd(), 'src/commands/**/*.js')); +} + +/** + * Load a single command module. + * @param {string} modulePath The path to the command module. + * @returns {Promise} The loaded command module. + */ +async function loadCommandModule(modulePath) { + try { + const module = await import(path.resolve(modulePath)); + const commandModule = module.default; + + if (!commandModule.data || !commandModule.execute) { + console.warn(`Invalid command module at ${modulePath}`); + return; + } + + console.info(`Loaded command module: ${commandModule.data.name}`); + return commandModule; + } catch (error) { + console.error(`Error loading module at ${modulePath}.`, error); + } +} + +/** + * Load all command modules. + * @returns {Promise} The loaded command modules. + */ +export async function loadCommandModules() { + const commandModulePaths = await getCommandModulePaths(); + const commandModules = await Promise.all( + commandModulePaths.map(loadCommandModule) + ); + + return commandModules.filter((module) => module); +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..8030084 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1925 @@ +{ + "name": "butlerbotng", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "butlerbotng", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "axios": "^1.7.7", + "date-fns": "^3.6.0", + "discord.js": "^14.16.1", + "glob": "^11.0.0", + "prettier": "^3.3.3" + }, + "devDependencies": { + "eslint": "^9.9.1" + } + }, + "node_modules/@discordjs/builders": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.9.0.tgz", + "integrity": "sha512-0zx8DePNVvQibh5ly5kCEei5wtPBIUbSoE9n+91Rlladz4tgtFbJ36PZMxxZrTEOQ7AHMZ/b0crT/0fCy6FTKg==", + "license": "Apache-2.0", + "dependencies": { + "@discordjs/formatters": "^0.5.0", + "@discordjs/util": "^1.1.1", + "@sapphire/shapeshift": "^4.0.0", + "discord-api-types": "0.37.97", + "fast-deep-equal": "^3.1.3", + "ts-mixer": "^6.0.4", + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=18" + }, + "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.5.0", + "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.5.0.tgz", + "integrity": "sha512-98b3i+Y19RFq1Xke4NkVY46x8KjJQjldHUuEbCqMvp1F5Iq9HgnGpu91jOi/Ufazhty32eRsKnnzS8n4c+L93g==", + "license": "Apache-2.0", + "dependencies": { + "discord-api-types": "0.37.97" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@discordjs/rest": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.4.0.tgz", + "integrity": "sha512-Xb2irDqNcq+O8F0/k/NaDp7+t091p+acb51iA4bCKfIn+WFWd6HrNvcsSbMMxIR9NjcMZS6NReTKygqiQN+ntw==", + "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.37.97", + "magic-bytes.js": "^1.10.0", + "tslib": "^2.6.3", + "undici": "6.19.8" + }, + "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.1.1", + "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.1.1.tgz", + "integrity": "sha512-PZ+vLpxGCRtmr2RMkqh8Zp+BenUaJqlS6xhgWKEZcgC/vfHLEzpHtKkB0sl3nZWpwtcKk6YWy+pU3okL2I97FA==", + "license": "Apache-2.0", + "dependencies": { + "@discordjs/collection": "^2.1.0", + "@discordjs/rest": "^2.3.0", + "@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.37.83", + "tslib": "^2.6.2", + "ws": "^8.16.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/@discordjs/ws/node_modules/discord-api-types": { + "version": "0.37.83", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.83.tgz", + "integrity": "sha512-urGGYeWtWNYMKnYlZnOnDHm8fVRffQs3U0SpE8RHeiuLKb/u92APS8HoQnPTFbnXmY1vVnXjXO4dOxcAn3J+DA==", + "license": "MIT" + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", + "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "9.9.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.1.tgz", + "integrity": "sha512-xIDQRsfg5hNBqHz04H1R3scSVwmI+KUbqjsQKHKQ1DAUSaUjYPReZZmS/5PNiKu1fUvzDd6H7DEDKACSEhu+TQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@sapphire/async-queue": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.3.tgz", + "integrity": "sha512-x7zadcfJGxFka1Q3f8gCts1F0xMwCKbZweM85xECGI0hBTeIZJGGCrHgLggihBoprlQ/hBmDR5LKfIPqnmHM3w==", + "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/@types/node": { + "version": "22.5.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.2.tgz", + "integrity": "sha512-acJsPTEqYqulZS/Yp/S3GgeE6GZ0qYODUR8aVr/DkhHQ8l9nd4j5x1/ZJy9/gHrRlFMqkO6i0I3E27Alu4jjPg==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/@types/ws": { + "version": "8.5.12", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", + "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", + "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.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/discord-api-types": { + "version": "0.37.97", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.97.tgz", + "integrity": "sha512-No1BXPcVkyVD4ZVmbNgDKaBoqgeQ+FJpzZ8wqHkfmBnTZig1FcH3iPPersiK1TUIAzgClh2IvOuVUYfcWLQAOA==", + "license": "MIT" + }, + "node_modules/discord.js": { + "version": "14.16.1", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.16.1.tgz", + "integrity": "sha512-/diX4shp3q1F3EySGQbQl10el+KIpffLSOJdtM35gGV7zw2ED7rKbASKJT7UIR9L/lTd0KtNenZ/h739TN7diA==", + "license": "Apache-2.0", + "dependencies": { + "@discordjs/builders": "^1.9.0", + "@discordjs/collection": "1.5.3", + "@discordjs/formatters": "^0.5.0", + "@discordjs/rest": "^2.4.0", + "@discordjs/util": "^1.1.1", + "@discordjs/ws": "1.1.1", + "@sapphire/snowflake": "3.5.3", + "discord-api-types": "0.37.97", + "fast-deep-equal": "3.1.3", + "lodash.snakecase": "4.1.1", + "tslib": "^2.6.3", + "undici": "6.19.8" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.9.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.9.1.tgz", + "integrity": "sha512-dHvhrbfr4xFQ9/dq+jcVneZMyRYLjggWjk6RVsIiHsP8Rz6yZ8LvZ//iU4TrZF+SXWG+JkNF2OyiZRvzgRDqMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.18.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.9.1", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.0.2", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", + "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.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/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz", + "integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.1.tgz", + "integrity": "sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "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/lru-cache": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.0.tgz", + "integrity": "sha512-Qv32eSV1RSCfhY3fpPE2GNZ8jgM9X7rdAfemLWqTUxwiyIC4jJ6Sy0fZ8H+oLWevO6i4/bizg7c8d8i6bxrzbA==", + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/magic-bytes.js": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.10.0.tgz", + "integrity": "sha512-/k20Lg2q8LE5xiaaSkMXk4sfvI+9EGEykFS4b0CHHGWqDYU0bGUFSwchNOMA56D7TCs9GwVTkqe9als1/ns8UQ==", + "license": "MIT" + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "license": "BlueOak-1.0.0" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "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/tslib": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/undici": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.19.8.tgz", + "integrity": "sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==", + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "license": "MIT" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "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/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..3e5777f --- /dev/null +++ b/package.json @@ -0,0 +1,28 @@ +{ + "name": "butlerbotng", + "version": "1.0.0", + "main": "src/index.js", + "type": "module", + "scripts": { + "start": "node --env-file .env src/index.js", + "register-slash-commands": "node --env-file .env src/register-slash-commands.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "https://git.3t.network/terriblecodeclub/butlerbotng.git" + }, + "author": "Butlersaurus", + "license": "ISC", + "description": "", + "dependencies": { + "axios": "^1.7.7", + "date-fns": "^3.6.0", + "discord.js": "^14.16.1", + "glob": "^11.0.0", + "prettier": "^3.3.3" + }, + "devDependencies": { + "eslint": "^9.9.1" + } +} diff --git a/src/commands/lookup/domain.js b/src/commands/lookup/domain.js new file mode 100644 index 0000000..051fecd --- /dev/null +++ b/src/commands/lookup/domain.js @@ -0,0 +1,56 @@ +import { EmbedBuilder, SlashCommandBuilder } from 'discord.js'; +import axios from 'axios'; + +const GODADDY_API_URL = 'https://api.godaddy.com/v1/domains/available'; + +const data = new SlashCommandBuilder() + .setName('domain') + .setDescription('Check the availability and price of a domain name.') + .addStringOption((option) => + option + .setName('domain') + .setDescription('The domain to check') + .setRequired(true) + ); + +async function execute(interaction) { + const domain = interaction.options.getString('domain'); + let embed = new EmbedBuilder().setTitle('Domain checker'); + + try { + const response = await axios.get(GODADDY_API_URL, { + params: { domain: domain }, + headers: { Authorization: `sso-key ${process.env.GODADDY_API_KEY}` }, + timeout: 5000, + }); + console.log(`Got response for domain: ${domain}.`, response.data); + + const result = response.data; + let isDomainAvailable = 'No.'; + let color = 0xff0000; + let price = null; + + if (response.status === 200 && result.available) { + isDomainAvailable = 'Yes!'; + color = 0x00ff00; + price = (result.price / 1000000).toFixed(2); + } + + embed.setColor(color).addFields({ + name: 'Is the domain available?', + value: isDomainAvailable, + }); + + if (price) { + embed.addFields({ name: 'Price', value: `$${price}` }); + } + } catch (error) { + console.error(`Error looking up domain: ${domain}.`, error); + await interaction.reply('An error occurred when querying the GoDaddy API.'); + return; + } + + await interaction.reply({ embeds: [embed] }); +} + +export default { data, execute }; diff --git a/src/commands/lookup/imdb.js b/src/commands/lookup/imdb.js new file mode 100644 index 0000000..84bebdd --- /dev/null +++ b/src/commands/lookup/imdb.js @@ -0,0 +1,71 @@ +import { EmbedBuilder, SlashCommandBuilder } from 'discord.js'; +import axios from 'axios'; + +const OMDB_API_URL = 'http://www.omdbapi.com/?apikey={apiKey}'; +const FIELDS = [ + 'Title', + 'Year', + 'Rated', + 'Released', + 'Genre', + 'Director', + 'Actors', + 'Plot', + 'imdbRating', + 'BoxOffice', +]; + +const data = new SlashCommandBuilder() + .setName('imdb') + .setDescription('Return IMDB listing for the specified film.') + .addStringOption((option) => + option + .setName('film_name') + .setDescription('The name of the film') + .setRequired(true) + ) + .addIntegerOption((option) => + option + .setName('film_year') + .setDescription('The year the specified film was released') + .setMinValue(1800) + .setMaxValue(2100) + ); + +async function execute(interaction) { + const filmName = interaction.options.getString('film_name'); + const filmYear = interaction.options.getInteger('film_year'); + let embed = new EmbedBuilder().setTitle('IMDB').setColor(0xf5de50); + + let omdbQueryUrl = OMDB_API_URL.replace('{apiKey}', process.env.OMDB_API_KEY); + omdbQueryUrl += `&t=${encodeURIComponent(filmName.toLowerCase())}`; + + if (filmYear) { + omdbQueryUrl += `&y=${filmYear}`; + } + + try { + const response = await axios.get(omdbQueryUrl, { timeout: 5000 }); + const result = response.data; + + FIELDS.forEach((field) => { + const fieldValue = result[field]; + if (fieldValue) { + embed.addFields({ name: field, value: fieldValue }); + } + }); + + const poster = result.Poster; + if (poster) { + embed.setImage(poster); + } + } catch (error) { + console.error(`Error looking up film: ${filmName}.`, error); + await interaction.reply('An error occurred when querying the OMDB API.'); + return; + } + + await interaction.reply({ embeds: [embed] }); +} + +export default { data, execute }; diff --git a/src/commands/lookup/plant.js b/src/commands/lookup/plant.js new file mode 100644 index 0000000..1b9375f --- /dev/null +++ b/src/commands/lookup/plant.js @@ -0,0 +1,75 @@ +import { EmbedBuilder, SlashCommandBuilder } from 'discord.js'; +import axios from 'axios'; + +const API_URL = 'https://my-api.plantnet.org/v2/identify/all?api-key={apiKey}'; +const LEAF_THUMBNAIL = + 'https://cdn.discordapp.com/attachments/870024275556446328/1006249009201033287/monstera.png'; + +const data = new SlashCommandBuilder() + .setName('plant') + .setDescription('Identify a plant by uploading an image.') + .addAttachmentOption((option) => + option + .setName('image') + .setDescription('The image of the plant to identify') + .setRequired(true) + ); + +async function execute(interaction) { + const image = interaction.options.getAttachment('image'); + let embed = new EmbedBuilder() + .setTitle('Plant Detector™️') + .setThumbnail(LEAF_THUMBNAIL) + .setColor(0xff0000); + + try { + const response = await axios.get( + API_URL.replace('{apiKey}', process.env.PLANTNET_API_KEY), + { + params: { + images: image.url, + organs: 'leaf', + }, + timeout: 5000, + } + ); + + const bestMatch = response.data.results[0]; + const commonName = + bestMatch.species.commonNames[0] || 'No common name found'; + const scientificName = bestMatch.species.scientificNameWithoutAuthor; + const confidence = parseFloat(bestMatch.score); + + let detail = ''; + + if (0.0 <= confidence && confidence < 0.25) { + detail = `I'm really not sure, but I think that looks like a **${commonName}**?`; + } else if (0.25 <= confidence && confidence < 0.5) { + detail = `I think that looks like a **${commonName}**!`; + } else if (0.5 <= confidence && confidence < 0.75) { + detail = `That looks like a **${commonName}**!`; + } else if (confidence >= 0.75) { + detail = `That is a really cool **${commonName}**!`; + } + + const imageUrl = `https://www.google.com/search?q=${encodeURIComponent(commonName || scientificName)}&tbm=isch`; + + detail += `\n\n**Scientific Name**: ${scientificName}`; + detail += `\n\n**Images**: [More images](${imageUrl})`; + detail += `\n\n**Confidence**: ${(confidence * 100).toFixed(3)}%`; + + embed + .setColor(0x00ff00) + .addFields({ name: 'Plant Details', value: detail }); + } catch (error) { + console.error(`Error looking up plant: ${image.url}`, error); + await interaction.reply( + 'An error occurred when querying the PlantNet API.' + ); + return; + } + + await interaction.reply({ embeds: [embed] }); +} + +export default { data, execute }; diff --git a/src/commands/memes/2020.js b/src/commands/memes/2020.js new file mode 100644 index 0000000..4349c10 --- /dev/null +++ b/src/commands/memes/2020.js @@ -0,0 +1,14 @@ +import { SlashCommandBuilder } from 'discord.js'; + +const TWENTY_TWENTY_IMAGE = + 'https://cdn.discordapp.com/attachments/506852356898422797/765256712063025172/unknown.png'; + +const data = new SlashCommandBuilder() + .setName('2020') + .setDescription('Returns a tweet from Boris, posted on 2 January 2020.'); + +async function execute(interaction) { + await interaction.reply(TWENTY_TWENTY_IMAGE); +} + +export default { data, execute }; diff --git a/src/commands/memes/8ball.js b/src/commands/memes/8ball.js new file mode 100644 index 0000000..3d85ba0 --- /dev/null +++ b/src/commands/memes/8ball.js @@ -0,0 +1,45 @@ +import { SlashCommandBuilder } from 'discord.js'; + +const data = new SlashCommandBuilder() + .setName('8ball') + .setDescription('Returns a Magic 8 ball response.') + .addStringOption((option) => + option + .setName('question') + .setDescription('The question to ask the Magic 8 ball') + .setRequired(true) + ); + +const MAGIC_EIGHT_BALL_RESPONSES = [ + 'As I see it, yes.', + 'Ask again later.', + 'Better not tell you now.', + 'Cannot predict now.', + 'Concentrate and ask again.', + "Don't count on it.", + 'It is certain.', + 'It is decidedly so.', + 'Most likely.', + 'My reply is no.', + 'My sources say no.', + 'Outlook not so good.', + 'Outlook good.', + 'Reply hazy, try again.', + 'Signs point to yes.', + 'Very doubtful.', + 'Without a doubt.', + 'Yes.', + 'Yes - definitely.', + 'You may rely on it.', +]; + +async function execute(interaction) { + const randomIndex = Math.floor( + Math.random() * MAGIC_EIGHT_BALL_RESPONSES.length + ); + const response = MAGIC_EIGHT_BALL_RESPONSES[randomIndex]; + + await interaction.reply(response); +} + +export default { data, execute }; diff --git a/src/commands/memes/birthday.js b/src/commands/memes/birthday.js new file mode 100644 index 0000000..a7f2b7c --- /dev/null +++ b/src/commands/memes/birthday.js @@ -0,0 +1,60 @@ +import { SlashCommandBuilder } from 'discord.js'; +import { + format, + differenceInYears, + differenceInMonths, + differenceInDays, + addYears, + isToday, +} from 'date-fns'; + +const BIRTHDAY_TIMESTAMP = 1582576229; + +const data = new SlashCommandBuilder() + .setName('birthday') + .setDescription("Returns ButlerBot's Birthday information."); + +async function execute(interaction) { + const today = new Date(); + const birthday = new Date(BIRTHDAY_TIMESTAMP * 1000); + + const ageYears = differenceInYears(today, birthday); + const ageMonths = differenceInMonths(today, birthday) % 12; + const ageDays = differenceInDays(today, addYears(birthday, ageYears)) % 30; + + let ageMessage = `I am ${ageYears} year`; + ageMessage += ageYears !== 1 ? 's, ' : ', '; + ageMessage += `${ageMonths} month`; + ageMessage += ageMonths !== 1 ? 's ' : ' '; + ageMessage += `and ${ageDays} day`; + ageMessage += ageDays !== 1 ? 's ' : ' '; + ageMessage += 'old!'; + + let birthdayMessage = `I was created on ${format(birthday, 'dd MMMM yyyy')}.`; + + const nextBirthdayYear = + today.getMonth() > birthday.getMonth() || + (today.getMonth() === birthday.getMonth() && + today.getDate() >= birthday.getDate()) + ? today.getFullYear() + 1 + : today.getFullYear(); + const nextBirthday = new Date( + nextBirthdayYear, + birthday.getMonth(), + birthday.getDate() + ); + const countdown = differenceInDays(nextBirthday, today); + + if (isToday(nextBirthday)) { + birthdayMessage += " It's my Birthday today!"; + } else if (countdown === 1) { + birthdayMessage += " It's my Birthday tomorrow!"; + } else { + birthdayMessage += ` It's my Birthday in ${countdown} days!`; + } + + const fullMessage = `${ageMessage} ${birthdayMessage}`; + await interaction.reply(fullMessage); +} + +export default { data, execute }; diff --git a/src/commands/memes/corrupt.js b/src/commands/memes/corrupt.js new file mode 100644 index 0000000..4772bd2 --- /dev/null +++ b/src/commands/memes/corrupt.js @@ -0,0 +1,16 @@ +import { SlashCommandBuilder } from 'discord.js'; + +const CORRUPT_IMAGE = + 'https://media.discordapp.net/attachments/506852356898422797/717395817626861638/isntthatcorrupt2.PNG'; + +const data = new SlashCommandBuilder() + .setName('corrupt') + .setDescription( + "Returns a powerful quote from Neil Breen's infamous indie film, Pass Thru (2016)." + ); + +async function execute(interaction) { + await interaction.reply(CORRUPT_IMAGE); +} + +export default { data, execute }; diff --git a/src/commands/memes/eyecandy.js b/src/commands/memes/eyecandy.js new file mode 100644 index 0000000..ab9a94f --- /dev/null +++ b/src/commands/memes/eyecandy.js @@ -0,0 +1,40 @@ +import { SlashCommandBuilder } from 'discord.js'; +import axios from 'axios'; + +const GIPHY_API_URL = 'http://api.giphy.com/v1/gifs/search'; + +const data = new SlashCommandBuilder() + .setName('eyecandy') + .setDescription('Returns a random gif of Gerard Butler.'); + +async function execute(interaction) { + const giphyApiKey = process.env.GIPHY_API_KEY; + + if (!giphyApiKey) { + await interaction.reply( + 'The bot has not been configured with a Giphy API key.' + ); + return; + } + + const randomOffset = Math.floor(Math.random() * 100); + const giphyQueryUrl = `${GIPHY_API_URL}?api_key=${giphyApiKey}&q=gerard+butler&limit=1&offset=${randomOffset}`; + + try { + const response = await axios.get(giphyQueryUrl, { timeout: 5000 }); + const result = response.data; + + if (result.data.length === 0) { + await interaction.reply('No gifs found.'); + return; + } + + const imageUrl = result.data[0].images.original.url; + await interaction.reply(imageUrl); + } catch (error) { + console.error('Error querying the Giphy API:', error); + await interaction.reply('An error occurred when querying the Giphy API.'); + } +} + +export default { data, execute }; diff --git a/src/commands/memes/kanye.js b/src/commands/memes/kanye.js new file mode 100644 index 0000000..944982c --- /dev/null +++ b/src/commands/memes/kanye.js @@ -0,0 +1,139 @@ +import { SlashCommandBuilder } from 'discord.js'; + +const KANYE_QUOTES = [ + '2024.', + 'All you have to be is yourself.', + 'Believe in your flyness... conquer your shyness.', + 'Burn that Excel spreadsheet.', + 'Decentralize.', + 'Distraction is the enemy of vision.', + 'Everything you do in life stems from either fear or love.', + 'For me giving up is way harder than trying.', + 'For me, money is not my definition of success. Inspiring people is a definition of success.', + 'Fur pillows are hard to actually sleep on.', + "George Bush doesn't care about black people.", + 'Have you ever thought you were in love with someone but then realized you were just staring in a mirror for 20 minutes?', + 'I care. I care about everything. Sometimes not giving a f#%k is caring the most.', + 'I feel calm but energized.', + "I feel like I'm too busy writing history to read it.", + 'I feel like me and Taylor might still have sex.', + 'I give up drinking every week.', + 'I leave my emojis Bart Simpson color.', + "I love sleep; it's my favorite.", + 'I make awesome decisions in bike stores!!!', + "I really love my Tesla. I'm in the future. Thank you Elon.", + 'I still think I am the greatest.', + "I think I do myself a disservice by comparing myself to Steve Jobs and Walt Disney and human beings that we've seen before. It should be more like Willy Wonka...and welcome to my chocolate factory.", + 'I want the world to be better! All I want is positive! All I want is dopeness!', + 'I wish I had a friend like me.', + "I'd like to meet with Tim Cook. I got some ideas.", + "I'll say things that are serious and put them in a joke form so people can enjoy them. We laugh to keep from crying.", + "I'm a creative genius.", + "I'm nice at ping pong.", + "I'm the best.", + "If I don't scream, if I don't say something then no one's going to say anything.", + 'If I got any cooler I would freeze to death.', + "If you have the opportunity to play this game of life you need to appreciate every moment. a lot of people don't appreciate the moment until it's passed.", + 'Just stop lying about shit. Just stop lying.', + 'Keep squares out yo circle.', + 'Keep your nose out the sky, keep your heart to god, and keep your face to the rising sun.', + "Let's be like water.", + 'Man... whatever happened to my antique fish tank?', + 'My dad got me a drone for Christmas.', + "My greatest award is what I'm about to do.", + 'My greatest pain in life is that I will never be able to see myself perform live.', + "One day I'm gon' marry a porn star.", + "One of my favorite of many things about what the Trump hat represents to me is that people can't tell me what to do because I'm black.", + 'Only free thinkers.', + "People always say that you can't please everybody. I think that's a cop-out. Why not attempt it? Cause think of all the people that you will please if you try.", + "People always tell you 'Be humble. Be humble.' When was the last time someone told you to be amazing? Be great! Be awesome! Be awesome!", + 'People only get jealous when they care.', + 'Perhaps I should have been more like water today.', + 'Pulling up in the may bike.', + 'Shut the fuck up I will fucking laser you with alien fucking eyes and explode your fucking head.', + 'Sometimes I push the door close button on people running towards the elevator. I just need my own elevator sometimes. My sanctuary.', + 'Sometimes you have to get rid of everything.', + 'Style is genderless.', + 'The thought police want to suppress freedom of thought.', + 'The world is our family.', + 'The world is our office.', + "Today is the best day ever and tomorrow's going to be even better.", + "Truth is my goal. Controversy is my gym. I'll do a hundred reps of controversy for a 6 pack of truth.", + 'Tweeting is legal and also therapeutic.', + "We all self-conscious. I'm just the first to admit it.", + "We came into a broken world. And we're the cleanup crew.", + "You can't look at a glass half full or empty if it's overflowing.", + "I hate when I'm on a flight and I wake up with a water bottle next to me like oh great now I gotta be responsible for this water bottle.", + 'All the musicians will be free.', + 'Artists are founders.', + 'Buy property.', + 'Culture is the most powerful force in humanity under God.', + 'Empathy is the glue.', + 'I am one of the most famous people on the planet.', + 'I am running for President of the United States.', + 'I am the head of Adidas. I will bring Adidas and Puma back together and bring me and jay back together.', + 'I am Warhol. I am the No. 1 most impactful artist of our generation. I am Shakespeare in the flesh.', + "I channel Will Ferrell when I'm at the daddy daughter dances.", + "I don't wanna see no woke tweets or hear no woke raps ... it's show time ... it's a whole different energy right now.", + 'I hear people say this person is cool and this person is not cool. People are cool. Man has never invented anything as awesome as a an actual person but sometimes we value the objects we create over life itself.', + 'I honestly need all my Royeres to be museum quality... if I see a fake Royere Ima have to Rick James your couch.', + 'I love UZI. I be saying the same thing about Steve Jobs. I be feeling just like UZI.', + 'I need an army of angels to cover me while I pull this sword out of the stone.', + 'I spoke to Dave Chapelle for two hours this morning. He is our modern day Socrates.', + 'I was just speaking with someone that told me their life story and they used to be homeless.', + 'I watch Bladerunner on repeat.', + "I'm giving all Good music artists back the 50% share I have of their masters.", + "I'm going to personally see to it that Taylor Swift gets her masters back. Scooter is a close family friend.", + "I'm the new Moses.", + 'Life is the ultimate gift.', + 'Ma$e is one of my favorite rappers and I based a lot of my flows off of him.', + 'Manga all day.', + "My first pillar when I'm on the board of adidas will be an adidas Nike collaboration to support community growth.", + "My mama was a' English teacher. I know how to use correct English but sometimes I just don't feel like it aaaand I ain't got to.", + 'My memories are from the future.', + 'My mother in law Kris Jenner ... makes the best music playlist.', + "People say it's enough and I got my point across ... the point isn't across until we cross the point.", + 'People tried to talk me out of running for President. Never let weak controlling people kill your spirit.', + 'So many of us need so much less than we have especially when so many of us are in need.', + "Speak God's truth to power.", + 'The media tries to kill our heroes one at a time.', + 'The world needs more Joy... this idea is super fresh.', + 'There are 5 main pillars in a professional musicians business - Recording, Publishing, Touring, Merchandise & Name and likeness.', + 'There are people sleeping in parking lots.', + "There's a crying need for civility across the board. We need to and will come together in the name of Jesus.", + "There's so many lonely emojis man.", + "Trust me ... I won't stop.", + 'Two years ago we had 50 million people subscribed to music streaming services around the world. Today we have 400 million.', + 'We are here to complete the revolution. We are building the future.', + 'We as a people will heal. We will insure the well being of each other.', + 'We have to evolve.', + 'We must and will cure homelessness and hunger. We have the capability as a species.', + 'We must form a union. We must unify.', + 'We used to diss Michael Jackson the media made us call him crazy ... then they killed him.', + 'We will be recognized.', + 'We will change the paradigm.', + 'We will cure hunger.', + 'We will heal. We will cure.', + "We're going to move the entire music industry into the 21st Century.", + "We've gotten comfortable with not having what we deserve.", + 'Who made up the term major label in the first place???', + 'Winning is the only option.', + "For me to say I wasn't a genius I'd just be lying to you and to myself.", + "I've known my mom since I was zero years old. She is quite dope.", + "I don't expect to be understood at all.", + "I'm on the pursuit of awesomeness, excellence is the bare minimum.", + 'You basically can say anything to someone on an email or text as long as you put LOL at the end.', +]; + +const data = new SlashCommandBuilder() + .setName('kanye') + .setDescription('Returns a random Kanye West quote.'); + +async function execute(interaction) { + const randomIndex = Math.floor(Math.random() * KANYE_QUOTES.length); + const quote = KANYE_QUOTES[randomIndex]; + + await interaction.reply(quote); +} + +export default { data, execute }; diff --git a/src/commands/memes/reminder.js b/src/commands/memes/reminder.js new file mode 100644 index 0000000..1700df6 --- /dev/null +++ b/src/commands/memes/reminder.js @@ -0,0 +1,14 @@ +import { SlashCommandBuilder } from 'discord.js'; + +const REMINDER_IMAGE = + 'https://media.discordapp.net/attachments/506852356898422797/715690132883111996/Capture.PNG'; + +const data = new SlashCommandBuilder() + .setName('reminder') + .setDescription('Returns an image which must always be remembered.'); + +async function execute(interaction) { + await interaction.reply(REMINDER_IMAGE); +} + +export default { data, execute }; diff --git a/src/commands/memes/taylor.js b/src/commands/memes/taylor.js new file mode 100644 index 0000000..13527c7 --- /dev/null +++ b/src/commands/memes/taylor.js @@ -0,0 +1,184 @@ +import { SlashCommandBuilder } from 'discord.js'; + +const TAYLOR_QUOTES = [ + "I don't know what I want, so don't ask me, 'cause I'm still trying to figure it out.", + 'When you think Tim McGraw, I hope you think of me.', + 'So watch me strike a match on all my wasted time.', + "I'll be strong, I'll be wrong, oh but life goes on…", + 'And when you take, you take the very best of me.', + "But no one notices until it's too late to do anything.", + "Our song is the slamming screen door, sneakin' out late, tapping on your window.", + "And I don't know why, but with you I'd dance in a storm in my best dress, fearless.", + "But in your life, you'll do things greater than dating the boy on the football team…But I didn't know it at fifteen.", + "I've found time can heal most anything and you just might find who you're supposed to be.", + "Romeo, save me. They're trying to tell me how to feel. This love is difficult but it's real.", + 'Why are people always leaving? I think you and I should stay the same.', + "My mistake, I didn't know to be in love you had to fight to have the upper hand.", + 'This is a big world, that was a small town there in my rear view mirror disappearing now.', + "You've got a smile that could light up this whole town.", + "And we know it's never simple, never easy. Never a clean break, no one here to save me.", + 'You took a swing, I took it hard. And down here from the ground I see who you are.', + "All this time I was wasting, hoping you would come around… I've been giving out chances every time and all you do is let me down.", + "And then you feel so low you can't feel nothing at all.", + "It rains when you're here and it rains when you're gone.", + 'These walls that they put up to hold us back will fall down…', + "My mind forgets to remind me you're a bad idea.", + "It turns out freedom ain't nothing but missing you.", + "She floats down the aisle like a pageant queen, but I know you wish it was me… don't you?", + 'I lived in your chess game, but you changed the rules every day.', + "I'm shining like fireworks over your sad, empty town.", + "Someday I'll be living in a big, old city and all you're ever gonna be is mean.", + "I'd tell you I miss you, but I don't know how, I've never heard silence quite this loud.", + 'This is looking like a contest of who can act like they care less. But I liked it better when you were on my side.', + "And don't lose the way that you dance around in your pj's getting ready for school.", + "This night is sparkling, don't you let it go. I'm wonderstruck, blushing all the way home.", + '2AM, who do you love?', + "Your string of lights is still bright to me… Who you are is not where you've been.", + 'Today is never too late to be brand new.', + "You and I walk a fragile line; I have known it all this time. But I never thought I'd live to see it break.", + "I don't know how to be something you miss.", + 'Bring on all the pretenders. One day, we will be remembered.', + "So don't you worry your pretty, little mind, people throw rocks at things that shine.", + "We are alone with our changing minds. We fall in love 'til it hurts or bleeds or fades in time.", + 'Love is a ruthless game unless you play it good and right.', + "He's long gone when he's next to me and I realize the blame is on me.", + "No apologies. He'll never see you cry. Pretends he doesn't know that he's the reason why.", + 'The saddest fear comes creeping in - that you never loved me or her, or anyone, or anything...', + "…That magic's not here no more. And I might be OK, but I'm not fine at all.", + "And your mother's telling stories about you on a tee ball team. You taught me 'bout your past, thinking your future was me.", + 'I forget about you long enough to forget why I needed to...', + "Maybe we got lost in translation, maybe I asked for too much. But maybe this thing was a masterpiece 'til you tore it all up. Running scared, I was there, I remember it all too well.", + 'You call me up again just to break me like a promise, so casually cruel in the name of being honest.', + "Time won't fly, it's like I'm paralyzed by it. I'd like to be my old self again, but I'm still trying to find it.", + "Cause there we are again, when I loved you so, back before you lost the one, real thing you've ever known.", + "Now you mail back my things and I walk home alone, but you keep my old scarf from that very first week, 'cause it reminds you of innocence and it smells like me.", + "Stay, and I'll be loving you for quite some time. No one else is gonna love me when I get mad.", + "We're happy, free, confused, and lonely at the same time. It's miserable and magical.", + "I wish I could run to you. And I hope you know that every time I don't I almost do.", + 'You wear your best apology, but I was there to watch you leave.', + 'But sometimes I wonder how you think about it now.', + "But I don't wanna dance if I'm not dancing with you.", + "Words, how little they mean when you're a little too late.", + "And they tell you that you're lucky, but you're so confused, 'cause you don't feel pretty, you just feel used.", + "I've been spending the last eight months thinking all love ever does is break and burn and end...", + "And what do you do when the one who means the most to you is the one who didn't show?", + "Your close friends always seem to know when there's something really wrong", + 'You called me later and said, "I\'m sorry I didn\'t make it". And I said, "I\'m sorry, too".', + 'Loving him is like driving a new Maserati down a dead-end street - faster than the wind, passionate as sin, ending so suddenly.', + 'The lights are so bright, but they never blind me.', + "Love's a game, wanna play?", + "So it's gonna be forever or it's gonna go down in flames.", + "But you'll come back each time you leave 'cause darling, I'm a nightmare dressed like a daydream.", + "When we go crashing down, we come back every time 'cause we never go out of style.", + 'I got that red lip, classic thing that you like.', + 'The rest of the world was black and white, but we were in screaming color.', + 'The more I think about it now, the less I know, all I know is that you drove us off the road.', + 'People like you always want back the love they pushed aside, but people like me are gone forever when you say goodbye.', + "Why'd you have to go and lock me out when I let you in?", + "While you've been getting down and out about the liars and the dirty, dirty cheats of the world… You could've been getting down to this sick beat.", + "We're a crooked love in a straight line down.", + 'And I wish you knew that I miss you too much to be mad anymore.', + 'You give me everything and nothing.', + 'Makes you wanna run and hide, but it made us turn right back around.', + "Band-aids don't fix bullet holes. You say sorry just for show.", + 'Someday when you leave me, I bet these memories follow you around.', + "When you're young, you just run, but you come back to what you need.", + 'This love left a permanent mark.', + 'Your kiss, my cheek; I watch you leave. Your smile, my ghost; I fall to my knees.', + "It was months and months of back and forth, you're still all over me like a wine-stained dress I can't wear anymore.", + "When I was drowning that's when I could finally breathe.", + "Just because you're clean, don't mean you don't miss it.", + "Didn't it all seem new and exciting? …It's all fun and games 'til somebody loses their mind.", + 'You search the world for something else to make you feel like what we had. And in the end in wonderland, we both went mad.', + 'Heartbreak is the national anthem, we sing it proudly.', + "They'll take their shots, but we are bulletproof.", + 'So I punched a hole in the roof; let the flood carry away all my pictures of you.', + 'When all you wanted was to be wanted; wish you could go back and tell yourself what you know now.', + "32 and still growing up now. Who you are is not what you did. You're still an innocent.", + "We play dumb but we know exactly what we're doing.", + "Please don't ever become a stranger whose laugh I could recognize anywhere.", + 'Can we always be this close forever and ever?', + "I'm only seventeen. I don't know anything but I know I miss you.", + 'I was walking home on broken cobblestones just thinking of you, when she pulled up like a figment of my worst intentions.', + 'You play stupid games, you win stupid prizes.', + 'I had a marvelous time ruining everything.', + "Untouchable, burning brighter than the sun, and when you're close I feel like coming undone.", + 'I could build a castle out of all the bricks they threw at me.', + 'Cold was the steel of my axe to grind for the boys who broke my heart. Now I send their babies presents.', + 'Back when you fit in my poems like a perfect rhyme.', + "I once believed love would be burning red... but it's golden.", + 'The monsters turned out to be just trees, when the sun came up you were looking at me.', + "I can't decide if it's a choice: getting swept away?", + 'They told me all of my cages were mental, so I got wasted like all my potential.', + "I don't like that falling feels like flying till the bone crush.", + 'I persist and resist the temptation to ask you: "If one thing had been different, would everything be different today?"', + 'When you are young they assume you know nothing.', + "You drew stars around my scars, but now I'm bleeding.", + 'You wear the same jewels that I gave you, as you bury me.', + "We gather stones, never knowing what they'll mean - some to throw, some to make a diamond ring.", + 'Bold was the waitress on our three-year trip... Getting lunch down by the Lakes, she said I looked like an American singer.', + 'One single thread of gold tied me to you.', + "I swear I don't love the drama, it loves me.", + "I bury hatchets, but I keep maps of where I put 'em.", + "Love made me crazy, if it doesn't, you ain't doin' it right.", + "My name is whatever you decide, and I'm just gonna call you mine.", + "Handsome, you're a mansion with a view.", + 'Sometimes I wonder when you sleep, are you ever dreaming of me?', + 'The world goes on another day, another drama. But not for me, all I think about is karma.', + 'You asked me for a place to sleep, locked me out and threw a feast.', + "You know I'm not a bad girl, but I do bad things with you.", + "You did a number on me but, honestly, baby, who's counting?", + 'Ocean blue eyes looking in mine. I feel like I might sink and drown and die.', + "Your love is a secret I'm hoping, dreaming, dying to keep.", + 'Is this the end of all the endings? My broken bones are mending.', + 'I loved you in spite of deep fears that the world would divide us.', + "Say that we got it! I'm a mess, but I'm the mess that you wanted!", + 'I brought a knife to a gunfight.', + 'He built a fire just to keep me warm.', + 'I want to wear his initial on a chain round my neck, not because he owns me, but cause he really knows me, which is more than they can say.', + 'Holding my breath, slowly, I said "You don\'t need to save me, but would you run away with me?"', + "Would've been right there, front row even if nobody came to your show.", + "I'm always waiting for you to be waiting below.", + "I don't wanna keep secrets just to keep you.", + "I'm drunk in the back of the car and I cried like a baby coming home from the bar. Said, \"I'm fine,\" but it wasn't true.", + "For whatever it's worth, I love you, ain't that the worst thing you ever heard?", + "I've got a hundred thrown-out speeches I almost said to you.", + "I am an architect, I'm drawing up the plans.", + "I'll never let you go 'cause I know this is a fight that someday we're gonna win.", + "I'm with you even if it makes me blue.", + "Without all the exes, fights, and flaws, we wouldn't be standing here so tall.", + 'We were a fresh page on the desk, filling in the blanks as we go.', + 'We were in the backseat drunk on something stronger than the drinks in the bar.', + 'If the story is over, why am I still writing pages?', + "I ask the traffic lights if it will be alright, they say I don't know.", + "They say home is where the heart is, but that's not where mine lives.", + 'I pinned your hands behind your back. Thought I had reason to attack, but no.', + "Fighting with a true love is boxing with no gloves... Chemistry 'til it blows up, 'til there's no us.", + "And I can't talk to you when you're like this, staring out the window like I'm not your favorite town.", + 'They say the road gets hard and you get lost.', + "Remember how I said I'd die for you?", + "I come back stronger than a '90s trend.", + '"This dorm was once a madhouse." I made a joke: "Well, it\'s made for me."', + "Sometimes you just don't know the answer 'til someone's on their knees and asks you.", + "I can't dare to dream about you anymore.", + 'I parked my car right between the Methodist and the school that used to be ours.', + "I'll go back to L.A. and the so-called friends who'll write books about me if I ever make it and wonder about the only soul who can tell which smiles I'm fakin'.", + 'What would you do if I break free and leave us in ruins, took this dagger in me and removed it, gain the weight of you then loose it?', + 'Your nemesis will defeat themselves before you get the chance to swing.', + 'My waves meet your shore ever and evermore.', + 'I replay my footsteps on each stepping stone, trying to find the one where I went wrong.', + "He can't see the smile I'm faking and my heart's not breaking 'cause I'm not feeling anything at all.", +]; + +const data = new SlashCommandBuilder() + .setName('taylor') + .setDescription('Returns a random Taylor Swift quote.'); + +async function execute(interaction) { + const randomIndex = Math.floor(Math.random() * TAYLOR_QUOTES.length); + const quote = TAYLOR_QUOTES[randomIndex]; + + await interaction.reply(quote); +} + +export default { data, execute }; diff --git a/src/commands/utilities/countdown.js b/src/commands/utilities/countdown.js new file mode 100644 index 0000000..9205706 --- /dev/null +++ b/src/commands/utilities/countdown.js @@ -0,0 +1,24 @@ +import { SlashCommandBuilder } from 'discord.js'; + +const data = new SlashCommandBuilder() + .setName('countdown') + .setDescription('Start a five second countdown.'); + +async function execute(interaction) { + // Initial response to acknowledge the command + await interaction.reply({ content: 'Starting countdown...' }); + + // Initial delay before starting the countdown + await new Promise((resolve) => setTimeout(resolve, 2000)); // 2-second delay + + // Edit the response with the countdown + for (let i = 5; i > 0; i--) { + await interaction.editReply({ content: String(i) }); + await new Promise((resolve) => setTimeout(resolve, 1000)); // 1-second delay between numbers + } + + // Final message + await interaction.editReply({ content: '🎉 GO! 🎉' }); +} + +export default { data, execute }; diff --git a/src/commands/utilities/servertime.js b/src/commands/utilities/servertime.js new file mode 100644 index 0000000..e9fc4a9 --- /dev/null +++ b/src/commands/utilities/servertime.js @@ -0,0 +1,14 @@ +import { SlashCommandBuilder } from 'discord.js'; +import { format } from 'date-fns'; + +const data = new SlashCommandBuilder() + .setName('servertime') + .setDescription("Returns the server's current time."); + +async function execute(interaction) { + const now = new Date(); + const formattedTime = format(now, 'dd/MM/yyyy HH:mm:ss'); + await interaction.reply(`The server's current time is: ${formattedTime}`); +} + +export default { data, execute }; diff --git a/src/commands/work/payday.js b/src/commands/work/payday.js new file mode 100644 index 0000000..c617109 --- /dev/null +++ b/src/commands/work/payday.js @@ -0,0 +1,111 @@ +import { EmbedBuilder, SlashCommandBuilder } from 'discord.js'; +import { + format, + addDays, + subDays, + getDay, + differenceInDays, + startOfToday, + set, +} from 'date-fns'; + +const ARM_EMPLOYEES = [141339536453140480]; +const ARM_THUMBNAIL = + 'https://cdn.discordapp.com/attachments/724000975626698894/928379448301088868/unknown.png'; +const BAE_THUMBNAIL = + 'https://cdn.discordapp.com/attachments/724000975626698894/928380073965408306/Untitled-1.png'; + +// Adjust payday for weekends +function adjustPayday(payday) { + const dayOfWeek = getDay(payday); + + if (dayOfWeek === 6) { + // Saturday + return subDays(payday, 1); + } else if (dayOfWeek === 0) { + // Sunday + return subDays(payday, 2); + } + + return payday; +} + +// Calculate next payday based on the current date +function calculateNextPayday( + payday = 22, + currentDate = new Date(), + adjust = 0 +) { + let theoreticalPayday = set(currentDate, { date: payday }); + let adjustedPayday = adjustPayday(theoreticalPayday); + + if (adjustedPayday < currentDate) { + theoreticalPayday = set(addDays(currentDate, adjust * 30), { + date: payday, + }); + adjustedPayday = adjustPayday(theoreticalPayday); + } + + return adjustedPayday; +} + +const data = new SlashCommandBuilder() + .setName('payday') + .setDescription('Calculate the number of days until the next payday.'); + +async function execute(interaction) { + const authorId = interaction.user.id; + const embed = new EmbedBuilder().setTitle('Payday'); + + let payday = 22; + let thumbnailUrl = BAE_THUMBNAIL; + let color = 0xf26521; + + if (ARM_EMPLOYEES.includes(authorId)) { + payday = 26; + thumbnailUrl = ARM_THUMBNAIL; + color = 0x0091bd; + } + + const nextPayday = calculateNextPayday(payday); + const daysToNextPayday = differenceInDays(nextPayday, startOfToday()); + + let monzoDaysToNextPayday = differenceInDays( + subDays(nextPayday, 1), + startOfToday() + ); + if (monzoDaysToNextPayday < 0) { + monzoDaysToNextPayday = differenceInDays( + subDays(calculateNextPayday(payday, new Date(), 1), 1), + startOfToday() + ); + } + + embed + .setColor(color) + .setThumbnail(thumbnailUrl) + .addFields( + { + name: '💳 Days to go', + value: `${daysToNextPayday} day${daysToNextPayday !== 1 ? 's' : ''}`, + inline: true, + }, + { + name: '<:monzo:764978030653210705> Days to go', + value: `${monzoDaysToNextPayday} day${monzoDaysToNextPayday !== 1 ? 's' : ''}`, + inline: true, + } + ); + + if (!ARM_EMPLOYEES.includes(authorId)) { + embed.addFields({ + name: '💸 Inconvenience', + value: nextPayday.getMonth() % 3 === 0 ? '💰💰💰' : '🗑️🗑️🗑️', + inline: false, + }); + } + + await interaction.reply({ embeds: [embed] }); +} + +export default { data, execute }; diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..4f213db --- /dev/null +++ b/src/index.js @@ -0,0 +1,45 @@ +import { Client, Collection, Events, GatewayIntentBits } from 'discord.js'; +import { loadCommandModules } from '../lib/utilities/commandModules.js'; + +const client = new Client({ intents: [GatewayIntentBits.Guilds] }); + +// Load all command modules and set them in the client. +client.commands = new Collection(); +const commandModules = await loadCommandModules(); +commandModules.forEach((module) => { + client.commands.set(module.data.name, module); +}); + +// Register the event listener for command interactions. +client.on(Events.InteractionCreate, async (interaction) => { + if (!interaction.isChatInputCommand()) return; + + const command = client.commands.get(interaction.commandName); + if (!command) { + console.warn(`Command ${interaction.commandName} not found.`); + return; + } + + try { + await command.execute(interaction); + } catch (error) { + console.error(error); + if (interaction.replied || interaction.deferred) { + await interaction.followUp({ + content: 'There was an error while executing this command!', + ephemeral: true, + }); + } else { + await interaction.reply({ + content: 'There was an error while executing this command!', + ephemeral: true, + }); + } + } +}); + +client.once(Events.ClientReady, (readyClient) => { + console.log(`Ready! Logged in as ${readyClient.user.tag}`); +}); + +client.login(process.env.DISCORD_TOKEN); diff --git a/src/register-slash-commands.js b/src/register-slash-commands.js new file mode 100644 index 0000000..9f00793 --- /dev/null +++ b/src/register-slash-commands.js @@ -0,0 +1,25 @@ +import { REST, Routes } from 'discord.js'; +import { loadCommandModules } from '../lib/utilities/commandModules.js'; + +// Register all slash commands, globally across all Guilds. +const commandModules = await loadCommandModules(); +const commands = commandModules.map((commandModule) => + commandModule.data.toJSON() +); + +const rest = new REST().setToken(process.env.DISCORD_TOKEN); + +try { + console.log('Started refreshing application (/) commands.'); + + // Refresh all slash commands globally. + const data = await rest.put( + Routes.applicationCommands(process.env.DISCORD_APPLICATION_ID), + { body: commands } + ); + + console.log(`Successfully reloaded ${data.length} application (/) commands.`); +} catch (error) { + // And of course, make sure you catch and log any errors! + console.error(error); +}