Discord: channel list and presence without the main bot (server-26#225 S5)

A server linked to an org now shows in the node picker while a radio bot the
org may use is in it, even when the DRB server bot is absent or left. Its
voice-channel list is read from that radio bot's cached REST snapshot
(discord_rest.guild_directory, the same snapshot the permission check reads,
so no extra Discord request): inline when no list is stored, in the
background when the list is older than discord_directory_refresh_seconds.
The server bot's own fresh list still wins (back-compat) and its directory
push now drops the server's cached snapshots.

Guards: a server acting only through the unlinked-server fallback org still
needs the server bot; REST never creates a discord_guilds doc, never writes
org_id or bot_present, and never writes onto a server unlinked meanwhile.

Also fixes server-26#251: an interactive start (/join, admin page, web
picker, node discord_join) re-reads a cached "denied" snapshot older than
10 s once before refusing, so "fix it in Discord, then try again" works on
the next try. The reconciler never re-reads (no REST loop).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Logan Cusano
2026-10-05 02:53:57 -04:00
co-authored by Claude Opus 5.5
parent e54191a5d0
commit a976464e72
8 changed files with 746 additions and 25 deletions
+4
View File
@@ -50,6 +50,10 @@ export interface DiscordGuildOption {
linked: boolean;
synced: boolean;
synced_at: string | null;
/** Who listed the channels (server-26#225 S5): the DRB server bot, or a radio bot read over REST. */
directory_source?: "main_bot" | "radio_bot" | null;
/** The DRB server bot is in this server. Not required: a radio bot alone is enough. */
main_bot_present?: boolean;
voice_channels: DiscordVoiceChannel[];
streams_on: number;
bot: { ok: boolean; code: string | null; message: string | null; invite: DiscordInvite[] };