feat: implement command registration and management with Discord API

This commit is contained in:
Sosokker 2025-09-02 21:08:19 +07:00
parent 4248c75bd6
commit fa0584c550
4 changed files with 114 additions and 13 deletions

View File

@ -1,6 +1,6 @@
import { Config } from "./config";
import { logger } from "./logger";
import { fetchDiscord } from "./discord/core";
import * as Discord from "./discord";
const COMMANDS = [
{
@ -23,18 +23,55 @@ const COMMANDS = [
},
];
export const registerCommand = async () => {
logger.info(
{ command: COMMANDS, guildId: Config.DEFAULT_GUILD_ID },
"Registering commands to discord server",
const normalizeCommand = (cmd: any) => ({
name: cmd.name,
description: cmd.description,
type: cmd.type,
options: (cmd.options || [])
.map((o: any) => ({
name: o.name,
description: o.description,
type: o.type,
required: o.required || false,
}))
.sort((a: any, b: any) => a.name.localeCompare(b.name)),
});
const commandsAreEqual = (existingCommands: any[], newCommands: any[]) => {
if (existingCommands.length !== newCommands.length) return false;
const sortedExisting = [...existingCommands].sort((a, b) =>
a.name.localeCompare(b.name),
);
for (const commmand of COMMANDS) {
const response = await fetchDiscord(
`/applications/${Config.APP_ID}/guilds/${Config.DEFAULT_GUILD_ID}/commands`,
{
method: "POST",
body: JSON.stringify(commmand),
},
);
const sortedNew = [...newCommands].sort((a, b) =>
a.name.localeCompare(b.name),
);
for (let i = 0; i < sortedNew.length; i++) {
if (
JSON.stringify(normalizeCommand(sortedExisting[i])) !==
JSON.stringify(normalizeCommand(sortedNew[i]))
) {
return false;
}
}
return true;
};
export const registerCommand = async () => {
try {
logger.info("Checking for command updates...");
const existingCommands = await Discord.getGuildCommands();
if (commandsAreEqual(existingCommands, COMMANDS)) {
logger.info("Commands are already up to date.");
return;
}
logger.info("Commands are different, registering...");
await Discord.bulkOverwriteGuildCommands(COMMANDS);
logger.info("Commands registered successfully.");
} catch (error) {
logger.error(error, "Failed to register commands");
}
};

View File

@ -0,0 +1,58 @@
import { fetchDiscord } from "./core";
import { Config } from "../config";
export interface Application {
id: string;
name: string;
icon: string | null;
description: string;
bot_public: boolean;
bot_require_code_grant: boolean;
team: any | null;
}
export const getCurrentApplication = async (): Promise<Application> => {
const res = await fetchDiscord("/applications/@me");
if (!res.ok) {
throw new Error(`Failed to get current application: ${res.status}`);
}
return res.json();
};
export const editCurrentApplication = async (data: any): Promise<Application> => {
const res = await fetchDiscord("/applications/@me", {
method: "PATCH",
body: JSON.stringify(data),
});
if (!res.ok) {
throw new Error(`Failed to edit current application: ${res.status}`);
}
return res.json();
};
export const getGuildCommands = async () => {
const res = await fetchDiscord(
`/applications/${Config.APP_ID}/guilds/${Config.DEFAULT_GUILD_ID}/commands`,
);
if (!res.ok) {
throw new Error(`Failed to get guild commands: ${res.status}`);
}
return res.json();
};
export const bulkOverwriteGuildCommands = async (commands: any[]) => {
const res = await fetchDiscord(
`/applications/${Config.APP_ID}/guilds/${Config.DEFAULT_GUILD_ID}/commands`,
{
method: "PUT",
body: JSON.stringify(commands),
},
);
if (!res.ok) {
const error = await res.text();
throw new Error(
`Failed to bulk overwrite guild commands: ${res.status} ${error}`,
);
}
return res.json();
};

View File

@ -1,3 +1,4 @@
export * from "./application";
export * from "./audit-log";
export * from "./core";
export * from "./guild";

View File

@ -3,12 +3,17 @@ import { Config } from "./config";
import { logger } from "./logger";
import * as nacl from "tweetnacl";
import * as Discord from "./discord";
import { registerCommand } from "./commands";
logger.info(
{ port: Config.PORT, guildId: Config.DEFAULT_GUILD_ID },
"Discord police bot is starting",
);
registerCommand().catch((err) =>
logger.error(err, "Failed to register commands"),
);
const snowflakeToMs = (id: string) =>
Number((BigInt(id) >> BigInt(22)) + BigInt(1420070400000));