Bot API
Everything @gryt/bot exports, generated from the source
Generated from the source and regenerated by CI, so it cannot fall behind the code. Editing this page by hand gets the edit wiped on the next run — change what the generator reads instead.
This is the reference. Writing a bot is the page that teaches the shape: the handshake, waiting to be approved, and what a bot does when an admin says no.
Everything below is exported from @gryt/bot. Nothing else in the package is
public.
import { GrytBot, parseCommand, splitArgs, createIdentity, loadIdentity, PERMISSIONS_BEFORE_CATALOGUE } from "@gryt/bot";GrytBot
A bot on one Gryt server. It joins like any other client and is a member like any other: no bot account type and no bypass, so what it may do is what its role says.
can()
can(permission: Permission): booleanFalse before ready. True for a permission the server's catalogue does not have — that
is a server older than the permission, not a refusal.
command()
command(name: string, handler: (ctx: CommandContext) => void | Promise<void>, options: CommandOptions = {}): thisRegister a command. Later registrations of the same name replace earlier.
start()
start(): Promise<ServerInfo>Connect, join, and resolve once the server has said who this bot is. On a first run it
does not resolve: the bot is waiting at the door. Listen for waiting, then ready.
stop()
stop(): Promise<void>Leave, and stop reconnecting.
send()
send(conversationId: string, text: string): Promise<void>Post in a channel. Throws before sending if the bot lacks send_messages, naming the
permission, so the stack trace points at the call rather than a socket handler.
react()
react(conversationId: string, messageId: string, reactionSrc: string): Promise<void>delete()
delete(conversationId: string, messageId: string, opts: { own?: boolean } = {}): Promise<void>Delete a message. Its own is delete_own_messages; anybody else's is manage_messages,
and the caller says which, because the bot may not know who sent it.
fetch()
fetch(conversationId: string, limit = 50): Promise<void>Ask for the last N messages in a channel. Answered on the message event.
GrytBotEvents
| Field | Type | What it is |
|---|---|---|
ready | [ServerInfo] | |
message | [Message] | |
members | [Member[]] | |
channels | [Channel[]] | |
error | [Error] | Something the server refused. Always worth logging; often a permission. |
waiting | [string] | Turned away pending approval. Not an error — see the note in wire. |
disconnected | [string] |
GrytBotOptions
| Field | Type | What it is |
|---|---|---|
host | string | chat.example.com, or localhost:5001. Scheme optional. |
nickname? | string | What the member list will call it. |
identityPath? | string | Where the key lives. The file is the bot — see identity.ts. |
identity? | BotIdentity | An already-loaded identity, if you keep the key somewhere of your own. |
wants? | string[] | Sent once, the first time it turns up, and shown to whoever approves it. Fixed from then on: a later run declaring more gets the answer to the question the first one asked. |
description? | string | One line, shown beside the ask. Say what the bot is for. |
botToken? | string | A token from a registration an operator set up in advance: no approval to wait for. Single-use — the first bot to present it becomes that registration. |
prefix? | string | The command prefix. Set to "" to turn the router off entirely. |
helpCommand? | boolean | Whether to answer help with a listing. On by default. |
secure? | boolean | Force http/https rather than guessing from the host. |
parseCommand
Which command a message invokes, if any. Case-insensitive on the command word, because
somebody will type !Help and being right about it helps nobody.
parseCommand(text: string, prefix: string): { name: string; rest: string } | nullsplitArgs
splitArgs(rest: string): string[]CommandContext
| Field | Type | What it is |
|---|---|---|
message | Message | The message that invoked it. |
rest | string | Everything after the command word, trimmed. Empty string, never null. |
args | string[] | rest split on whitespace, with empties dropped. |
reply | (text: string): Promise<void> | Reply in the channel the command came from. |
react | (emoji: string): Promise<void> | React to the message that invoked it. |
CommandOptions
| Field | Type | What it is |
|---|---|---|
description? | string | One line, for the help listing. |
requires? | Permission[] | Permissions the bot needs before this command is worth offering, checked before the handler runs. About the bot, not the person: what they may do is the server's business. |
RegisteredCommand
| Field | Type | What it is |
|---|---|---|
name | string | |
handler | (ctx: CommandContext) => void | Promise<void> |
createIdentity
Mint a new identity. The bot this belongs to has never been seen anywhere.
createIdentity(): Promise<{ identity: BotIdentity; privateJwk: JWK; }>loadIdentity
The second run must be the same bot: same id, same role, same history. Written 0o600 —
anyone who can read this file can be this bot.
loadIdentity(path: string): Promise<BotIdentity>PERMISSIONS_BEFORE_CATALOGUE
Stands in for the catalogue on a server too old to publish one, so an absent permission is not read as a refusal. Frozen: it describes a release that has already happened.
PERMISSIONS_BEFORE_CATALOGUE: readonly Permission[] = [ "send_messages", "attach_files", "add_reactions", "join_voice", "speak", "share_video", "share_screen", "change_nickname", "change_avatar", "create_invite", "manage_invites", "manage_messages", "kick_members", "ban_members", "mute_members", "manage_reports", "manage_join_requests", "manage_channels", "manage_emojis", "manage_webhooks", "manage_roles", "manage_server", "view_audit_log", ]BotIdentity
| Field | Type | What it is |
|---|---|---|
subject | string | The id this bot will be known by on every server. Derived from the key. |
certificate | (): Promise<string> | A certificate that vouches for itself, valid for an hour. |
assertion | (audience: string, nonce: string): Promise<string> | Proof, bound to one server's challenge, that this bot holds the key. |
Attachment
| Field | Type | What it is |
|---|---|---|
file_id | string | |
mime | string | null | |
size | number | null | |
original_name | string | null | |
width | number | null | |
height | number | null | |
has_thumbnail | boolean |
Channel
| Field | Type | What it is |
|---|---|---|
id | string | |
name | string | |
type | "text" | "voice" |
ServerRefusal
Why the server refused something. The machine-readable half is error; code is accepted
too, because this SDK reached for that name first and the mistake read as a crash.
| Field | Type | What it is |
|---|---|---|
error? | string | |
code? | string | |
message? | string | |
permission? | string | Named when the refusal was a permission. |
Member
| Field | Type | What it is |
|---|---|---|
serverUserId | string | |
nickname | string | |
role | string | |
status | "online" | "in_voice" | "afk" | "offline" | |
avatarFileId | string | null |
Message
| Field | Type | What it is |
|---|---|---|
conversationId | string | |
messageId | string | |
senderServerUserId | string | |
senderNickname | string | null | |
text | string | null | |
attachments | Attachment[] | |
createdAt | Date | |
editedAt | Date | null | |
replyToMessageId | string | null | |
isSystem | boolean | True for the "X joined the server" kind of message, which has no sender. |
isOwn | boolean | True when this bot sent it. Handlers are not called for these. |
Permission
A permission id. The server owns the list; see GrytBot.permissions.
export type Permission = string;ServerInfo
| Field | Type | What it is |
|---|---|---|
serverId | string | |
name | string | |
description | string | |
permissions | Permission[] | What this bot may do here. Empty until the server has said. |
role | string | The role this bot holds. |