Skip to content

Commit b049b11

Browse files
committed
Move hardcoded snowflakes into src/config.ts
The BetterDiscord guild id appeared four times across three files, the developer role ids five times across two, and the account-issues channel and AutoMod rule ids were inline constants in the files that used them. Changing any of them meant grepping for a number. src/config.ts collects all seven, each overridable by an environment variable so the bot can be pointed at a test server without editing source: BD_GUILD_ID, BD_ROLE_PLUGIN_DEV, BD_ROLE_THEME_DEV, COMMUNITY_ROLE_PLUGIN_DEV, COMMUNITY_ROLE_THEME_DEV, BD_CHANNEL_ACCOUNT_ISSUES, BD_AUTOMOD_SPAM_LINK_RULE Defaults are the values that were already inline, so behaviour is unchanged with no environment set. Verified: all seven defaults match the literals they replaced, and setting BD_GUILD_ID overrides that one while leaving the rest alone. src/util/web.ts keeps its release-channel ids. They are BetterDiscord website data copied from the client repository rather than deployment configuration, and the file documents its upstream source. No inline snowflakes remain in src/ outside config.ts and web.ts. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015hDX4g1EjTN7424A5wnptE
1 parent 82f1ec3 commit b049b11

5 files changed

Lines changed: 56 additions & 15 deletions

File tree

src/commands/developer.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {ApplicationCommandOptionType, ApplicationCommandType, ChatInputCommandInteraction, InteractionContextType, type GuildTextBasedChannel} from "discord.js";
22
import {defineCommand} from "../framework";
3+
import config from "../config";
34
import {guildDB} from "../db";
45
import * as notices from "../util/notices";
56

@@ -35,8 +36,8 @@ async function add(interaction: ChatInputCommandInteraction<"cached">) {
3536
const targetUser = interaction.options.getUser("user", true);
3637
const roleName = interaction.options.getString("role", true);
3738

38-
const bdRoleId = roleName.toLowerCase().includes("plugin") ? "125166040689803264" : "165005972970930176";
39-
const bdGuild = await interaction.client.guilds.fetch("86004744966914048");
39+
const bdRoleId = roleName.toLowerCase().includes("plugin") ? config.roles.pluginDeveloper : config.roles.themeDeveloper;
40+
const bdGuild = await interaction.client.guilds.fetch(config.guilds.betterDiscord);
4041
try {
4142
const member = await bdGuild.members.fetch(targetUser);
4243
try {
@@ -89,12 +90,12 @@ async function add(interaction: ChatInputCommandInteraction<"cached">) {
8990

9091
async function sync(interaction: ChatInputCommandInteraction<"cached">) {
9192
const targetUser = interaction.options.getUser("user", true);
92-
const bdGuild = await interaction.client.guilds.fetch("86004744966914048");
93+
const bdGuild = await interaction.client.guilds.fetch(config.guilds.betterDiscord);
9394
const bdMember = await bdGuild.members.fetch(targetUser);
9495
if (!bdMember) return await interaction.reply(notices.error("User is not in BetterDiscord server!", {ephemeral: true}));
95-
const isPluginDev = bdMember.roles.cache.has("125166040689803264");
96-
const isThemeDev = bdMember.roles.cache.has("165005972970930176");
97-
const rolesToAdd = [isPluginDev ? "948627723830591568" : "", isThemeDev ? "948627648706392104" : ""].filter(r => r);
96+
const isPluginDev = bdMember.roles.cache.has(config.roles.pluginDeveloper);
97+
const isThemeDev = bdMember.roles.cache.has(config.roles.themeDeveloper);
98+
const rolesToAdd = [isPluginDev ? config.roles.communityPluginDeveloper : "", isThemeDev ? config.roles.communityThemeDeveloper : ""].filter(r => r);
9899

99100
const communityMember = await interaction.guild.members.fetch(targetUser);
100101

src/commands/spam.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import {ApplicationCommandOptionType, ApplicationCommandType, ChatInputCommandInteraction, InteractionContextType, PermissionFlagsBits} from "discord.js";
22
import {defineCommand} from "../framework";
3+
import config from "../config";
34
import * as notices from "../util/notices";
45

56

67
// TODO: move detectspam from moderation to here
78
async function addLink(interaction: ChatInputCommandInteraction<"cached">) {
8-
const rule = await interaction.guild.autoModerationRules.fetch("1256935881168781332");
9+
const rule = await interaction.guild.autoModerationRules.fetch(config.automod.spamLinkRule);
910
if (!rule) return await interaction.reply(notices.error("Spam link filter rule not found! Report this to Zerebos!", {ephemeral: true}));
1011

1112
const existing = rule.triggerMetadata?.keywordFilter ?? [];

src/config.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* Every Discord snowflake and community-specific constant the bot depends on.
3+
*
4+
* These were inline literals scattered across six files — the BetterDiscord
5+
* guild id appeared four times, the developer role ids five. Each entry may be
6+
* overridden by an environment variable so the bot can be pointed at a test
7+
* server without editing source.
8+
*/
9+
10+
const id = (key: string, fallback: string): string => process.env[key] || fallback;
11+
12+
export const config = {
13+
guilds: {
14+
/** The main BetterDiscord server. */
15+
betterDiscord: id("BD_GUILD_ID", "86004744966914048")
16+
},
17+
18+
roles: {
19+
/** Roles in the main server that mark someone as a verified developer. */
20+
pluginDeveloper: id("BD_ROLE_PLUGIN_DEV", "125166040689803264"),
21+
themeDeveloper: id("BD_ROLE_THEME_DEV", "165005972970930176"),
22+
23+
/** The equivalents in the developer community server, kept in sync. */
24+
communityPluginDeveloper: id("COMMUNITY_ROLE_PLUGIN_DEV", "948627723830591568"),
25+
communityThemeDeveloper: id("COMMUNITY_ROLE_THEME_DEV", "948627648706392104")
26+
},
27+
28+
channels: {
29+
/** Where compromised-account warnings are posted. */
30+
accountIssues: id("BD_CHANNEL_ACCOUNT_ISSUES", "1465301762821853204")
31+
},
32+
33+
automod: {
34+
/** The AutoMod rule whose keyword list `/spam link` appends to. */
35+
spamLinkRule: id("BD_AUTOMOD_SPAM_LINK_RULE", "1256935881168781332")
36+
}
37+
} as const;
38+
39+
export default config;

src/events/detectcryptoscam.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import {Events, Message, PermissionFlagsBits} from "discord.js";
2+
import config from "../config";
23
import {guildDB} from "../db";
34
import {sendModLog} from "../util/modlog";
45

56

67
const TIMEOUT_DURATION = 60 * 60 * 1000; // 1 hour in milliseconds
7-
const TARGET_GUILD_ID = "86004744966914048";
8-
const ACCOUNT_ISSUES_CHANNEL_ID = "1465301762821853204";
98
const sketchyImageRegex = /https:\/\/(?:cdn|media)\.(?:discord|discordapp)\.(?:com|net)\/attachments\/\d+\/\d+\/(?:[1234]|image)\.(?:jpg|png|webp)(?:\?.*?)?(?:\s+|$)/;
109

1110
// TODO: consider de-duping with invitefilter event
@@ -16,7 +15,7 @@ export default {
1615
// Ignore DM messages and owner messages and people with manage messages perms
1716
if (!message.inGuild() || message.author.id === process.env.BOT_OWNER_ID) return;
1817
if (message.author.id === message.client.user.id) return;
19-
if (message.guild.id !== TARGET_GUILD_ID) return;
18+
if (message.guild.id !== config.guilds.betterDiscord) return;
2019
if (message.channel.permissionsFor(message.author)?.has(PermissionFlagsBits.ManageMessages)) return;
2120

2221
// Obviously if this is disabled we don't need to do this stuff either
@@ -48,7 +47,7 @@ export default {
4847
console.error("Could not timeout member. Likely permissions.");
4948
}
5049

51-
const accountIssuesChannel = message.guild.channels.cache.get(ACCOUNT_ISSUES_CHANNEL_ID);
50+
const accountIssuesChannel = message.guild.channels.cache.get(config.channels.accountIssues);
5251
if (accountIssuesChannel && accountIssuesChannel.isTextBased()) {
5352
await accountIssuesChannel.send({content: `${message.author.toString()} (${message.author.id}) your account may be compromised! Change your password and remove any unfamiliar account connections and authorized apps.`});
5453
}

src/events/developer.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
import {Events, GuildMember} from "discord.js";
2+
import config from "../config";
23

34

45
export default {
56
name: Events.GuildMemberAdd,
67

78
async execute(member: GuildMember) {
8-
const bdGuild = await member.client.guilds.fetch("86004744966914048");
9+
const bdGuild = await member.client.guilds.fetch(config.guilds.betterDiscord);
910
const bdMember = await bdGuild.members.fetch(member);
1011
if (!bdMember) return;
1112

12-
const isPluginDev = bdMember.roles.cache.has("125166040689803264");
13-
const isThemeDev = bdMember.roles.cache.has("165005972970930176");
14-
const rolesToAdd = [isPluginDev ? "948627723830591568" : "", isThemeDev ? "948627648706392104" : ""].filter(r => r);
13+
const isPluginDev = bdMember.roles.cache.has(config.roles.pluginDeveloper);
14+
const isThemeDev = bdMember.roles.cache.has(config.roles.themeDeveloper);
15+
const rolesToAdd = [isPluginDev ? config.roles.communityPluginDeveloper : "", isThemeDev ? config.roles.communityThemeDeveloper : ""].filter(r => r);
1516

1617
try {
1718
await member.roles.add(rolesToAdd, "Syncing roles from main server");

0 commit comments

Comments
 (0)