fix: big bot template

This commit is contained in:
Skillz4Killz
2022-03-25 12:44:21 +00:00
committed by GitHub
parent 3bec0cea4d
commit 27e863def0
17 changed files with 196 additions and 103 deletions
+92
View File
@@ -0,0 +1,92 @@
import { dotEnvConfig, GatewayIntents } from "./deps.ts";
// Get the .env file that the user should have created, and load the configs.
const env = dotEnvConfig({ export: true });
// TODO: REMOVE THESE! THEY ARE BAD FOR YOU! DUH! Seriously, only keep the ones your bot needs!
export const GATEWAY_INTENTS: (keyof typeof GatewayIntents)[] = [
"DirectMessageReactions",
"DirectMessageTyping",
"DirectMessages",
"GuildBans",
"GuildEmojis",
"GuildIntegrations",
"GuildInvites",
"GuildMembers",
"GuildMessageReactions",
"GuildMessageTyping",
"GuildMessages",
"GuildPresences",
"GuildVoiceStates",
"GuildWebhooks",
"Guilds",
];
if (!env.DISCORD_TOKEN) {
throw new Error("DUDE! You did not provide a Discord token!");
}
export const DISCORD_TOKEN = `Bot ${env.DISCORD_TOKEN!}`;
// Set as 0 to make it use default values. NOT RECOMMENDED TO DEFAULT FOR BIG BOTS!!!!
export const MAX_SHARDS = env.MAX_SHARDS ? parseInt(env.MAX_SHARDS, 10) : 0;
export const FIRST_SHARD_ID = env.FIRST_SHARD_ID ? parseInt(env.FIRST_SHARD_ID, 10) : 0;
export const LAST_SHARD_ID = env.LAST_SHARD_ID ? parseInt(env.LAST_SHARD_ID, 10) : 0;
// Default to 10
export const SHARDS_PER_CLUSTER = env.SHARDS_PER_CLUSTER ? parseInt(env.SHARDS_PER_CLUSTER, 10) : 10;
export const MAX_CLUSTERS = parseInt(env.MAX_CLUSTERS!, 10);
if (!MAX_CLUSTERS) {
throw new Error(
"Please for the love of god, tell me how many clusters your machine can handle!",
);
}
export const URL_GATEWAY_PROXY_WILL_FORWARD_TO = env
.URL_GATEWAY_PROXY_WILL_FORWARD_TO!;
if (!URL_GATEWAY_PROXY_WILL_FORWARD_TO) {
throw new Error(
"Don't you think you need to give a URL where you want your gateway proxy to send events to?",
);
}
export const EVENT_HANDLER_URL = env
.EVENT_HANDLER_URL!;
if (!EVENT_HANDLER_URL) {
throw new Error(
"Don't you think you need to give a URL where you want your events sent to?",
);
}
export const GATEWAY_SECRET_KEY = env.GATEWAY_SECRET_KEY!;
if (!GATEWAY_SECRET_KEY) {
throw new Error(
"Do you want to be hacked? Add a secret authorization key that can be used to identify requests are from you.",
);
}
export const REST_AUTHORIZATION_KEY = env.REST_AUTHORIZATION_KEY!;
if (!REST_AUTHORIZATION_KEY) {
throw new Error(
"Do you want to be hacked? Add a secret authorization key to make sure requests are only made by you.",
);
}
export const EVENT_HANDLER_SECRET_KEY = env.EVENT_HANDLER_SECRET_KEY!;
if (!EVENT_HANDLER_SECRET_KEY) {
throw new Error(
"Do you want to be hacked? Add a secret authorization key to make sure requests are only made by you.",
);
}
export const BOT_ID = BigInt(atob(env.DISCORD_TOKEN.split(".")[0]));
if (!BOT_ID) {
throw new Error("Please enter the BOT ID you want to run this with.");
}
export const REST_PORT = env.REST_PORT ? parseInt(env.REST_PORT, 10) : 5000;
export const GATEWAY_PORT = env.GATEWAY_PORT ? parseInt(env.GATEWAY_PORT, 10) : 8080;
export const EVENT_HANDLER_PORT = env.EVENT_HANDLER_PORT ? parseInt(env.EVENT_HANDLER_PORT, 10) : 7050;
export const DEVELOPMENT = env.DEVELOPMENT ?? true;
export const MISSING_TRANSLATION_WEBHOOK = env.MISSING_TRANSLATION_WEBHOOK ||
"";
export const DEV_GUILD_ID = env.DEV_GUILD_ID ? BigInt(env.DEV_GUILD_ID) : 0n;
+3 -4
View File
@@ -1,10 +1,9 @@
export * from "https://deno.land/x/discordeno@13.0.0-rc27/mod.ts";
export * from "https://deno.land/x/discordeno@13.0.0-rc27/plugins/mod.ts";
// Terminal Colors!
export * from "https://deno.land/std@0.117.0/fmt/colors.ts";
// Get data from .env files
export { config as dotEnvConfig } from "https://deno.land/x/dotenv@v3.1.0/mod.ts";
export * from "https://deno.land/x/discordeno@13.0.0-rc15/mod.ts";
// All the Plugins
export * from "https://deno.land/x/discordeno_helpers_plugin@0.0.3/mod.ts";
export { validatePermissions } from "https://deno.land/x/discordeno_permissions_plugin@0.0.11/src/permissions.ts";
// export * from "https://deno.land/x/kwik@v1.2.0/mod.ts";
export * from "https://raw.githubusercontent.com/TriForMine/kwik/4df9d84eefee7ff299cc65e0f31adb8dbee64cde/mod.ts";
@@ -1,4 +1,4 @@
import { ButtonData, InteractionTypes, MessageComponentTypes } from "../../../../deps.ts";
import { InteractionTypes, MessageComponentTypes } from "../../../../deps.ts";
import { bot } from "../../mod.ts";
import { executeSlashCommand } from "../interactions/executeSlashCommand.ts";
@@ -14,7 +14,7 @@ export function setInteractionCreateEvent() {
// THE INTERACTION CAME FROM A BUTTON
if (
(interaction.data as ButtonData).componentType ===
interaction.data.componentType ===
MessageComponentTypes.Button
) {
// processButtonCollectors(bot, interaction)
@@ -4,10 +4,11 @@ import {
bgMagenta,
bgYellow,
black,
DiscordenoInteraction,
green,
Interaction,
InteractionResponseTypes,
red,
sendPrivateInteractionResponse,
white,
} from "../../../../deps.ts";
import logger from "../../../../src/utils/logger.ts";
@@ -20,7 +21,7 @@ import { Command, ConvertArgumentDefinitionsToArgs } from "../../types/command.t
import commands from "./mod.ts";
function logCommand(
info: DiscordenoInteraction,
info: Interaction,
type: "Failure" | "Success" | "Trigger" | "Slowmode" | "Missing" | "Inhibit",
commandName: string,
) {
@@ -32,7 +33,7 @@ function logCommand(
const user = bgGreen(
black(
`${info.user.username}#${info.user.discriminator.toString().padStart(4, "0")}(${info.id})`,
`${info.user.username}#${info.user.discriminator}(${info.id})`,
),
);
const guild = bgMagenta(
@@ -44,7 +45,7 @@ function logCommand(
export async function executeSlashCommand(
bot: BotClient,
interaction: DiscordenoInteraction,
interaction: Interaction,
) {
const data = interaction.data;
const name = data?.name as keyof typeof commands;
@@ -54,18 +55,16 @@ export async function executeSlashCommand(
// Command could not be found
if (!command?.execute) {
return await bot.helpers
.sendInteractionResponse(interaction.id, interaction.token, {
type: InteractionResponseTypes.ChannelMessageWithSource,
private: true,
data: {
content: translate(
bot,
interaction.guildId!,
"EXECUTE_COMMAND_NOT_FOUND",
),
},
})
return await sendPrivateInteractionResponse(bot, interaction.id, interaction.token, {
type: InteractionResponseTypes.ChannelMessageWithSource,
data: {
content: translate(
bot,
interaction.guildId!,
"EXECUTE_COMMAND_NOT_FOUND",
),
},
})
.catch(logger.error);
}
@@ -1,12 +1,12 @@
import { DEV_GUILD_ID } from "../../../../../configs.ts";
import { DiscordUnavailableGuild, GatewayPayload } from "../../../../../deps.ts";
import { DiscordUnavailableGuild, DiscordGatewayPayload } from "../../../../../deps.ts";
import logger from "../../../../utils/logger.ts";
import { updateGuildCommands } from "../../../../utils/updateSlash.ts";
import { BotClient } from "../../../botClient.ts";
import { usesLatestCommandVersion } from "../../../database/commandVersion.ts";
import { commandVersions } from "../../../database/kwik.ts";
export async function setGuildCommands(bot: BotClient, data: GatewayPayload) {
export async function setGuildCommands(bot: BotClient, data: DiscordGatewayPayload) {
if (!data.t) return;
if (data.t === "GUILD_DELETE") {
+2 -2
View File
@@ -8,7 +8,7 @@ import {
REST_AUTHORIZATION_KEY,
REST_PORT,
} from "../../configs.ts";
import { createBot, createRestManager, GatewayPayload, SnakeCasedPropertiesDeep } from "../../deps.ts";
import { createBot, createRestManager, DiscordGatewayPayload } from "../../deps.ts";
import logger from "../utils/logger.ts";
import { updateDevCommands } from "../utils/updateSlash.ts";
import { BotClient, setupBotClient } from "./botClient.ts";
@@ -80,7 +80,7 @@ async function handleRequest(conn: Deno.Conn) {
}
const json = (await requestEvent.request.json()) as {
data: SnakeCasedPropertiesDeep<GatewayPayload>;
data: DiscordGatewayPayload;
shardId: number;
};
// EMITS RAW EVENT
+26 -26
View File
@@ -1,12 +1,12 @@
import {
ApplicationCommandOptionTypes,
ApplicationCommandTypes,
DiscordenoChannel,
DiscordenoInteraction,
DiscordenoMember,
DiscordenoRole,
DiscordenoUser,
Permission,
Channel,
Interaction,
Member,
Role,
User,
PermissionStrings,
} from "../../../deps.ts";
import { PermissionLevelHandlers } from "../../utils/permLevels.ts";
import { BotClient } from "../botClient.ts";
@@ -215,33 +215,33 @@ export type ConvertArgumentDefinitionsToArgs<
: // USER
T[P] extends UserOptionalArgumentDefinition<infer N> ? {
[_ in getName<N>]?: {
user: DiscordenoUser;
member: DiscordenoMember;
user: User;
member: Member;
};
}
: T[P] extends UserArgumentDefinition<infer N> ? {
[_ in getName<N>]: {
user: DiscordenoUser;
member: DiscordenoMember;
user: User;
member: Member;
};
}
: // CHANNEL
T[P] extends ChannelOptionalArgumentDefinition<infer N> ? { [_ in getName<N>]?: DiscordenoChannel }
: T[P] extends ChannelArgumentDefinition<infer N> ? { [_ in getName<N>]: DiscordenoChannel }
T[P] extends ChannelOptionalArgumentDefinition<infer N> ? { [_ in getName<N>]?: Channel }
: T[P] extends ChannelArgumentDefinition<infer N> ? { [_ in getName<N>]: Channel }
: // ROLE
T[P] extends RoleOptionalArgumentDefinition<infer N> ? { [_ in getName<N>]?: DiscordenoRole }
: T[P] extends RoleArgumentDefinition<infer N> ? { [_ in getName<N>]: DiscordenoRole }
T[P] extends RoleOptionalArgumentDefinition<infer N> ? { [_ in getName<N>]?: Role }
: T[P] extends RoleArgumentDefinition<infer N> ? { [_ in getName<N>]: Role }
: // MENTIONABLE
T[P] extends MentionableOptionalArgumentDefinition<infer N> ? {
[_ in getName<N>]?: DiscordenoRole | {
user: DiscordenoUser;
member: DiscordenoMember;
[_ in getName<N>]?: Role | {
user: User;
member: Member;
};
}
: T[P] extends MentionableArgumentDefinition<infer N> ? {
[_ in getName<N>]: DiscordenoRole | {
user: DiscordenoUser;
member: DiscordenoMember;
[_ in getName<N>]: Role | {
user: User;
member: Member;
};
}
: // SUBCOMMAND
@@ -275,7 +275,7 @@ export interface Command<T extends readonly ArgumentDefinition[]> {
options?: T;
execute: (
bot: BotClient,
data: DiscordenoInteraction,
data: Interaction,
args: ConvertArgumentDefinitionsToArgs<T>,
) => unknown;
subcommands?: Record<
@@ -308,13 +308,13 @@ export interface Command<T extends readonly ArgumentDefinition[]> {
permissionLevels?:
| (keyof typeof PermissionLevelHandlers)[]
| ((
data: DiscordenoInteraction,
data: Interaction,
command: Command<T>,
) => boolean | Promise<boolean>);
botServerPermissions?: Permission[];
botChannelPermissions?: Permission[];
userServerPermissions?: Permission[];
userChannelPermissions?: Permission[];
botServerPermissions?: PermissionStrings[];
botChannelPermissions?: PermissionStrings[];
userServerPermissions?: PermissionStrings[];
userChannelPermissions?: PermissionStrings[];
}
export enum PermissionLevels {
+1 -1
View File
@@ -60,7 +60,7 @@ export class Components extends Array<ActionRow> {
// A snowflake id was provided
if (SNOWFLAKE_REGEX.test(emoji)) {
return {
id: emoji.match(SNOWFLAKE_REGEX)![0],
id: BigInt(emoji.match(SNOWFLAKE_REGEX)![0]),
};
}
+5 -5
View File
@@ -1,4 +1,4 @@
import { Bot, DiscordenoUser, Embed } from "../../deps.ts";
import { Bot, Embed, User } from "../../deps.ts";
const embedLimits = {
title: 256,
@@ -44,7 +44,7 @@ export class Embeds extends Array<Embed> {
return data;
}
setAuthor(name: string, iconUrl?: string | DiscordenoUser, url?: string) {
setAuthor(name: string, iconUrl?: string | User, url?: string) {
const embed = this.#getLastEmbed();
const finalName = this.enforceLimits ? this.fitData(name, embedLimits.authorName) : name;
@@ -126,7 +126,7 @@ export class Embeds extends Array<Embed> {
return this;
}
setImage(url: string | DiscordenoUser) {
setImage(url: string | User) {
if (typeof url === "string") this.#getLastEmbed().image = { url };
else {
this.#getLastEmbed().image = {
@@ -140,8 +140,8 @@ export class Embeds extends Array<Embed> {
return this;
}
setTimestamp(time = Date.now()) {
this.#getLastEmbed().timestamp = new Date(time).toISOString();
setTimestamp(time: number | string = Date.now()) {
this.#getLastEmbed().timestamp = typeof time === "string" ? Date.parse(time) : time;
return this;
}
+3 -3
View File
@@ -1,12 +1,12 @@
import { DiscordenoUser } from "../../deps.ts";
import { User } from "../../deps.ts";
import { Milliseconds } from "../constants/milliseconds.ts";
export function chooseRandom<T>(array: T[]) {
return array[Math.floor(Math.random() * array.length)]!;
}
export function getUserTag(user: DiscordenoUser) {
return `${user.username}#${user.discriminator.toString().padStart(4, "0")}`;
export function getUserTag(user: User) {
return `${user.username}#${user.discriminator}`;
}
export function toTitleCase(text: string) {
+26 -26
View File
@@ -4,11 +4,11 @@ import {
Bot,
ChannelTypes,
Collection,
DiscordenoChannel,
DiscordenoMember,
DiscordenoMessage,
DiscordenoRole,
DiscordenoUser,
Channel,
Member,
Message,
Role,
User,
InteractionDataOption,
} from "../../deps.ts";
import { getLanguage, translate } from "../bot/languages/translate.ts";
@@ -62,13 +62,13 @@ function convertOptionValue(
option: InteractionDataOption,
resolved?: {
/** The Ids and Message objects */
messages?: Collection<bigint, DiscordenoMessage>;
messages?: Collection<bigint, Message>;
/** The Ids and User objects */
users?: Collection<bigint, DiscordenoUser>;
users?: Collection<bigint, User>;
/** The Ids and partial Member objects */
members?: Collection<bigint, DiscordenoMember>;
members?: Collection<bigint, Member>;
/** The Ids and Role objects */
roles?: Collection<bigint, DiscordenoRole>;
roles?: Collection<bigint, Role>;
/** The Ids and partial Channel objects */
channels?: Collection<
bigint,
@@ -84,8 +84,8 @@ function convertOptionValue(
): [
string,
(
| { user: DiscordenoUser; member: DiscordenoMember }
| DiscordenoRole
| { user: User; member: Member }
| Role
| {
id: bigint;
name: string;
@@ -154,13 +154,13 @@ export function optionParser(
options?: InteractionDataOption[],
resolved?: {
/** The Ids and Message objects */
messages?: Collection<bigint, DiscordenoMessage>;
messages?: Collection<bigint, Message>;
/** The Ids and User objects */
users?: Collection<bigint, DiscordenoUser>;
users?: Collection<bigint, User>;
/** The Ids and partial Member objects */
members?: Collection<bigint, DiscordenoMember>;
members?: Collection<bigint, Member>;
/** The Ids and Role objects */
roles?: Collection<bigint, DiscordenoRole>;
roles?: Collection<bigint, Role>;
/** The Ids and partial Channel objects */
channels?: Collection<
bigint,
@@ -184,8 +184,8 @@ export function optionParser(
if (options[0].type === ApplicationCommandOptionTypes.SubCommand) {
const convertedOptions: Record<
string,
| { user: DiscordenoUser; member: DiscordenoMember }
| DiscordenoRole
| { user: User; member: Member }
| Role
| {
id: bigint;
name: string;
@@ -216,9 +216,9 @@ export function optionParser(
if (options[0].type === ApplicationCommandOptionTypes.SubCommandGroup) {
const convertedOptions: Record<
string,
| DiscordenoMember
| DiscordenoRole
| DiscordenoChannel
| Member
| Role
| Channel
| boolean
| string
| number
@@ -248,11 +248,11 @@ export function optionParser(
// A NORMAL COMMAND WAS USED
const convertedOptions: Record<
string,
| DiscordenoMember
| DiscordenoRole
| Member
| Role
| Record<
string,
Pick<DiscordenoChannel, "id" | "name" | "type" | "permissions">
Pick<Channel, "id" | "name" | "type" | "permissions">
>
| boolean
| string
@@ -276,11 +276,11 @@ export function optionParser(
*/
export type InteractionCommandArgs = Record<
string,
| DiscordenoMember
| DiscordenoRole
| Member
| Role
| Record<
string,
Pick<DiscordenoChannel, "id" | "name" | "type" | "permissions">
Pick<Channel, "id" | "name" | "type" | "permissions">
>
| boolean
| string
+3 -3
View File
@@ -1,10 +1,10 @@
import { DiscordenoInteraction, validatePermissions } from "../../deps.ts";
import { Interaction, validatePermissions } from "../../deps.ts";
import { Command } from "../bot/types/command.ts";
export default async function hasPermissionLevel(
// deno-lint-ignore no-explicit-any
command: Command<any>,
payload: DiscordenoInteraction,
payload: Interaction,
) {
// This command doesnt require a perm level so allow the command.
if (!command.permissionLevels) return true;
@@ -27,7 +27,7 @@ export default async function hasPermissionLevel(
export const PermissionLevelHandlers: Record<
keyof typeof PermissionLevels,
(
payload: DiscordenoInteraction,
payload: Interaction,
// deno-lint-ignore no-explicit-any
command: Command<any>,
) => boolean | Promise<boolean>
+6 -9
View File
@@ -1,18 +1,16 @@
import {
Bot,
DiscordenoInteraction,
Interaction,
InteractionApplicationCommandCallbackData,
InteractionResponseTypes,
} from "../../deps.ts";
export async function replyToInteraction(
bot: Bot,
payload: DiscordenoInteraction,
payload: Interaction,
options:
| string
| (InteractionApplicationCommandCallbackData & {
/** Set to true if the response should be private, only works with slash commands */
private?: boolean;
/** Type of the reply */
type?: InteractionResponseTypes;
}),
@@ -21,24 +19,23 @@ export async function replyToInteraction(
return await bot.helpers.sendInteractionResponse(payload.id, payload.token, {
type: options.type ?? InteractionResponseTypes.ChannelMessageWithSource,
private: options.private,
data: options,
});
}
export async function privateReplyToInteraction(
bot: Bot,
payload: DiscordenoInteraction,
payload: Interaction,
options:
| string
| (InteractionApplicationCommandCallbackData & {
/** Set to true if the response should be private, only works with slash commands */
private?: boolean;
/** Type of the reply */
type?: InteractionResponseTypes;
}),
) {
if (typeof options === "string") options = { content: options };
// SET PRIVATE
options.flags = 64;
return await replyToInteraction(bot, payload, { ...options, private: true });
return await replyToInteraction(bot, payload, { ...options });
}
+2 -2
View File
@@ -1,11 +1,11 @@
import { Bot, DiscordenoInteraction } from "../../deps.ts";
import { Bot, Interaction } from "../../deps.ts";
import Embeds from "./Embeds.ts";
import { getUserTag } from "./helpers.ts";
import logger from "./logger.ts";
export async function slashLogWebhook(
bot: Bot,
payload: DiscordenoInteraction,
payload: Interaction,
name: string,
) {
const webhook = Deno.env.get("DISCORD_LOGS_WEBHOOK");
+6
View File
@@ -0,0 +1,6 @@
import { dotEnvConfig } from "./deps.ts";
dotEnvConfig({ export: true });
export const BOT_TOKEN = Deno.env.get("BOT_TOKEN") || "";
export const BOT_ID = BigInt(atob(BOT_TOKEN.split(".")[0]));
+1 -1
View File
@@ -12,7 +12,7 @@ export function transformMessage(bot: Bot, payload: DiscordMessage) {
// UNTRANSFORMED STUFF HERE
content: payload.content || "",
isBot: payload.author.bot || false,
tag: `${payload.author.username}#${payload.author.discriminator.toString().padStart(4, "0")}`,
tag: `${payload.author.username}#${payload.author.discriminator}`,
timestamp: Date.parse(payload.timestamp),
editedTimestamp: payload.edited_timestamp ? Date.parse(payload.edited_timestamp) : undefined,
bitfield: (payload.tts ? 1n : 0n) | (payload.mention_everyone ? 2n : 0n) | (payload.pinned ? 4n : 0n),
+1 -1
View File
@@ -15,7 +15,7 @@ export function transformWidget(bot: Bot, payload: DiscordGuildWidget) {
members: payload.members.map((member) => ({
id: bot.transformers.snowflake(member.id),
username: member.username,
discriminator: Number(member.discriminator),
discriminator: member.discriminator,
avatar: member.avatar ? bot.utils.iconHashToBigInt(member.avatar) : undefined,
status: member.status,
avatarUrl: member.avatar_url,