@karinjs/adapter-qqbot 1.2.10 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/README.md +326 -85
  2. package/dist/apps/login.d.ts +20 -0
  3. package/dist/apps/login.js +57 -0
  4. package/dist/config-H7LrvlNU.js +197 -0
  5. package/dist/index.d.ts +670 -0
  6. package/dist/index.js +2847 -0
  7. package/dist/onboard-BX8g8Wik.js +249 -0
  8. package/dist/utils-DO4gEkVN.js +3 -0
  9. package/dist/web.config.d.ts +22 -0
  10. package/dist/web.config.js +173 -0
  11. package/package.json +34 -21
  12. package/config/comment/config.json +0 -3
  13. package/config/config/config.yaml +0 -53
  14. package/lib/cli/pr.d.ts +0 -2
  15. package/lib/cli/pr.js +0 -73
  16. package/lib/core/adapter/adapter.d.ts +0 -91
  17. package/lib/core/adapter/adapter.js +0 -144
  18. package/lib/core/adapter/handler.d.ts +0 -49
  19. package/lib/core/adapter/handler.js +0 -140
  20. package/lib/core/adapter/markdown.d.ts +0 -38
  21. package/lib/core/adapter/markdown.js +0 -220
  22. package/lib/core/adapter/normal.d.ts +0 -30
  23. package/lib/core/adapter/normal.js +0 -263
  24. package/lib/core/api/index.d.ts +0 -167
  25. package/lib/core/api/index.js +0 -180
  26. package/lib/core/api/sign.d.ts +0 -22
  27. package/lib/core/api/sign.js +0 -40
  28. package/lib/core/api/types.d.ts +0 -236
  29. package/lib/core/api/types.js +0 -1
  30. package/lib/core/event/conver.d.ts +0 -10
  31. package/lib/core/event/conver.js +0 -57
  32. package/lib/core/event/index.d.ts +0 -9
  33. package/lib/core/event/index.js +0 -98
  34. package/lib/core/event/message.d.ts +0 -27
  35. package/lib/core/event/message.js +0 -95
  36. package/lib/core/event/notice.d.ts +0 -50
  37. package/lib/core/event/notice.js +0 -133
  38. package/lib/core/event/types.d.ts +0 -473
  39. package/lib/core/event/types.js +0 -1
  40. package/lib/core/internal/axios.d.ts +0 -25
  41. package/lib/core/internal/axios.js +0 -46
  42. package/lib/core/internal/sign.d.ts +0 -22
  43. package/lib/core/internal/sign.js +0 -40
  44. package/lib/core/webhook/c2c.d.ts +0 -2
  45. package/lib/core/webhook/c2c.js +0 -14
  46. package/lib/core/webhook/http.d.ts +0 -2
  47. package/lib/core/webhook/http.js +0 -35
  48. package/lib/core/webhook/index.d.ts +0 -17
  49. package/lib/core/webhook/index.js +0 -87
  50. package/lib/core/webhook/ws.d.ts +0 -2
  51. package/lib/core/webhook/ws.js +0 -79
  52. package/lib/index.d.ts +0 -1
  53. package/lib/index.js +0 -5
  54. package/lib/root.d.ts +0 -5
  55. package/lib/root.js +0 -9
  56. package/lib/types/config.d.ts +0 -53
  57. package/lib/types/config.js +0 -1
  58. package/lib/utils/common.d.ts +0 -80
  59. package/lib/utils/common.js +0 -198
  60. package/lib/utils/config.d.ts +0 -9
  61. package/lib/utils/config.js +0 -54
  62. package/lib/utils/dir.d.ts +0 -1
  63. package/lib/utils/dir.js +0 -1
  64. package/lib/utils/index.d.ts +0 -4
  65. package/lib/utils/index.js +0 -4
@@ -0,0 +1,249 @@
1
+ import { d as sleep, f as log, i as getDefaultConfig, n as config, o as writeConfig } from "./config-H7LrvlNU.js";
2
+ import qrcode from "qrcode";
3
+ import axios from "node-karin/axios";
4
+ import crypto from "node:crypto";
5
+
6
+ //#region src/core/onboard/crypto.ts
7
+ /**
8
+ * 生成 256-bit 随机 AES 密钥(base64)
9
+ */
10
+ const generateBindKey = () => crypto.randomBytes(32).toString("base64");
11
+ /**
12
+ * 解密 bot_encrypt_secret(AES-256-GCM)
13
+ *
14
+ * 密文布局:IV (12 bytes) || ciphertext (N bytes) || AuthTag (16 bytes)
15
+ */
16
+ const decryptSecret = (encryptedBase64, keyBase64) => {
17
+ const key = Buffer.from(keyBase64, "base64");
18
+ if (key.length !== 32) throw new Error(`AES key length must be 32 bytes, got ${key.length}`);
19
+ const raw = Buffer.from(encryptedBase64, "base64");
20
+ const iv = raw.subarray(0, 12);
21
+ const ciphertext = raw.subarray(12, raw.length - 16);
22
+ const authTag = raw.subarray(raw.length - 16);
23
+ const decipher = crypto.createDecipheriv("aes-256-gcm", key, iv);
24
+ decipher.setAuthTag(authTag);
25
+ let plaintext = decipher.update(ciphertext, void 0, "utf8");
26
+ plaintext += decipher.final("utf8");
27
+ return plaintext;
28
+ };
29
+
30
+ //#endregion
31
+ //#region src/core/onboard/portal.ts
32
+ /** QQ 开放平台扫码绑定服务域名 */
33
+ const PORTAL_HOST = "q.qq.com";
34
+ const CREATE_PATH = "/lite/create_bind_task";
35
+ const POLL_PATH = "/lite/poll_bind_result";
36
+ /** 扫码页面模板 */
37
+ const CONNECT_URL = "https://q.qq.com/qqbot/openclaw/connect.html?task_id={task_id}&_wv=2&source=karin";
38
+ const headers = {
39
+ "Content-Type": "application/json",
40
+ Accept: "application/json"
41
+ };
42
+ /** 绑定状态 */
43
+ const BindStatus = {
44
+ NONE: 0,
45
+ PENDING: 1,
46
+ COMPLETED: 2,
47
+ EXPIRED: 3
48
+ };
49
+ /**
50
+ * 创建绑定任务
51
+ * @returns task_id 与本地生成的 AES key
52
+ */
53
+ const createBindTask = async () => {
54
+ const key = generateBindKey();
55
+ const { data } = await axios.post(`https://${PORTAL_HOST}${CREATE_PATH}`, { key }, { headers });
56
+ if (data.retcode !== 0) throw new Error(`create_bind_task: ${data.msg || "unknown error"}`);
57
+ const taskId = data.data?.task_id;
58
+ if (!taskId) throw new Error("create_bind_task: missing task_id");
59
+ return {
60
+ taskId,
61
+ aesKey: key
62
+ };
63
+ };
64
+ /**
65
+ * 轮询绑定结果
66
+ */
67
+ const pollBindResult = async (taskId) => {
68
+ const { data } = await axios.post(`https://${PORTAL_HOST}${POLL_PATH}`, { task_id: taskId }, { headers });
69
+ if (data.retcode !== 0) throw new Error(`poll_bind_result: ${data.msg || "unknown error"}`);
70
+ const d = data.data ?? {};
71
+ return {
72
+ status: d.status ?? BindStatus.NONE,
73
+ appId: String(d.bot_appid ?? ""),
74
+ encryptedSecret: d.bot_encrypt_secret ?? "",
75
+ userOpenid: d.user_openid ?? ""
76
+ };
77
+ };
78
+ /**
79
+ * 构造扫码 URL
80
+ */
81
+ const buildConnectUrl = (taskId) => CONNECT_URL.replace("{task_id}", encodeURIComponent(taskId));
82
+ /**
83
+ * 通过 appId + secret 直接调一次 @me,拿到 bot 昵称
84
+ * 用于扫码完成后的展示与写入配置
85
+ */
86
+ const fetchBotName = async (appId, secret) => {
87
+ try {
88
+ const accessToken = (await axios.post("https://bots.qq.com/app/getAppAccessToken", {
89
+ appId,
90
+ clientSecret: secret
91
+ })).data?.access_token;
92
+ if (!accessToken) return "";
93
+ return (await axios.get("https://api.sgroup.qq.com/users/@me", { headers: { Authorization: `QQBot ${accessToken}` } })).data?.username || "";
94
+ } catch {
95
+ return "";
96
+ }
97
+ };
98
+
99
+ //#endregion
100
+ //#region src/core/onboard/qr.ts
101
+ /** 默认轮询间隔(毫秒) */
102
+ const POLL_INTERVAL = 2e3;
103
+ /** 默认总超时(秒) */
104
+ const DEFAULT_TIMEOUT_S = 600;
105
+ /** 单张二维码硬编码有效期:60s,到时主动判定过期触发刷新 */
106
+ const QR_TTL_MS = 6e4;
107
+ /** 二维码过期最大刷新次数 */
108
+ const MAX_REFRESHES = 3;
109
+ /**
110
+ * 生成二维码(同时拿到 ascii / base64)
111
+ */
112
+ const renderQr = async (url) => {
113
+ return {
114
+ ascii: await qrcode.toString(url, {
115
+ type: "terminal",
116
+ small: true
117
+ }).catch(() => ""),
118
+ base64: `base64://${(await qrcode.toDataURL(url, {
119
+ width: 320,
120
+ margin: 2
121
+ })).split(",")[1]}`
122
+ };
123
+ };
124
+ /**
125
+ * 扫码登录主流程:
126
+ * 1. 创建绑定任务,调用 onQr 暴露二维码
127
+ * 2. 轮询直到 COMPLETED / 二维码过期刷新 / 超时
128
+ * 3. 解密返回 secret
129
+ */
130
+ const qrRegister = async (opts = {}) => {
131
+ const { timeoutSeconds = DEFAULT_TIMEOUT_S, onQr } = opts;
132
+ const deadline = Date.now() + timeoutSeconds * 1e3;
133
+ for (let refresh = 0; refresh <= MAX_REFRESHES; refresh++) {
134
+ let task;
135
+ try {
136
+ task = await createBindTask();
137
+ } catch (err) {
138
+ log("error", "[扫码登录] 创建绑定任务失败:", err);
139
+ return null;
140
+ }
141
+ const url = buildConnectUrl(task.taskId);
142
+ const { ascii, base64 } = await renderQr(url);
143
+ const qrDeadline = Date.now() + QR_TTL_MS;
144
+ if (ascii) {
145
+ console.log();
146
+ console.log(ascii);
147
+ }
148
+ console.log(` 请使用 QQ 扫码(60s 内有效),或在手机 QQ 打开:\n ${url}\n`);
149
+ if (onQr) try {
150
+ await onQr({
151
+ url,
152
+ ascii,
153
+ base64,
154
+ refresh
155
+ });
156
+ } catch (err) {
157
+ log("warn", "[扫码登录] onQr 回调异常:", err);
158
+ }
159
+ let expired = false;
160
+ while (Date.now() < deadline) {
161
+ if (Date.now() >= qrDeadline) {
162
+ expired = true;
163
+ break;
164
+ }
165
+ let result;
166
+ try {
167
+ result = await pollBindResult(task.taskId);
168
+ } catch {
169
+ await sleep(POLL_INTERVAL);
170
+ continue;
171
+ }
172
+ if (result.status === BindStatus.COMPLETED) {
173
+ if (!result.encryptedSecret) {
174
+ log("error", "[扫码登录] 绑定结果缺少加密密钥");
175
+ return null;
176
+ }
177
+ let secret;
178
+ try {
179
+ secret = decryptSecret(result.encryptedSecret, task.aesKey);
180
+ } catch (err) {
181
+ log("error", "[扫码登录] 解密 secret 失败:", err);
182
+ return null;
183
+ }
184
+ log("info", `[扫码登录] 授权成功,App ID: ${result.appId}`);
185
+ return {
186
+ appId: result.appId,
187
+ secret,
188
+ userOpenid: result.userOpenid
189
+ };
190
+ }
191
+ if (result.status === BindStatus.EXPIRED) {
192
+ expired = true;
193
+ break;
194
+ }
195
+ await sleep(POLL_INTERVAL);
196
+ }
197
+ if (expired) {
198
+ if (refresh >= MAX_REFRESHES) {
199
+ log("error", `[扫码登录] 二维码已过期 ${MAX_REFRESHES + 1} 次,终止流程`);
200
+ return null;
201
+ }
202
+ log("info", `[扫码登录] 二维码 60s 内未完成扫码,正在刷新 (${refresh + 1}/${MAX_REFRESHES})`);
203
+ continue;
204
+ }
205
+ log("error", `[扫码登录] 等待扫码总超时(${timeoutSeconds}s)`);
206
+ return null;
207
+ }
208
+ return null;
209
+ };
210
+
211
+ //#endregion
212
+ //#region src/core/onboard/index.ts
213
+ /** 是否需要触发扫码引导:完全没有 bot 配置时为 true */
214
+ const needQrOnboard = () => config().length === 0;
215
+ /**
216
+ * 执行扫码登录并把结果写入 config.json
217
+ *
218
+ * - 同 appId 已存在 → 覆盖 secret / name
219
+ * - 不存在 → 追加新配置
220
+ *
221
+ * 支持 `opts.onQr` 把新二维码透出给调用方(如 #QQ登录 指令把图片回给用户)
222
+ */
223
+ const runQrOnboard = async (opts = {}) => {
224
+ const result = await qrRegister(opts);
225
+ if (!result) return false;
226
+ const name = await fetchBotName(result.appId, result.secret);
227
+ if (name) log("info", `[扫码登录] Bot 名称: ${name}`);
228
+ const list = config();
229
+ const idx = list.findIndex((item) => item.appId === result.appId);
230
+ if (idx >= 0) {
231
+ list[idx].secret = result.secret;
232
+ if (name) list[idx].name = name;
233
+ log("info", `[扫码登录] 已更新已有配置: ${result.appId}`);
234
+ } else {
235
+ const defaults = getDefaultConfig()[0];
236
+ list.push({
237
+ ...defaults,
238
+ name: name || "",
239
+ appId: result.appId,
240
+ secret: result.secret
241
+ });
242
+ log("info", `[扫码登录] 已添加新配置: ${result.appId}`);
243
+ }
244
+ writeConfig(list);
245
+ return true;
246
+ };
247
+
248
+ //#endregion
249
+ export { runQrOnboard as n, needQrOnboard as t };
@@ -0,0 +1,3 @@
1
+ import "./config-H7LrvlNU.js";
2
+
3
+ export { };
@@ -0,0 +1,22 @@
1
+ import * as _$node_karin0 from "node-karin";
2
+
3
+ //#region src/web.config.d.ts
4
+ declare const _default: _$node_karin0.DefineConfig<{
5
+ qqbot: Array<{
6
+ name: string;
7
+ appId: string;
8
+ secret: string;
9
+ prodApi: string;
10
+ sandboxApi: string;
11
+ tokenApi: string;
12
+ sandbox: boolean;
13
+ qqEnable: boolean;
14
+ guildEnable: boolean;
15
+ guildMode: boolean;
16
+ regex: string[];
17
+ "keyboard:enable": boolean;
18
+ "event:type": string;
19
+ }>;
20
+ }>;
21
+ //#endregion
22
+ export { _default as default };
@@ -0,0 +1,173 @@
1
+ import { a as pkg, n as config, o as writeConfig } from "./config-H7LrvlNU.js";
2
+ import "./utils-DO4gEkVN.js";
3
+ import { components, defineConfig } from "node-karin";
4
+
5
+ //#region src/web.config.ts
6
+ var web_config_default = defineConfig({
7
+ info: {
8
+ id: pkg().name,
9
+ name: "QQBot 适配器",
10
+ version: pkg().version,
11
+ description: "为 karin 提供 QQ 官方 Bot 连接能力(2.0)",
12
+ author: [{
13
+ name: "shijin",
14
+ avatar: "https://github.com/sj817.png"
15
+ }]
16
+ },
17
+ components: () => {
18
+ const data = [];
19
+ config().forEach((item) => {
20
+ data.push({
21
+ title: item.name || item.appId,
22
+ subtitle: item.appId,
23
+ name: item.name,
24
+ appId: item.appId,
25
+ secret: item.secret,
26
+ prodApi: item.prodApi,
27
+ sandboxApi: item.sandboxApi,
28
+ tokenApi: item.tokenApi,
29
+ sandbox: item.sandbox,
30
+ qqEnable: item.qqEnable,
31
+ guildEnable: item.guildEnable,
32
+ guildMode: item.guildMode === 1,
33
+ regex: item.regex.map((r) => `${r.reg} ${r.rep}`),
34
+ "keyboard:enable": item.keyboard?.enable !== false,
35
+ "event:type": String(item.event?.type ?? 2)
36
+ });
37
+ });
38
+ return [components.accordionPro.create("qqbot", data, {
39
+ label: "QQBot",
40
+ description: "QQBot 配置",
41
+ children: {
42
+ key: "qqbotConfig",
43
+ children: [
44
+ components.input.create("name", {
45
+ label: "机器人名称",
46
+ description: "机器人名称,扫码登录会自动获取"
47
+ }),
48
+ components.input.create("appId", {
49
+ label: "AppID",
50
+ description: "机器人 AppID",
51
+ isRequired: true
52
+ }),
53
+ components.input.create("secret", {
54
+ label: "Secret",
55
+ description: "机器人 Secret",
56
+ isRequired: true
57
+ }),
58
+ components.input.create("prodApi", {
59
+ label: "正式环境 API",
60
+ defaultValue: "https://api.sgroup.qq.com",
61
+ isRequired: true
62
+ }),
63
+ components.input.create("sandboxApi", {
64
+ label: "沙盒环境 API",
65
+ defaultValue: "https://sandbox.api.sgroup.qq.com",
66
+ isRequired: true
67
+ }),
68
+ components.input.create("tokenApi", {
69
+ label: "AccessToken 接口",
70
+ defaultValue: "https://bots.qq.com/app/getAppAccessToken",
71
+ isRequired: true
72
+ }),
73
+ components.switch.create("sandbox", {
74
+ label: "沙盒环境",
75
+ description: "启用后调用沙盒 API",
76
+ defaultSelected: false
77
+ }),
78
+ components.switch.create("qqEnable", {
79
+ label: "QQ 场景",
80
+ description: "是否处理私聊和群聊消息",
81
+ defaultSelected: true
82
+ }),
83
+ components.switch.create("guildEnable", {
84
+ label: "频道场景",
85
+ description: "是否处理频道消息",
86
+ defaultSelected: true
87
+ }),
88
+ components.switch.create("guildMode", {
89
+ label: "频道私域模式",
90
+ description: "开启 = 私域机器人;关闭 = 公域机器人",
91
+ defaultSelected: false
92
+ }),
93
+ components.input.group("regex", {
94
+ data: [],
95
+ label: "消息正则替换",
96
+ description: "每行格式:正则表达式 替换内容。如:^/ #",
97
+ template: components.input.create("regex", {
98
+ label: "正则规则",
99
+ placeholder: "^/ #"
100
+ })
101
+ }),
102
+ components.switch.create("keyboard:enable", {
103
+ label: "URL 自动按钮",
104
+ description: "将文本中的链接自动转为 keyboard 按钮",
105
+ defaultSelected: true
106
+ }),
107
+ components.radio.group("event:type", {
108
+ label: "事件接收方式",
109
+ description: "选择 QQ 官方推送事件的方式",
110
+ defaultValue: "2",
111
+ radio: [
112
+ components.radio.create("0", {
113
+ label: "关闭",
114
+ value: "0",
115
+ description: "不接收任何事件"
116
+ }),
117
+ components.radio.create("1", {
118
+ label: "Webhook",
119
+ value: "1",
120
+ description: "QQ 官方主动推送事件到本机"
121
+ }),
122
+ components.radio.create("2", {
123
+ label: "WebSocket",
124
+ value: "2",
125
+ description: "主动连接 QQ 官方 WebSocket 网关接收事件(推荐)"
126
+ })
127
+ ]
128
+ })
129
+ ]
130
+ }
131
+ })];
132
+ },
133
+ save: (input) => {
134
+ if (!Array.isArray(input.qqbot)) return {
135
+ success: false,
136
+ message: "保存失败:配置格式错误"
137
+ };
138
+ const data = input.qqbot.map((item) => {
139
+ const guildMode = item.guildMode === true ? 1 : 0;
140
+ const eventType = Number(item["event:type"] ?? 0);
141
+ const regex = (item.regex || []).map((str) => {
142
+ const parts = str.split(" ");
143
+ return {
144
+ reg: parts[0]?.replace(/^<|>$/g, "") || "",
145
+ rep: parts[1]?.replace(/^<|>$/g, "") || ""
146
+ };
147
+ });
148
+ return {
149
+ name: item.name || "",
150
+ appId: item.appId || "",
151
+ secret: item.secret || "",
152
+ prodApi: item.prodApi || "https://api.sgroup.qq.com",
153
+ sandboxApi: item.sandboxApi || "https://sandbox.api.sgroup.qq.com",
154
+ tokenApi: item.tokenApi || "https://bots.qq.com/app/getAppAccessToken",
155
+ sandbox: !!item.sandbox,
156
+ qqEnable: !!item.qqEnable,
157
+ guildEnable: !!item.guildEnable,
158
+ guildMode,
159
+ regex,
160
+ keyboard: { enable: item["keyboard:enable"] !== false },
161
+ event: { type: eventType }
162
+ };
163
+ });
164
+ writeConfig(data);
165
+ return {
166
+ success: true,
167
+ message: "保存成功"
168
+ };
169
+ }
170
+ });
171
+
172
+ //#endregion
173
+ export { web_config_default as default };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@karinjs/adapter-qqbot",
3
- "version": "1.2.10",
4
- "description": "karin plugin adapter for qqbot",
3
+ "version": "2.0.0",
4
+ "description": "karin adapter for QQ Official Bot (2.0)",
5
5
  "homepage": "https://github.com/KarinJS/karin-plugin-adapter-qqbot",
6
6
  "bugs": {
7
7
  "url": "https://github.com/KarinJS/karin-plugin-adapter-qqbot/issues"
@@ -12,41 +12,52 @@
12
12
  },
13
13
  "author": "shijin",
14
14
  "type": "module",
15
- "main": "lib/index.js",
15
+ "main": "dist/index.js",
16
+ "types": "dist/index.d.ts",
16
17
  "files": [
17
- "/lib/**/*.js",
18
- "/lib/**/*.d.ts",
19
- "config",
20
- "resources",
21
- "LICENSE",
22
- "package.json",
23
- "README.md"
18
+ "dist"
24
19
  ],
25
20
  "scripts": {
26
- "build": "tsc && tsup",
27
- "pr": "node lib/cli/pr.js",
21
+ "build": "tsc && tsdown",
22
+ "dev": "tsx watch --include \"src/**/*.ts\" src/app.ts",
23
+ "karin": "karin",
24
+ "lint": "eslint src",
25
+ "lint:fix": "eslint src --fix",
28
26
  "pub": "npm publish --access public",
29
- "pub-beta": "npm publish --tag beta",
30
- "sort": "npx sort-package-json",
31
- "dev": "tsx src/index.ts",
32
- "karin": "karin"
27
+ "sort": "npx sort-package-json"
33
28
  },
34
29
  "dependencies": {
35
30
  "@karinjs/geturls": "^1.0.2",
36
- "form-data": "^4.0.2",
37
- "image-size": "^1.2.0",
31
+ "form-data": "^4.0.5",
32
+ "image-size": "^2.0.2",
38
33
  "qrcode": "^1.5.4",
39
- "silk-wasm": "^3.6.3",
34
+ "silk-wasm": "^3.7.1",
40
35
  "tweetnacl": "^1.0.3"
41
36
  },
37
+ "devDependencies": {
38
+ "@types/express": "5.0.6",
39
+ "@types/node": "^24.12.4",
40
+ "@types/qrcode": "^1.5.6",
41
+ "eslint": "^9.39.4",
42
+ "neostandard": "^0.13.0",
43
+ "node-karin": "^1.15.5",
44
+ "tsdown": "^0.22.0",
45
+ "tsx": "^4.22.0",
46
+ "typescript": "^6.0.3"
47
+ },
42
48
  "publishConfig": {
43
49
  "access": "public",
44
50
  "registry": "https://registry.npmjs.org"
45
51
  },
52
+ "pnpm": {
53
+ "overrides": {
54
+ "yaml@>=2.0.0 <2.8.3": "^2.8.3"
55
+ }
56
+ },
46
57
  "karin": {
47
58
  "main": "src/index.ts",
48
59
  "apps": [
49
- "lib/apps"
60
+ "dist/apps"
50
61
  ],
51
62
  "ts-apps": [
52
63
  "src/apps"
@@ -58,6 +69,8 @@
58
69
  "config",
59
70
  "data",
60
71
  "resources"
61
- ]
72
+ ],
73
+ "ts-web": "src/web.config.ts",
74
+ "web": "dist/web.config.js"
62
75
  }
63
76
  }
@@ -1,3 +0,0 @@
1
- {
2
- "screenshotUrl": "网页截图测试地址"
3
- }
@@ -1,53 +0,0 @@
1
- # 全局默认配置 以下所有配置均可在账号配置中单独配置
2
- default:
3
- # 机器人ID
4
- appId: string
5
- # 机器人密钥
6
- secret: string
7
- # 正式环境api
8
- prodApi: https://api.sgroup.qq.com
9
- # 沙盒api
10
- sandboxApi: https://sandbox.api.sgroup.qq.com
11
- # 调用凭证的Api
12
- tokenApi: https://bots.qq.com/app/getAppAccessToken
13
- # 是否开启沙盒环境
14
- sandbox: false
15
- # 开启QQ场景能力
16
- qqEnable: true
17
- # 开启频道场景能力
18
- guildEnable: true
19
- # 频道场景模式 0-公域 1-私域
20
- guildMode: 0
21
- # 文本中的url转二维码白名单 配置后将不转换这些url为二维码
22
- exclude: []
23
- # 接受到消息后对文本进行表达式处理
24
- regex: [
25
- {
26
- # 表达式
27
- reg: "^#",
28
- # 替换为
29
- rep: "",
30
- },
31
- ]
32
- # markdown配置
33
- markdown:
34
- # 发送模式 0-关闭MD 1-原生MD 3-旧图文模板MD 4-纯文模板MD 5-自定义处理
35
- mode: 0
36
- # 模板ID
37
- id: ""
38
- kv:
39
- - text_start
40
- - img_dec
41
- - img_url
42
- - text_end
43
-
44
- # 事件接收配置
45
- event:
46
- # 接收方式 0-关闭 1-webhook 2-http 3-ws
47
- type: 0
48
- # ws服务器地址
49
- wsUrl: ws://example.com/webhook
50
- # ws服务器token
51
- wsToken: your_token
52
- # http鉴权token
53
- httpToken: your_token
package/lib/cli/pr.d.ts DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
package/lib/cli/pr.js DELETED
@@ -1,73 +0,0 @@
1
- #!/usr/bin/env node
2
- import fs from 'fs';
3
- /**
4
- * @description 获取package.json路径
5
- */
6
- const getPkgPath = () => process.cwd() + '/package.json';
7
- /**
8
- * @description 读取package.json
9
- */
10
- const readPkg = () => JSON.parse(fs.readFileSync(getPkgPath(), 'utf-8'));
11
- /**
12
- * @description 写入package.json
13
- * @param pkg package.json
14
- */
15
- const writePkg = (pkg) => fs.writeFileSync(getPkgPath(), JSON.stringify(pkg, null, 2));
16
- /**
17
- * @description 构建pr版本号 <主版本号>.<次版本号>.<修订号>-<预发布标识>.<PR标识>.<PR编号>.<工作流唯一编号>-<时间戳>
18
-
19
- * @param pkg package.json
20
- */
21
- const updateVersion = (pkg) => {
22
- const list = pkg.version.split('.');
23
- // 1.0.0 => 1.0.1-beta.pr.pr编号.工作流唯一编号-时间戳 => 1.0.1-beta.pr.184-1631537630
24
- const timestamp = Math.floor(Date.now() / 1000);
25
- list[2] = `${Number(list[2]) + 1}-beta.pr.${process.env.PR_NUMBER}.${process.env.GITHUB_RUN_ATTEMPT || 1}-${timestamp}`;
26
- pkg.version = list.join('.');
27
- };
28
- /**
29
- * @description 设置环境变量
30
- * @param pkg package.json
31
- */
32
- const setEnvVariables = (pkg) => {
33
- fs.appendFileSync(process.env.GITHUB_ENV, `PKG_NAME=${pkg.name}\nPKG_VERSION=${pkg.version}\n`);
34
- };
35
- /**
36
- * @description 更新版本号并设置环境变量
37
- */
38
- const version = () => {
39
- const pkg = readPkg();
40
- updateVersion(pkg);
41
- writePkg(pkg);
42
- setEnvVariables(pkg);
43
- };
44
- /**
45
- * @description 删除devDependencies和peerDependencies
46
- */
47
- const clean = () => {
48
- const pkg = readPkg();
49
- delete pkg.devDependencies;
50
- delete pkg.peerDependencies;
51
- writePkg(pkg);
52
- };
53
- /**
54
- * @description 执行所有操作
55
- */
56
- const all = () => {
57
- const pkg = readPkg();
58
- updateVersion(pkg);
59
- delete pkg.devDependencies;
60
- delete pkg.peerDependencies;
61
- writePkg(pkg);
62
- setEnvVariables(pkg);
63
- };
64
- const cmd = process.argv[2];
65
- if (cmd === 'version') {
66
- version();
67
- }
68
- else if (cmd === 'clean') {
69
- clean();
70
- }
71
- else if (cmd === 'all') {
72
- all();
73
- }