English (this file) · 简体中文
Node.js SDK for the QQ Open Platform. Ships every protocol primitive you need to talk to the platform:
- HTTP REST client with token management & retry policies
- Dual transport: WebSocket Gateway and Webhook
- Koa-style middleware pipeline with 12 batteries-included stages
- Text / media (image / voice / video / file) messaging, including automatic chunked upload for large files
- C2C streaming messages (
stream_messages, replace-mode) - First-class TypeScript types
Positioned like @line/bot-sdk
and @larksuiteoapi/node-sdk:
protocol + types only, no business logic.
- Node.js >= 20 (uses global
fetch/AbortController) - Pure ESM (
"type": "module"); consumers on CJS should use dynamicimport()
pnpm add @tencent-connect/qqbot-nodejs
# or
npm install @tencent-connect/qqbot-nodejs
# or
yarn add @tencent-connect/qqbot-nodejsimport { QQBot } from "@tencent-connect/qqbot-nodejs";
const bot = new QQBot({
appId: process.env.QQBOT_APP_ID!,
appSecret: process.env.QQBOT_APP_SECRET!,
logger: console,
});
bot.on("message", async (ctx, msg) => {
await bot.sendText(msg.replyTarget, `Echo: ${msg.content}`);
});
await bot.start();Full runnable examples live in examples/:
| Example | Description |
|---|---|
playground |
Text / streaming / media / commands demo |
middleware |
The full Koa-style middleware pipeline |
webhook |
HTTP callback transport (serverless-friendly) |
send-plain-100 |
Regular text send-path baseline |
send-streaming-100 |
Streaming send-path baseline |
Examples read
QQBOT_APP_ID/QQBOT_APP_SECRETfromprocess.envonly for demo convenience. The SDK itself never reads environment variables — credentials are always injected vianew QQBot({ appId, appSecret }).
// WebSocket (default) — long-lived, heartbeat + RESUME
const bot = new QQBot({ appId, appSecret });
// Webhook — HTTP callback, ideal for Serverless / horizontal scaling
const bot = new QQBot({
appId, appSecret,
transport: "webhook",
webhook: { port: 8080, path: "/callback" },
});Middleware, event listeners and send APIs are identical across transports.
The SDK ships an onion-model pipeline; bot.on("message", ...) is the
innermost downstream:
import {
errorHandler,
messageFilter,
contentSanitizer,
mentionGate,
} from "@tencent-connect/qqbot-nodejs";
bot.use(errorHandler());
bot.use(messageFilter({ skipSelfEcho: true, dedup: { windowMs: 5000 } }));
bot.use(contentSanitizer({ stripBotMention: true }));
bot.use(mentionGate({ requireMentionInGroup: true }));
bot.use(async (ctx, next) => {
const start = Date.now();
await next();
ctx.log.debug?.(`elapsed: ${Date.now() - start}ms`);
});Built-in middleware:
| Middleware | Purpose |
|---|---|
errorHandler |
Unified error capture with friendly reply |
messageFilter |
Echo suppression + message dedup |
rateLimiter |
Three-tier limiting (sender / group / global) |
concurrencyGuard |
Per-target serial processing (avoids stream races) |
accessPolicy |
Allow / block lists |
contentSanitizer |
Strip @-marker / face tags / whitespace |
mentionGate |
Group @bot gating |
quoteRef |
Message-id index + quoted-message resolution |
historyBuffer |
In-memory group history |
envelopeFormatter |
Assemble LLM prompt context (XML tags) |
typingIndicator |
Auto "typing…" in C2C |
slashCommand |
/cmd command framework |
sendImage / sendVoice / sendVideo / sendFile are convenience wrappers
over sendMedia. Files ≥ 5 MB transparently switch to chunked upload.
await bot.sendImage(target, { localPath: "/tmp/cat.jpg" });
await bot.sendFile(
target,
{ buffer: bigBuffer },
{
fileName: "report.pdf",
onProgress: (uploaded, total) => console.log(`${uploaded}/${total}`),
},
);const stream = bot.openStream({ target });
for (const partial of generator) {
await stream.update(partial); // always the full text so far, NOT a delta
}
await stream.complete();QQ platform constraint: stream_messages is available for C2C only.
bot.on("ready", () => console.log("connected"));
bot.on("resumed", () => console.log("reconnected"));
bot.on("error", (err) => console.error(err));
bot.on("message", (ctx, msg) => { /* C2C / Group / Guild / DM */ });
bot.on("interaction", (ctx, event) => { /* button clicks */ });For custom retry policies, session persistence, raw WebSocket frames etc.:
import {
ApiClient,
TokenManager,
GatewayConnection,
withRetry,
} from "@tencent-connect/qqbot-nodejs/protocol";- USAGE.md — complete usage guide (currently in Chinese; contributions to translate are very welcome).
- README.zh-CN.md — this README in Chinese.
These peerDependencies are declared as optional. Install them only if you
need the feature:
| Package | Enables |
|---|---|
silk-wasm |
Sending voice messages (SILK encoding) |
mpg123-decoder |
Decoding MP3 audio to PCM before encoding |
Bug reports, feature proposals and pull requests are welcome. Please read:
- CONTRIBUTING.md — dev workflow & commit convention
- SECURITY.md — how to report vulnerabilities privately
Thanks to all the wonderful people who have contributed to this project!
Contributor avatars are rendered by contrib.rocks.
MIT © Tencent