feat(bot): list all server members for whitelist search (gated intent)
To show every server user (not just cached speakers) in the whitelist/blacklist popup, the bot needs the privileged Server Members Intent. Declaring it while the Developer Portal toggle is off breaks login, so it's gated behind WSAI_MEMBERS_INTENT=1: when set, the bot adds GuildMembers intent, fetches each guild's full member list on ready, and reports it (cap 200→2000). Default off = unchanged behavior, safe to deploy. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
23
dave/bot.mjs
23
dave/bot.mjs
@@ -161,9 +161,14 @@ if (process.argv.includes('--invite')) {
|
||||
if (!TOKEN) { console.error('no DISCORD_BOT_TOKEN in env or ../.env'); process.exit(2); }
|
||||
|
||||
// ---------- client ----------
|
||||
const client = new Client({
|
||||
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates],
|
||||
});
|
||||
// Listing ALL server members needs the privileged "Server Members Intent".
|
||||
// Gate it behind an env flag: enabling the intent in code while the Developer
|
||||
// Portal toggle is OFF makes login fail ("disallowed intents"). So this stays
|
||||
// off until the user turns the portal intent on and sets WSAI_MEMBERS_INTENT=1.
|
||||
const MEMBERS_INTENT = (process.env.WSAI_MEMBERS_INTENT || env.WSAI_MEMBERS_INTENT) === '1';
|
||||
const intents = [GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates];
|
||||
if (MEMBERS_INTENT) intents.push(GatewayIntentBits.GuildMembers);
|
||||
const client = new Client({ intents });
|
||||
|
||||
const perUser = new Map(); // userId -> { opusPackets, pcmFrames }
|
||||
|
||||
@@ -271,7 +276,7 @@ function buildState() {
|
||||
roles: [...g.roles.cache.values()]
|
||||
.filter((r) => r.id !== g.id && r.name !== '@everyone')
|
||||
.map((r) => ({ id: r.id, name: r.name })),
|
||||
members: [...g.members.cache.values()].slice(0, 200).map((m) => ({
|
||||
members: [...g.members.cache.values()].slice(0, 2000).map((m) => ({
|
||||
id: m.id, name: m.displayName, bot: m.user?.bot === true,
|
||||
roleIds: [...m.roles.cache.keys()],
|
||||
})),
|
||||
@@ -342,6 +347,16 @@ client.once('clientReady', async () => {
|
||||
log('no default channel — waiting for the dashboard to select a server/voice channel…');
|
||||
}
|
||||
|
||||
// With the members intent on, pull the full member list of each guild so the
|
||||
// whitelist/blacklist popup can search every user (not just cached speakers).
|
||||
if (MEMBERS_INTENT) {
|
||||
for (const g of client.guilds.cache.values()) {
|
||||
g.members.fetch()
|
||||
.then((m) => log(`fetched ${m.size} members of "${g.name}"`))
|
||||
.catch((e) => log(`member fetch failed ("${g.name}"): ${e.message}`));
|
||||
}
|
||||
}
|
||||
|
||||
// Report state + poll commands forever. This is what powers the dashboard's
|
||||
// bot info, server/voice-channel pickers, participant list, and join/leave.
|
||||
reportLoop();
|
||||
|
||||
Reference in New Issue
Block a user