Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .eslintignore

This file was deleted.

35 changes: 0 additions & 35 deletions .eslintrc.js

This file was deleted.

3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ lib
test-config
package-lock.json
example/config.json
.env
.codebuddy/
pnpm-lock.yaml
6 changes: 3 additions & 3 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"editor.defaultFormatter": "esbenp.prettier-vscode",
"eslint.validate": ["javascript", "typescript",],
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
"source.fixAll": true,
"source.fixAll.stylelint": true
"source.fixAll.eslint": "explicit",
"source.fixAll": "explicit",
"source.fixAll.stylelint": "explicit"
},
}
101 changes: 90 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,107 @@
# QQ 频道机器人 SDK qq-guild-bot
# QQ Bot NodeSDK

用于开发 QQ 频道机器人的 Node.js SDK。
QQ 机器人 Node.js SDK,支持频道、群、C2C 单聊场景

## 使用文档
## 功能特性

[NodeSDK 文档](https://bot.q.qq.com/wiki/develop/nodesdk/)
- **OAuth2 认证** — 基于 AppID + Secret 自动获取和刷新 AccessToken
- **WebSocket** — 长连接接收事件推送(频道 / 群 / C2C / 好友等)
- **Webhook** — HTTP 回调接收事件(Ed25519 签名验证)
- **频道消息 API** — 发送文本、Markdown、Ark、Embed、图片等
- **群消息 API** — 发送群文本、Markdown、富媒体、流式消息等
- **C2C 消息 API** — 单聊文本、富媒体(图片/语音/视频/文件)
- **富媒体上传** — 分步上传 + file_info 发送
- **HTTPS 代理** — 支持 `https_proxy` 环境变量(CONNECT 隧道,方便 Whistle/Charles 抓包)

## 安装

```bash
npm install qq-guild-bot
```

## 快速开始

```js
const { createOpenAPI, createWebsocket } = require('qq-guild-bot');

// 1. 创建 OpenAPI 客户端
const client = createOpenAPI({
appID: '你的AppID',
secret: '你的AppSecret',
});

// 2. 创建 WebSocket 连接
const ws = createWebsocket({
appID: '你的AppID',
secret: '你的AppSecret',
intents: ['GROUP_MESSAGES'],
});

// 3. 监听事件
ws.on('READY', (data) => {
console.log('机器人已上线:', data);
});

ws.on('GROUP_MESSAGES', async (eventData) => {
if (eventData.eventType === 'C2C_MESSAGE_CREATE') {
const msg = eventData.msg;
await client.c2cMessageApi.postC2CMessage(msg.author.id, {
content: '收到!',
msg_type: 0,
msg_id: msg.id,
});
}
});
```

## 示例项目

`example/` 目录包含一个完整的模块化示例,覆盖 C2C / 群 / 频道场景:

```bash
# 先构建 SDK
npm run build

# 进入示例目录
cd example
cp .env.example .env # 填入 AppID 和 Secret
npm install
npm run dev
```

详见 [example/README.md](example/README.md)。

## 本地开发

```shell
# clone repo
```bash
# 克隆仓库
git clone https://github.com/tencent-connect/bot-node-sdk.git

# cd repo
cd bot-node-sdk

# run
# 安装依赖
npm install

# 开发模式(watch)
npm run dev

# run example
npm run linkdev
# 生产构建
npm run build

# 运行示例
npm run example

# 运行测试
npm run test
```

> **注意**:修改 SDK 源码后需要 `npm run build`,然后在 `example/` 目录执行 `npm install` 同步最新构建产物。

## 使用文档

[QQ 机器人官方文档](https://bot.q.qq.com/wiki/develop/api-v2/)

[NodeSDK 文档](https://bot.q.qq.com/wiki/develop/nodesdk/)

## 参与共建 [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)

- 👏 如果您有针对 SDK 的错误修复,请以分支`fix/xxx`向`main`分支发 PR
Expand Down
79 changes: 79 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import globals from 'globals';
import tseslint from 'typescript-eslint';
import eslintConfigPrettier from 'eslint-config-prettier';
import eslintPluginPrettier from 'eslint-plugin-prettier';
import jest from 'eslint-plugin-jest';

export default tseslint.config(
// 全局忽略(替代 .eslintignore)
{
ignores: ['dist/**', 'node_modules/**', 'example/**', 'es/**', 'lib/**', 'typings/**'],
},

// JS/TS 基础推荐规则
...tseslint.configs.recommended,

// Prettier 兼容(关闭冲突规则)
eslintConfigPrettier,

// 通用配置
{
languageOptions: {
ecmaVersion: 2018,
sourceType: 'module',
globals: {
...globals.node,
},
},
plugins: {
prettier: eslintPluginPrettier,
},
rules: {
'prettier/prettier': 'warn',

// 从原 .eslintrc.js 迁移的规则
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/no-empty-interface': 'off',
'@typescript-eslint/no-this-alias': 'off',
'@typescript-eslint/no-require-imports': 'off',
'@typescript-eslint/prefer-optional-chain': 'off',
'no-new-func': 'off',
complexity: 'off',
'max-params': 'off',
'no-param-reassign': 'off',
'no-trailing-spaces': [
'error',
{
skipBlankLines: true,
},
],

// 放宽一些对旧代码过于严格的规则
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-empty-object-type': 'off',
'@typescript-eslint/no-unused-expressions': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/no-unused-vars': [
'warn',
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
],
},
},

// 测试文件配置
{
files: ['test/**/*.ts'],
plugins: {
jest,
},
languageOptions: {
globals: {
...globals.jest,
},
},
rules: {
...jest.configs.recommended.rules,
'jest/no-conditional-expect': 'warn',
},
},
);
12 changes: 12 additions & 0 deletions example/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# QQ Bot 配置
BOT_APP_ID=你的AppID
BOT_APP_SECRET=你的AppSecret

# 是否沙箱环境 (true/false)
BOT_SANDBOX=false

# 启动模式: ws | webhook
MODE=ws

# Webhook 端口(仅 webhook 模式)
PORT=8080
104 changes: 100 additions & 4 deletions example/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,102 @@
# 简单示例
# QQ Bot SDK 示例项目

## 步骤
## 快速开始

- 1、将 `config.example.json` 重命名为 `config.json`,并更新相关配置信息
- 2、`yarn example`
1. 复制 `.env.example` 为 `.env`,填入你的 AppID 和 Secret:

```bash
cp .env.example .env
```

2. 安装依赖并启动:

```bash
npm install
npm run dev
```

或者从根目录启动:

```bash
# 在 bot-node-sdk 根目录
npm install # 安装 SDK 依赖
npm run build # 构建 SDK
cd example
npm install # 安装示例依赖(同步最新 SDK 构建产物)
npm run dev
```

## 项目结构

```
example/
├── index.js # 入口:配置加载 + WebSocket/Webhook 事件分发
├── .env.example # 环境变量模板
├── handlers/
│ ├── c2c.js # C2C 单聊消息处理(指令路由 + 富媒体回声)
│ ├── group.js # 群消息处理(与 C2C 对称)
│ └── guild.js # 频道消息处理
├── commands/
│ ├── index.js # 指令注册入口(所有指令在此注册)
│ ├── registry.js # 指令路由中心(cmdMap)
│ ├── help.js # /help — Markdown 帮助菜单(参数指令标签)
│ └── media.js # /发图片 /发语音 /发视频 /发文件 /发MD
└── utils/
└── message.js # 消息体构建工具(类型推断、按钮构造等)
```

## 支持的指令

| 指令 | 说明 |
| ---------- | --------------------------------- |
| `/help` | 显示帮助菜单(Markdown 参数指令) |
| `/发图片` | 发送一张示例图片 |
| `/发视频` | 发送一段示例视频 |
| `/发语音` | 发送一段示例语音 |
| `/发文件` | 发送一个示例文件 |
| `/发MD` | 发送 Markdown 示例(可带自定义内容) |

- `/发MD` 不带参数时发送默认示例,带参数时用参数内容作为 Markdown 正文
- 富媒体发送内部自动分两步(上传获取 file_info → 用 file_info 发消息),对用户透明

## C2C / 群消息回声

收到以下类型的消息会先回复内容信息(文件名、类型、大小、URL),再回声发回原文件:

- ✅ 纯文本
- ✅ 图片
- ✅ 语音
- ✅ 视频
- ✅ 文件

## 添加新指令

在 `commands/` 目录新建文件,然后在 `commands/index.js` 中注册即可:

```js
// commands/ping.js
async function pingHandler(ctx) {
await ctx.reply({ content: 'pong! 🏓', msg_type: 0 });
}
module.exports = { pingHandler };
```

```js
// commands/index.js 中添加:
const { pingHandler } = require('./ping');
registry.register('/ping', pingHandler, '测试延迟');
```

重启后生效,`/help` 菜单会自动包含新指令。

## ctx 上下文对象

指令处理器接收一个 `ctx` 对象,包含以下方法:

| 属性/方法 | 说明 |
| --- | --- |
| `ctx.msg` | 原始消息对象 |
| `ctx.args` | 指令参数(指令名之后的文本) |
| `ctx.reply(body)` | 回复消息(自动带 msg_id 做被动回复) |
| `ctx.uploadMedia(body)` | 上传富媒体文件,返回 file_info |
| `ctx.nextSeq()` | 获取递增的消息序号(用于去重) |
Loading