* feat(discord): add configurable privileged Gateway Intents (GuildPresences, GuildMembers)
Add support for optionally enabling Discord privileged Gateway Intents
via config, starting with GuildPresences and GuildMembers.
When `channels.discord.intents.presence` is set to true:
- GatewayIntents.GuildPresences is added to the gateway connection
- A PresenceUpdateListener caches user presence data in memory
- The member-info action includes user status and activities
(e.g. Spotify listening activity) from the cache
This enables use cases like:
- Seeing what music a user is currently listening to
- Checking user online/offline/idle/dnd status
- Tracking user activities through the bot API
Both intents require Portal opt-in (Discord Developer Portal →
Privileged Gateway Intents) before they can be used.
Changes:
- config: add `channels.discord.intents.{presence,guildMembers}`
- provider: compute intents dynamically from config
- listeners: add DiscordPresenceListener (extends PresenceUpdateListener)
- presence-cache: simple in-memory Map<userId, GatewayPresenceUpdate>
- discord-actions-guild: include cached presence in member-info response
- schema: add labels and descriptions for new config fields
* fix(test): add PresenceUpdateListener to @buape/carbon mock
* Discord: scope presence cache by account
---------
Co-authored-by: kugutsushi <kugutsushi@clawd>
Co-authored-by: Shadow <hi@shadowing.dev>
53 lines
1.5 KiB
TypeScript
53 lines
1.5 KiB
TypeScript
import type { GatewayPresenceUpdate } from "discord-api-types/v10";
|
|
|
|
/**
|
|
* In-memory cache of Discord user presence data.
|
|
* Populated by PRESENCE_UPDATE gateway events when the GuildPresences intent is enabled.
|
|
*/
|
|
const presenceCache = new Map<string, Map<string, GatewayPresenceUpdate>>();
|
|
|
|
function resolveAccountKey(accountId?: string): string {
|
|
return accountId ?? "default";
|
|
}
|
|
|
|
/** Update cached presence for a user. */
|
|
export function setPresence(
|
|
accountId: string | undefined,
|
|
userId: string,
|
|
data: GatewayPresenceUpdate,
|
|
): void {
|
|
const accountKey = resolveAccountKey(accountId);
|
|
let accountCache = presenceCache.get(accountKey);
|
|
if (!accountCache) {
|
|
accountCache = new Map();
|
|
presenceCache.set(accountKey, accountCache);
|
|
}
|
|
accountCache.set(userId, data);
|
|
}
|
|
|
|
/** Get cached presence for a user. Returns undefined if not cached. */
|
|
export function getPresence(
|
|
accountId: string | undefined,
|
|
userId: string,
|
|
): GatewayPresenceUpdate | undefined {
|
|
return presenceCache.get(resolveAccountKey(accountId))?.get(userId);
|
|
}
|
|
|
|
/** Clear cached presence data. */
|
|
export function clearPresences(accountId?: string): void {
|
|
if (accountId) {
|
|
presenceCache.delete(resolveAccountKey(accountId));
|
|
return;
|
|
}
|
|
presenceCache.clear();
|
|
}
|
|
|
|
/** Get the number of cached presence entries. */
|
|
export function presenceCacheSize(): number {
|
|
let total = 0;
|
|
for (const accountCache of presenceCache.values()) {
|
|
total += accountCache.size;
|
|
}
|
|
return total;
|
|
}
|