Skip to main content
A Cloak mention is two independent halves, and you supply both: the pill is literal text inside the encrypted body, and the ping is an [id, isRole] pair in SendOptions.mentions. These helpers build and read both halves. For the model and the patterns, see Mentions and replies.
Mention targets are not end-to-end encrypted. Message bodies are, the list of who a message pings is not. It rides the send frame in plaintext because the server routes notification fanout without decrypting anything. Anyone with server-side visibility can see who your bot pinged, just not what it said. This is Cloak’s design and it is true of every Cloak client.

userMention

The rendered form of a user mention: Cloak’s id-keyed wire entity, HTML-escaped exactly as every human client writes it. Accepts a raw id or anything with an id, and normalizes dashed uuids to undashed lowercase hex.
Because the pill is keyed by id, it follows the user across nickname and display-name changes.
The text alone renders a pill and notifies nobody. Pass mentions too, or the ping does not happen.

roleMention

The rendered form of a role mention: literal @Name. Roles are still name-keyed on the wire, so the pill renders only for viewers whose client resolves that role name, and renaming the role stops old messages from rendering it. The ping itself rides the id pair and is unaffected. Multi-word role names work, because clients match them longest first. Single-word names must match [\w-]+ to render as a pill.
Role, @everyone and @here pings are gated server-side on mention_roles. client.can('mention_roles', serverId) is an advisory pre-check, and the server remains authoritative.

mentionPairs

Builds the plaintext ping array for the outbound frame. Deduplicates, and drops empty ids. send() calls this for you on SendOptions.mentions, so you rarely call it directly. Reach for it when you are building a frame yourself with client.raw. The pairs it produces: Ids may be passed dashed or undashed. The backend validates direct mention ids as uuids and silently discards targets that are not members of the server.

parseMentions

Recovers the mentions carried by a decrypted message body. This is how the real clients decide “was I mentioned”. The ping array a sender supplies is routing metadata the server consumes and never echoes back, so the decrypted text is the only inbound source. Message.mentions and Message.mentionsMe are produced by this function, and fetched history is populated identically.
@Everyone and @Here are matched case-insensitively, exactly like the clients.

EVERYONE and HERE

The literal pill text for the two broadcast mentions. Pair each with the matching target, because text alone notifies nobody.

MENTION_ENTITY_RE

Matches a user-mention wire entity, raw or HTML-escaped, dashed or raw hex. Exported so you can scan text yourself without re-deriving the pattern.
It carries the global flag. Reset MENTION_ENTITY_RE.lastIndex = 0 before every use, or a second scan starts wherever the previous one stopped. Prefer parseMentions() unless you specifically need the raw matches.

Types

MentionTarget

What SendOptions.mentions accepts. Ids may be dashed or undashed.

MentionPair

One entry of the plaintext ping array. The second element is 1 for a role and 0 for everything else.

MessageMentions

What parseMentions() returns, and the shape of Message.mentions.
string[]
Normalized (undashed, lowercase) ids of the user-mention entities in the body.
string[]
Literal @name tokens that are neither @everyone, @here, nor an id entity. A name may be a role, an older-format user mention, or just text. The SDK cannot tell them apart without the server’s role list.
boolean
The body contains @everyone, case-insensitively.
boolean
The body contains @here, case-insensitively.
Message.mentionsMe covers direct mentions only. A role mention cannot be resolved to “this means me”: the SDK does not know which roles the bot holds, because permission verdicts carry an effective rank rather than role ids. Compare names against guild(serverId).fetchRoles() if you need that.
Do not compare names against fetchMembers(). That method is broken against every current backend: it awaits a frame the backend no longer sends, so it neither resolves nor rejects, and awaiting it hangs your handler. fetchRoles() works.

Next

Mentions and replies

The two-part model, and true replies.

Sending messages

Where SendOptions is documented.

Encryption lanes

What leaves the encrypted envelope, and why.

Types

Message, SendOptions, and the rest.