JavaScript client — `@disband/bot`

The official JavaScript client. Zero runtime dependencies — it uses only fetch and standard globals — and works from Node.js 18+, Deno, Bun, and the browser.

Install

npm install @disband/bot

or, from this monorepo:

npm install /path/to/packages/bot

Quick start

import { Client } from "@disband/bot";

const client = new Client({ token: process.env.DISBAND_BOT_TOKEN });

client.on("ready", (me) => {
  console.log(`Logged in as ${me.name} (${me.scopes.join(", ")})`);
});

client.on("messageCreate", async (message) => {
  if (message.author?.is_bot) return;
  if (message.content !== "!ping") return;
  await message.reply("pong");
});

await client.connect();

Constructor

`new Client({ token, baseUrl?, gatewayTimeout? })`

Option Type Default Description
token string (required) The bot token from Settings → Bots.
baseUrl string "https://www.disband.dev" API root (change for a custom domain).
gatewayTimeout number 20 Seconds per gateway poll (1–20).

Lifecycle

Method Description
connect() Resolves the bot identity (GET /api/bot/me), emits ready, and starts the gateway loop. Resolves once connected.
close() Stops the gateway loop.
connected Boolean: whether the loop is currently running.

Events

Register with client.on(name, handler); some are async. once and off work the same way they do in Node's EventEmitter.

Event Args Notes
ready user user.id, user.userId, user.name, user.username, user.avatarUrl, user.scopes.
messageCreate message A new message in a server the bot can see.
messageUpdate message A message was edited (content, editedAt updated).
messageDelete message A message was deleted (content empty; id/channelId valid).
error error Gateway errors. The loop retries automatically unless the token is invalid, in which case it stops.
debug * Low-level observability.

`Message`

Field Type Description
id string Message id.
channelId string Channel id.
serverId string | null Server id.
author object | null { id, username, display_name, avatar_url, is_bot }.
content string Message text.
replyToId string | null The message this replies to, if any.
mentions array Mentioned users.
attachment object | null { url, type } when the message has a file.
createdAt string | null ISO timestamp.
editedAt string | null ISO timestamp of the last edit.
displayId number | null The sequential display number.

Methodsmessage.reply(content) (replies in the same channel) and the message.authorIsBot getter (true when the sender was a bot).

Methods

await client.sendMessage(channelId, "Deploy finished");          // send
await message.reply("pong");                                      // reply to a received message

const messages = await client.listMessages(channelId, { limit: 25, before: "…" });
const channels  = await client.listChannels(serverId);
const members   = await client.listMembers(serverId);

const channelId = await client.createChannel(serverId, "deploys", { type: "text", categoryId: null });
await client.renameChannel(channelId, "deploys-2");
await client.deleteChannel(channelId);

await client.leaveServer(serverId);

const invite = await client.createInvite(serverId, ["messages.read", "messages.write"]);
// invite.invite_url -> send to the server owner

Errors

Thrown errors carry the status and body:

Error When
AuthError 401 — invalid or revoked token. The gateway loop stops on this.
PermissionError 403 — missing scope or role permission.
RateLimitError 429 — includes retryAfter seconds.
HttpError Any other non-2xx status.

Internally the client is a thin wrapper over the HTTP API: REST.get/post/patch/delete with Authorization: Bot <token>.