chore: init
This commit is contained in:
commit
a07d554b41
10 changed files with 310 additions and 0 deletions
3
.env.example
Normal file
3
.env.example
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
token=
|
||||
clientId=
|
||||
guildId=
|
||||
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.env
|
||||
3
README.md
Normal file
3
README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# CharCord
|
||||
|
||||
Talk to AIs from character.ai directly into a discord voice channel.
|
||||
27
commands.ts
Normal file
27
commands.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import * as path from "jsr:@std/path";
|
||||
|
||||
export async function gatherCommandsPaths(): Promise<string[]> {
|
||||
const commandsPath: string[] = [];
|
||||
const foldersPath = path.join(import.meta.dirname!, "commands");
|
||||
const commandsRoot = Deno.readDir(foldersPath);
|
||||
|
||||
for await (const entry of commandsRoot) {
|
||||
if (entry.isDirectory) {
|
||||
const commandsFolderPath = path.join(foldersPath, entry.name);
|
||||
const commandsFiles = (
|
||||
await Array.fromAsync(Deno.readDir(commandsFolderPath))
|
||||
).filter((file) => file.name.endsWith(".js"));
|
||||
for (const file of commandsFiles) {
|
||||
const commandPath = path.join(commandsFolderPath, file.name);
|
||||
|
||||
commandsPath.push(commandPath);
|
||||
}
|
||||
} else if (entry.name !== "template.ts") {
|
||||
const commandPath = path.join(foldersPath, entry.name);
|
||||
|
||||
commandsPath.push(commandPath);
|
||||
}
|
||||
}
|
||||
|
||||
return commandsPath;
|
||||
}
|
||||
10
commands/template.ts
Normal file
10
commands/template.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { CacheType, ChatInputCommandInteraction, SlashCommandBuilder } from "npm:discord.js";
|
||||
|
||||
export default {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName("template")
|
||||
.setDescription("Template command"),
|
||||
async execute(interaction: ChatInputCommandInteraction<CacheType>) {
|
||||
await interaction.reply("Pong!");
|
||||
},
|
||||
};
|
||||
6
deno.json
Normal file
6
deno.json
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"tasks": {
|
||||
"dev": "deno run --watch --env-file --allow-all main.ts",
|
||||
"deployCommands": "deno run --env-file --allow-all scripts/deployCommands.ts"
|
||||
}
|
||||
}
|
||||
146
deno.lock
generated
Normal file
146
deno.lock
generated
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
{
|
||||
"version": "4",
|
||||
"specifiers": {
|
||||
"jsr:@std/path@*": "1.1.0",
|
||||
"npm:@types/node@*": "22.12.0",
|
||||
"npm:discord.js@*": "14.20.0"
|
||||
},
|
||||
"jsr": {
|
||||
"@std/path@1.1.0": {
|
||||
"integrity": "ddc94f8e3c275627281cbc23341df6b8bcc874d70374f75fec2533521e3d6886"
|
||||
}
|
||||
},
|
||||
"npm": {
|
||||
"@discordjs/builders@1.11.2": {
|
||||
"integrity": "sha512-F1WTABdd8/R9D1icJzajC4IuLyyS8f3rTOz66JsSI3pKvpCAtsMBweu8cyNYsIyvcrKAVn9EPK+Psoymq+XC0A==",
|
||||
"dependencies": [
|
||||
"@discordjs/formatters",
|
||||
"@discordjs/util",
|
||||
"@sapphire/shapeshift",
|
||||
"discord-api-types",
|
||||
"fast-deep-equal",
|
||||
"ts-mixer",
|
||||
"tslib"
|
||||
]
|
||||
},
|
||||
"@discordjs/collection@1.5.3": {
|
||||
"integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ=="
|
||||
},
|
||||
"@discordjs/collection@2.1.1": {
|
||||
"integrity": "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="
|
||||
},
|
||||
"@discordjs/formatters@0.6.1": {
|
||||
"integrity": "sha512-5cnX+tASiPCqCWtFcFslxBVUaCetB0thvM/JyavhbXInP1HJIEU+Qv/zMrnuwSsX3yWH2lVXNJZeDK3EiP4HHg==",
|
||||
"dependencies": [
|
||||
"discord-api-types"
|
||||
]
|
||||
},
|
||||
"@discordjs/rest@2.5.1": {
|
||||
"integrity": "sha512-Tg9840IneBcbrAjcGaQzHUJWFNq1MMWZjTdjJ0WS/89IffaNKc++iOvffucPxQTF/gviO9+9r8kEPea1X5J2Dw==",
|
||||
"dependencies": [
|
||||
"@discordjs/collection@2.1.1",
|
||||
"@discordjs/util",
|
||||
"@sapphire/async-queue",
|
||||
"@sapphire/snowflake",
|
||||
"@vladfrangu/async_event_emitter",
|
||||
"discord-api-types",
|
||||
"magic-bytes.js",
|
||||
"tslib",
|
||||
"undici"
|
||||
]
|
||||
},
|
||||
"@discordjs/util@1.1.1": {
|
||||
"integrity": "sha512-eddz6UnOBEB1oITPinyrB2Pttej49M9FZQY8NxgEvc3tq6ZICZ19m70RsmzRdDHk80O9NoYN/25AqJl8vPVf/g=="
|
||||
},
|
||||
"@discordjs/ws@1.2.3": {
|
||||
"integrity": "sha512-wPlQDxEmlDg5IxhJPuxXr3Vy9AjYq5xCvFWGJyD7w7Np8ZGu+Mc+97LCoEc/+AYCo2IDpKioiH0/c/mj5ZR9Uw==",
|
||||
"dependencies": [
|
||||
"@discordjs/collection@2.1.1",
|
||||
"@discordjs/rest",
|
||||
"@discordjs/util",
|
||||
"@sapphire/async-queue",
|
||||
"@types/ws",
|
||||
"@vladfrangu/async_event_emitter",
|
||||
"discord-api-types",
|
||||
"tslib",
|
||||
"ws"
|
||||
]
|
||||
},
|
||||
"@sapphire/async-queue@1.5.5": {
|
||||
"integrity": "sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg=="
|
||||
},
|
||||
"@sapphire/shapeshift@4.0.0": {
|
||||
"integrity": "sha512-d9dUmWVA7MMiKobL3VpLF8P2aeanRTu6ypG2OIaEv/ZHH/SUQ2iHOVyi5wAPjQ+HmnMuL0whK9ez8I/raWbtIg==",
|
||||
"dependencies": [
|
||||
"fast-deep-equal",
|
||||
"lodash"
|
||||
]
|
||||
},
|
||||
"@sapphire/snowflake@3.5.3": {
|
||||
"integrity": "sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ=="
|
||||
},
|
||||
"@types/node@22.12.0": {
|
||||
"integrity": "sha512-Fll2FZ1riMjNmlmJOdAyY5pUbkftXslB5DgEzlIuNaiWhXd00FhWxVC/r4yV/4wBb9JfImTu+jiSvXTkJ7F/gA==",
|
||||
"dependencies": [
|
||||
"undici-types"
|
||||
]
|
||||
},
|
||||
"@types/ws@8.18.1": {
|
||||
"integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
|
||||
"dependencies": [
|
||||
"@types/node"
|
||||
]
|
||||
},
|
||||
"@vladfrangu/async_event_emitter@2.4.6": {
|
||||
"integrity": "sha512-RaI5qZo6D2CVS6sTHFKg1v5Ohq/+Bo2LZ5gzUEwZ/WkHhwtGTCB/sVLw8ijOkAUxasZ+WshN/Rzj4ywsABJ5ZA=="
|
||||
},
|
||||
"discord-api-types@0.38.12": {
|
||||
"integrity": "sha512-vqkRM50N5Zc6OVckAqtSslbUEoXmpN4bd9xq2jkoK9fgO3KNRIOyMMQ7ipqjwjKuAgzWvU6G8bRIcYWaUe1sCA=="
|
||||
},
|
||||
"discord.js@14.20.0": {
|
||||
"integrity": "sha512-5fRTptK2vpuz+bTuAEUQLSo/3AgCSLHl6Mm9+/ofb+8cbbnjWllhtaqRBq7XcpzlBnfNEugKv8HvCwcOtIHpCg==",
|
||||
"dependencies": [
|
||||
"@discordjs/builders",
|
||||
"@discordjs/collection@1.5.3",
|
||||
"@discordjs/formatters",
|
||||
"@discordjs/rest",
|
||||
"@discordjs/util",
|
||||
"@discordjs/ws",
|
||||
"@sapphire/snowflake",
|
||||
"discord-api-types",
|
||||
"fast-deep-equal",
|
||||
"lodash.snakecase",
|
||||
"magic-bytes.js",
|
||||
"tslib",
|
||||
"undici"
|
||||
]
|
||||
},
|
||||
"fast-deep-equal@3.1.3": {
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
||||
},
|
||||
"lodash.snakecase@4.1.1": {
|
||||
"integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw=="
|
||||
},
|
||||
"lodash@4.17.21": {
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"magic-bytes.js@1.12.1": {
|
||||
"integrity": "sha512-ThQLOhN86ZkJ7qemtVRGYM+gRgR8GEXNli9H/PMvpnZsE44Xfh3wx9kGJaldg314v85m+bFW6WBMaVHJc/c3zA=="
|
||||
},
|
||||
"ts-mixer@6.0.4": {
|
||||
"integrity": "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA=="
|
||||
},
|
||||
"tslib@2.8.1": {
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
|
||||
},
|
||||
"undici-types@6.20.0": {
|
||||
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="
|
||||
},
|
||||
"undici@6.21.3": {
|
||||
"integrity": "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw=="
|
||||
},
|
||||
"ws@8.18.2": {
|
||||
"integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ=="
|
||||
}
|
||||
}
|
||||
}
|
||||
64
main.ts
Normal file
64
main.ts
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
import {
|
||||
Client as _client,
|
||||
ClientOptions,
|
||||
Collection,
|
||||
Events,
|
||||
GatewayIntentBits,
|
||||
MessageFlags,
|
||||
} from "npm:discord.js";
|
||||
const token = Deno.env.get("token");
|
||||
import { Command } from "./types.ts";
|
||||
import { gatherCommandsPaths } from "./commands.ts";
|
||||
|
||||
|
||||
class Client extends _client {
|
||||
commands: Collection<string, Command>;
|
||||
constructor(options: ClientOptions) {
|
||||
super(options);
|
||||
this.commands = new Collection();
|
||||
}
|
||||
}
|
||||
|
||||
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
|
||||
|
||||
async function register(commandPath: string) {
|
||||
const { default: command }: { default: Command } = await import(commandPath);
|
||||
if ("data" in command && "execute" in command) {
|
||||
client.commands.set(command.data.name, command);
|
||||
console.log(`Registered ${command.data.name}.`);
|
||||
} else {
|
||||
console.log(
|
||||
`[WARNING] The command at ${commandPath} is missing a required "data" or "execute" property.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
(await gatherCommandsPaths()).forEach(register)
|
||||
|
||||
client.once(Events.ClientReady, (readyClient) => {
|
||||
console.log(`Ready! Logged in as ${readyClient.user.tag}`);
|
||||
});
|
||||
|
||||
client.on(Events.InteractionCreate, async interaction => {
|
||||
if (!interaction.isChatInputCommand()) return;
|
||||
|
||||
const command = client.commands.get(interaction.commandName);
|
||||
|
||||
if (!command) {
|
||||
console.error(`No command matching ${interaction.commandName} was 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!', flags: MessageFlags.Ephemeral });
|
||||
} else {
|
||||
await interaction.reply({ content: 'There was an error while executing this command!', flags: MessageFlags.Ephemeral });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
client.login(token);
|
||||
42
scripts/deployCommands.ts
Normal file
42
scripts/deployCommands.ts
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import { REST, RESTPostAPIChatInputApplicationCommandsJSONBody, Routes } from "npm:discord.js";
|
||||
const { clientId, guildId, token } = Deno.env.toObject();
|
||||
import { Command } from "../types.ts";
|
||||
import { gatherCommandsPaths } from "../commands.ts";
|
||||
|
||||
const commands: RESTPostAPIChatInputApplicationCommandsJSONBody[] = [];
|
||||
async function register(commandPath: string) {
|
||||
const { default: command }: { default: Command } = await import(commandPath);
|
||||
if ("data" in command && "execute" in command) {
|
||||
commands.push(command.data.toJSON());
|
||||
console.log(`Deploying ${command.data.name}...`);
|
||||
} else {
|
||||
console.log(
|
||||
`[WARNING] The command at ${commandPath} is missing a required "data" or "execute" property.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (const commandPath of await gatherCommandsPaths()) {
|
||||
await register(commandPath)
|
||||
}
|
||||
|
||||
const rest = new REST().setToken(token);
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
console.log(
|
||||
`Started refreshing ${commands.length} application (/) commands.`
|
||||
);
|
||||
|
||||
await rest.put(
|
||||
Routes.applicationGuildCommands(clientId, guildId),
|
||||
{ body: commands }
|
||||
);
|
||||
|
||||
console.log(
|
||||
`Successfully reloaded ${commands.length} application (/) commands.`
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
})();
|
||||
8
types.ts
Normal file
8
types.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { CacheType, ChatInputCommandInteraction, SlashCommandBuilder } from "npm:discord.js";
|
||||
|
||||
export type Command = {
|
||||
data: SlashCommandBuilder;
|
||||
execute: (
|
||||
interaction: ChatInputCommandInteraction<CacheType>
|
||||
) => Promise<void>;
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue