EDA.Gateway.Capabilities (EDA v0.4.0)

Copy Markdown View Source

Gateway capabilities — opt-in protocol behaviour sent in the IDENTIFY payload.

Capabilities let a bot enable a gateway behaviour before Discord makes it mandatory, so the change can be observed and handled ahead of its deadline.

Configuration

config :eda, capabilities: [:channel_obfuscation]
config :eda, capabilities: :channel_obfuscation   # single capability
config :eda, capabilities: 32768                  # raw bitfield

Unset (the default) sends no capabilities field at all, so gateway behaviour is unchanged.

Channel obfuscation

:channel_obfuscation (1 <<< 15) opts into Discord's redaction of channels the bot cannot see. Once enabled — and for every bot from 2026-11-16, whether opted in or not — such channels are still dispatched over the gateway but caviarded:

  • name becomes "___hidden___",
  • sensitive fields are nulled or reduced,
  • permission_overwrites holds a single overwrite denying VIEW_CHANNEL to the guild's @everyone role,
  • the channel's flags carry CHANNEL_OBFUSCATED (1 <<< 17).

Interaction payloads are built through a separate path and are never obfuscated.

REST is not obfuscated

Discord's changelog states GET /guilds/{guild.id}/channels omits inaccessible channels. That is not the observed behaviour. Probed against a real guild on 2026-09-19 with this capability enabled: all 44 obfuscated channels were returned by REST, with their real name, flags: 0 and their genuine permission overwrites — only the gateway payloads were redacted. Treat the two sources as disagreeing, and do not rely on either to hide a channel.

The same opt-in is available as the "Private Channel Obfuscation" toggle in the Developer Portal; this option is the programmatic equivalent.

Cache and permissions

Obfuscated channels are cached like any other, so EDA.Cache.channels_for_guild/1 returns "___hidden___" entries — reject them with EDA.Channel.obfuscated?/1 before showing a channel list. EDA.Permission.in_channel/3 already refuses to compute from the synthetic overwrite and returns {:error, :channel_obfuscated}.

Summary

Functions

Returns all capability names EDA knows about.

Checks whether a capability is enabled in a bitfield.

Converts capabilities to a bitfield integer.

Functions

all_capabilities()

@spec all_capabilities() :: [atom()]

Returns all capability names EDA knows about.

has_capability?(bitfield, capability)

@spec has_capability?(non_neg_integer(), atom()) :: boolean()

Checks whether a capability is enabled in a bitfield.

Examples

iex> EDA.Gateway.Capabilities.has_capability?(32768, :channel_obfuscation)
true

iex> EDA.Gateway.Capabilities.has_capability?(0, :channel_obfuscation)
false

to_bitfield(bitfield)

@spec to_bitfield(non_neg_integer() | atom() | [atom()]) :: non_neg_integer()

Converts capabilities to a bitfield integer.

Accepts a list of atoms, a single atom, or a raw integer. A raw integer passes through unchanged so that capabilities Discord adds later can be sent without a library update.

Examples

iex> EDA.Gateway.Capabilities.to_bitfield([])
0

iex> EDA.Gateway.Capabilities.to_bitfield([:channel_obfuscation])
32768

iex> EDA.Gateway.Capabilities.to_bitfield(:channel_obfuscation)
32768

iex> EDA.Gateway.Capabilities.to_bitfield(41)
41