From f8780249ce80f5c0fea5fdc3d40bdf16e0ef3562 Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Mon, 22 Jul 2024 09:19:12 +0000 Subject: [PATCH] architecture besides db setup, say+roll --- .gitignore | 3 + commands/error.ts | 2 + commands/index.ts | 78 ++++++++ commands/roll.ts | 39 ++++ commands/say.ts | 35 ++++ db.ts | 12 ++ guards.ts | 7 + index.ts | 24 +++ package-lock.json | 486 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 21 ++ register.ts | 63 ++++++ tsconfig.json | 13 ++ 12 files changed, 783 insertions(+) create mode 100644 .gitignore create mode 100644 commands/error.ts create mode 100644 commands/index.ts create mode 100644 commands/roll.ts create mode 100644 commands/say.ts create mode 100644 db.ts create mode 100644 guards.ts create mode 100644 index.ts create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 register.ts create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..180bd6a --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.env +node_modules +*.js diff --git a/commands/error.ts b/commands/error.ts new file mode 100644 index 0000000..f31eb38 --- /dev/null +++ b/commands/error.ts @@ -0,0 +1,2 @@ +export class BotError extends Error {}; + diff --git a/commands/index.ts b/commands/index.ts new file mode 100644 index 0000000..1ea2694 --- /dev/null +++ b/commands/index.ts @@ -0,0 +1,78 @@ +import { EmbedBuilder } from "discord.js"; +import type { ChatInputCommandInteraction } from "discord.js"; + +import { BotError } from "./error"; + +import say from "./say"; +import roll from "./roll"; + + +export interface CommandData { + name: string; + description: string; + ephemeral: boolean; + admin_only: boolean; + run: (interaction: ChatInputCommandInteraction) => Promise; + // +}; + +const commands: CommandData[] = [say, roll]; + +//todo: look from config. also, have a config +function is_admin(interaction: ChatInputCommandInteraction): boolean { + // + //placeholder + return true; +} + +export default async function run(interaction: ChatInputCommandInteraction) { + const name = interaction.commandName; + + //help command is "auto-generated" + if (name === "help") { + //max of 25 fields per embed, so if too many commands, this section needs a rewrite + let embeds = []; + let help_embed = new EmbedBuilder(); + help_embed.setTitle("Help"); + for (const c of commands.filter((c) => !c.admin_only)) { + help_embed.addFields([{ + name: `/${c.name}`, + value: c.description, + }]); + } + embeds.push(help_embed); + if (is_admin(interaction)) { + let admin_help_embed = new EmbedBuilder(); + admin_help_embed.setTitle("Help (admin only)"); + for (const c of commands.filter((c) => c.admin_only)) { + admin_help_embed.addFields([{ + name: `/${c.name}`, + value: c.description, + }]); + } + embeds.push(admin_help_embed); + } + return await interaction.reply({ embeds, ephemeral: true }); + } + + const found = commands.find((c) => c.name === name); + try { + //admin stuff should be ideally handled by register.ts, but this is a fallback + if (found.admin_only && !is_admin(interaction)) throw new BotError("Admin permission needed to run that command"); + await found.run(interaction); + } catch (e) { + if (e instanceof BotError) { + //send error message to that channel + if (interaction.deferred) { + return await interaction.editReply(String(e)); + } else { + return await interaction.reply({ content: String(e), ephemeral: found.ephemeral }); + } + } else { + //an actual error + //console.log(e); + throw e; //crash it + } + } +} + diff --git a/commands/roll.ts b/commands/roll.ts new file mode 100644 index 0000000..305165b --- /dev/null +++ b/commands/roll.ts @@ -0,0 +1,39 @@ +import type { ChatInputCommandInteraction } from "discord.js"; +import { randomInt } from "crypto"; + +import type { CommandData } from "./index"; +import { BotError } from "./error"; + +const MAX_DICE: number = 100; +const MAX_FACES: number = 9999; + +async function run(interaction: ChatInputCommandInteraction) { + await interaction.deferReply(); //do these options.get things need to be await?? kinda stupid + const options = interaction.options; + const dice_num: number = (await options.get("dice_num")).value as number; + const dice_faces: number = (await options.get("dice_faces")).value as number; + const show_calc: boolean = ((await options.get("show_calc"))?.value ?? true) as boolean; + const include_zero: boolean = ((await options.get("include_zero"))?.value ?? false) as boolean; + if (dice_num < 1) throw new BotError("Must roll at least 1 dice, obviously"); + //semi-arbitrary limits, discord messages can be max 2000 chars long + if (dice_num > MAX_DICE) throw new BotError(`Max of ${MAX_DICE} dice`); + if (dice_faces > 9999) throw new BotError(`Max of ${MAX_FACES} faces`); + let rolls: number[] = []; + for (let i = 0; i < dice_num; i++) { + rolls.push(randomInt(include_zero ? 0 : 1, dice_faces + 1)); + } + const result: number = rolls.reduce((accum, roll) => accum + roll, 0); + return await interaction.editReply(`Result: **${result}** ${ show_calc ? `(${ rolls.join(" + ")} = ${result})` : "" }`); +} + +const data: CommandData = { + name: "roll", + description: "Roll dice", + ephemeral: false, + admin_only: false, + run, + // +}; + +export default data; + diff --git a/commands/say.ts b/commands/say.ts new file mode 100644 index 0000000..7653fd8 --- /dev/null +++ b/commands/say.ts @@ -0,0 +1,35 @@ +import type { ChatInputCommandInteraction } from "discord.js"; + +import type { CommandData } from "./index"; +import { BotError } from "./error"; +import { is_text_channel } from "../guards"; + +async function run(interaction: ChatInputCommandInteraction) { + const options = interaction.options; + const text: string = (await options.get("text")).value as string; //100% this is a string + const channel = (await options.get("channel")).channel; + //screw threads, news, announcements and shit, at least for now + if (is_text_channel(channel)) { + try { + await channel.send(text); + } catch (e) { + console.log(e); + throw new BotError("Couldn't send message"); + } + return await interaction.reply({ content: "Sent", ephemeral: true }); + } else { + throw new BotError("Must be guild text channel"); //I don't think DM channels are valid to pass in here so no worries there, probably + } +} + +const data: CommandData = { + name: "say", + description: "Have the bot say something in a channel", + ephemeral: true, + admin_only: true, + run, + // +}; + +export default data; + diff --git a/db.ts b/db.ts new file mode 100644 index 0000000..75ff928 --- /dev/null +++ b/db.ts @@ -0,0 +1,12 @@ +import { MongoClient } from "mongodb"; + +//figure out the options and whatnot later +const client = new MongoClient(process.env.MONGO_CONNECTION_STRING); + +let store, users, income; + +client.connect().then(() => { + console.log("Connected to the database"); + // +}); + diff --git a/guards.ts b/guards.ts new file mode 100644 index 0000000..1f1f15d --- /dev/null +++ b/guards.ts @@ -0,0 +1,7 @@ +import type { TextChannel } from "discord.js"; +import { ChannelType } from "discord.js"; + +export function is_text_channel(channel: any): channel is TextChannel { + return channel.type === ChannelType.GuildText; +} + diff --git a/index.ts b/index.ts new file mode 100644 index 0000000..9aad70b --- /dev/null +++ b/index.ts @@ -0,0 +1,24 @@ +import { Client, BaseInteraction } from "discord.js"; +import { config } from "dotenv"; + +//import db from "./db"; +import run from "./commands"; + +config(); + +const client = new Client({ intents: [] }); + +client.on("ready", async () => { + console.log(`Logged in as ${client.user.tag}`); + // +}); + +client.on("interactionCreate", async (interaction: BaseInteraction) => { + // + if (interaction.isChatInputCommand()) { + return await run(interaction); + } +}); + +setTimeout(() => client.login(process.env.DISCORD_TOKEN), 2000); + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..587b79b --- /dev/null +++ b/package-lock.json @@ -0,0 +1,486 @@ +{ + "name": "arvalddos-bot", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "arvalddos-bot", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "discord.js": "^14.15.3", + "dotenv": "^16.4.5", + "mongodb": "^6.8.0" + }, + "devDependencies": { + "typescript": "^5.5.3" + } + }, + "node_modules/@discordjs/builders": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.8.2.tgz", + "integrity": "sha512-6wvG3QaCjtMu0xnle4SoOIeFB4y6fKMN6WZfy3BMKJdQQtPLik8KGzDwBVL/+wTtcE/ZlFjgEk74GublyEVZ7g==", + "license": "Apache-2.0", + "dependencies": { + "@discordjs/formatters": "^0.4.0", + "@discordjs/util": "^1.1.0", + "@sapphire/shapeshift": "^3.9.7", + "discord-api-types": "0.37.83", + "fast-deep-equal": "^3.1.3", + "ts-mixer": "^6.0.4", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.11.0" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@discordjs/collection": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz", + "integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/formatters": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.4.0.tgz", + "integrity": "sha512-fJ06TLC1NiruF35470q3Nr1bi95BdvKFAF+T5bNfZJ4bNdqZ3VZ+Ttg6SThqTxm6qumSG3choxLBHMC69WXNXQ==", + "license": "Apache-2.0", + "dependencies": { + "discord-api-types": "0.37.83" + }, + "engines": { + "node": ">=16.11.0" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@discordjs/rest": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.3.0.tgz", + "integrity": "sha512-C1kAJK8aSYRv3ZwMG8cvrrW4GN0g5eMdP8AuN8ODH5DyOCbHgJspze1my3xHOAgwLJdKUbWNVyAeJ9cEdduqIg==", + "license": "Apache-2.0", + "dependencies": { + "@discordjs/collection": "^2.1.0", + "@discordjs/util": "^1.1.0", + "@sapphire/async-queue": "^1.5.2", + "@sapphire/snowflake": "^3.5.3", + "@vladfrangu/async_event_emitter": "^2.2.4", + "discord-api-types": "0.37.83", + "magic-bytes.js": "^1.10.0", + "tslib": "^2.6.2", + "undici": "6.13.0" + }, + "engines": { + "node": ">=16.11.0" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@discordjs/rest/node_modules/@discordjs/collection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.1.0.tgz", + "integrity": "sha512-mLcTACtXUuVgutoznkh6hS3UFqYirDYAg5Dc1m8xn6OvPjetnUlf/xjtqnnc47OwWdaoCQnHmHh9KofhD6uRqw==", + "license": "Apache-2.0", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@discordjs/util": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.1.0.tgz", + "integrity": "sha512-IndcI5hzlNZ7GS96RV3Xw1R2kaDuXEp7tRIy/KlhidpN/BQ1qh1NZt3377dMLTa44xDUNKT7hnXkA/oUAzD/lg==", + "license": "Apache-2.0", + "engines": { + "node": ">=16.11.0" + }, + "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.0", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.1.0.tgz", + "integrity": "sha512-mLcTACtXUuVgutoznkh6hS3UFqYirDYAg5Dc1m8xn6OvPjetnUlf/xjtqnnc47OwWdaoCQnHmHh9KofhD6uRqw==", + "license": "Apache-2.0", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.8.tgz", + "integrity": "sha512-qKwC/M/nNNaKUBMQ0nuzm47b7ZYWQHN3pcXq4IIcoSBc2hOIrflAxJduIvvqmhoz3gR2TacTAs8vlsCVPkiEdQ==", + "license": "MIT", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, + "node_modules/@sapphire/async-queue": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.2.tgz", + "integrity": "sha512-7X7FFAA4DngXUl95+hYbUF19bp1LGiffjJtu7ygrZrbdCSsdDDBaSjB7Akw0ZbOu6k0xpXyljnJ6/RZUvLfRdg==", + "license": "MIT", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@sapphire/shapeshift": { + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.7.tgz", + "integrity": "sha512-4It2mxPSr4OGn4HSQWGmhFMsNFGfFVhWeRPCRwbH972Ek2pzfGRZtb0pJ4Ze6oIzcyh2jw7nUDa6qGlWofgd9g==", + "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": "20.14.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz", + "integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", + "license": "MIT" + }, + "node_modules/@types/whatwg-url": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "license": "MIT", + "dependencies": { + "@types/webidl-conversions": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.5.11", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.11.tgz", + "integrity": "sha512-4+q7P5h3SpJxaBft0Dzpbr6lmMaqh0Jr2tbhJZ/luAwvD7ohSCniYkwz/pLxuT2h0EOa6QADgJj1Ko+TzRfZ+w==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@vladfrangu/async_event_emitter": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.4.4.tgz", + "integrity": "sha512-ZL62PFXEIeGUI8btfJ5S8Flc286eU1ZUSjwyFQtIGXfRUDPZKO+CDJMYb1R71LjGWRZ4n202O+a6FGjsgTw58g==", + "license": "MIT", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/bson": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.8.0.tgz", + "integrity": "sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=16.20.1" + } + }, + "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/discord.js": { + "version": "14.15.3", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.15.3.tgz", + "integrity": "sha512-/UJDQO10VuU6wQPglA4kz2bw2ngeeSbogiIPx/TsnctfzV/tNf+q+i1HlgtX1OGpeOBpJH9erZQNO5oRM2uAtQ==", + "license": "Apache-2.0", + "dependencies": { + "@discordjs/builders": "^1.8.2", + "@discordjs/collection": "1.5.3", + "@discordjs/formatters": "^0.4.0", + "@discordjs/rest": "^2.3.0", + "@discordjs/util": "^1.1.0", + "@discordjs/ws": "^1.1.1", + "@sapphire/snowflake": "3.5.3", + "discord-api-types": "0.37.83", + "fast-deep-equal": "3.1.3", + "lodash.snakecase": "4.1.1", + "tslib": "2.6.2", + "undici": "6.13.0" + }, + "engines": { + "node": ">=16.11.0" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "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/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", + "license": "MIT" + }, + "node_modules/magic-bytes.js": { + "version": "1.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/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "license": "MIT" + }, + "node_modules/mongodb": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.8.0.tgz", + "integrity": "sha512-HGQ9NWDle5WvwMnrvUxsFYPd3JEbqD3RgABHBQRuoCEND0qzhsd0iH5ypHsf1eJ+sXmvmyKpP+FLOKY8Il7jMw==", + "license": "Apache-2.0", + "dependencies": { + "@mongodb-js/saslprep": "^1.1.5", + "bson": "^6.7.0", + "mongodb-connection-string-url": "^3.0.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz", + "integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==", + "license": "Apache-2.0", + "dependencies": { + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^13.0.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "license": "MIT", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "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.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.13.0.tgz", + "integrity": "sha512-Q2rtqmZWrbP8nePMq7mOJIN98M0fYvSgV89vwl/BQRT4mDOeY2GXZngfGpcBBhtky3woM7G24wZV3Q304Bv6cw==", + "license": "MIT", + "engines": { + "node": ">=18.0" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "license": "MIT" + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", + "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", + "license": "MIT", + "dependencies": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "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 + } + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..c8102c1 --- /dev/null +++ b/package.json @@ -0,0 +1,21 @@ +{ + "name": "arvalddos-bot", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "compile": "tsc -p .", + "register": "npm run compile && node register.js", + "start": "npm run compile && node index.js" + }, + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "discord.js": "^14.15.3", + "dotenv": "^16.4.5", + "mongodb": "^6.8.0" + }, + "devDependencies": { + "typescript": "^5.5.3" + } +} diff --git a/register.ts b/register.ts new file mode 100644 index 0000000..40b6ff4 --- /dev/null +++ b/register.ts @@ -0,0 +1,63 @@ +import { REST, Routes } from "discord.js"; +import { config } from "dotenv"; + +config(); + +//description in two places is annoying but length limits are different (100 vs 1024 [but sum of all chars in embed cannot be >6000]) +const commands = [ + { + name: "help", + description: "Get a list of commands for this bot", + }, + { + name: "say", + description: "Have bot say something in a channel (admin only)", + options: [ + { + type: 3, + name: "text", + description: "What the bot should say", + required: true, + }, + { + type: 7, + name: "channel", + description: "What guild text channel the bot should say the text in", + required: true, + }, + ], + }, + { + name: "roll", + description: "Roll dice", + options: [ + { + type: 4, + name: "dice_num", + description: "Amount of dice to roll", + required: true, + }, + { + type: 4, + name: "dice_faces", + description: "Max value of each dice", + required: true, + }, + { + type: 5, + name: "show_calc", + description: "Show the calculations and each dice roll (default: true)", + required: false, + }, + { + type: 5, + name: "include_zero", + description: "Make it possible for the dice to roll 0 (default: false)", + required: false, + }, + ], + }, +]; + +(new REST().setToken(process.env.DISCORD_TOKEN)).put(Routes.applicationCommands(process.env.CLIENT_ID), { body: commands }).then(() => console.log("Finished reloading slash commands")); + diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..ef3a6b1 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "es2020", + "module": "node16", + "moduleResolution": "node16", + "typeRoots": ["./node_modules/@types"], + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + }, + "lib": ["ES2020"], + "exclude": ["node_modules"] +}