@karinjs/adapter-qqbot 2.1.0 → 2.2.1
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.
- package/README.md +10 -0
- package/dist/apps/cleanup.js +2 -2
- package/dist/apps/login.js +2 -2
- package/dist/config-B_Gc9JKZ.js +253 -0
- package/dist/index.d.ts +21 -6
- package/dist/index.js +223 -36
- package/dist/{message-O73AeL_P.js → message-Dt4QkDYn.js} +1 -1
- package/dist/{onboard-DPWgX39H.js → onboard-BXQ1cG8h.js} +1 -1
- package/dist/utils-DIq0lGMt.js +4 -0
- package/dist/web.config.d.ts +21 -19
- package/dist/web.config.js +224 -96
- package/package.json +3 -3
- package/dist/config-DKa7596f.js +0 -170
- package/dist/utils-BPbnNAix.js +0 -4
package/dist/web.config.js
CHANGED
|
@@ -1,8 +1,92 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
import "./utils-
|
|
1
|
+
import { a as readConfigFile, f as pkg, i as getDefaultConfig, n as config, o as writeConfig, s as buildFallbackWsUrlFromApi, u as normalizeProxyConfig } from "./config-B_Gc9JKZ.js";
|
|
2
|
+
import "./utils-DIq0lGMt.js";
|
|
3
3
|
import { components, defineConfig } from "node-karin";
|
|
4
4
|
|
|
5
5
|
//#region src/web.config.ts
|
|
6
|
+
const defaultProxy = () => getDefaultConfig()[0].proxy;
|
|
7
|
+
const unwrapValue = (value) => {
|
|
8
|
+
if (value && typeof value === "object" && "value" in value) return value.value;
|
|
9
|
+
return value;
|
|
10
|
+
};
|
|
11
|
+
const toBool = (value, fallback) => {
|
|
12
|
+
const raw = unwrapValue(value);
|
|
13
|
+
if (typeof raw === "boolean") return raw;
|
|
14
|
+
if (typeof raw === "number") return raw !== 0;
|
|
15
|
+
if (typeof raw === "string") {
|
|
16
|
+
const normalized = raw.trim().toLowerCase();
|
|
17
|
+
if ([
|
|
18
|
+
"false",
|
|
19
|
+
"0",
|
|
20
|
+
"off",
|
|
21
|
+
"no",
|
|
22
|
+
""
|
|
23
|
+
].includes(normalized)) return false;
|
|
24
|
+
if ([
|
|
25
|
+
"true",
|
|
26
|
+
"1",
|
|
27
|
+
"on",
|
|
28
|
+
"yes"
|
|
29
|
+
].includes(normalized)) return true;
|
|
30
|
+
}
|
|
31
|
+
if (raw === null || raw === void 0) return fallback;
|
|
32
|
+
return fallback;
|
|
33
|
+
};
|
|
34
|
+
const toStringValue = (value, fallback = "") => {
|
|
35
|
+
const raw = unwrapValue(value);
|
|
36
|
+
if (typeof raw === "string") return raw;
|
|
37
|
+
if (raw === null || raw === void 0) return fallback;
|
|
38
|
+
return String(raw);
|
|
39
|
+
};
|
|
40
|
+
const toStringList = (value) => {
|
|
41
|
+
const raw = unwrapValue(value);
|
|
42
|
+
if (!Array.isArray(raw)) return [];
|
|
43
|
+
return raw.map((item) => toStringValue(item)).filter(Boolean);
|
|
44
|
+
};
|
|
45
|
+
const proxyKeys = (sandbox) => sandbox ? {
|
|
46
|
+
api: "sandboxApi",
|
|
47
|
+
ws: "sandboxWs"
|
|
48
|
+
} : {
|
|
49
|
+
api: "prodApi",
|
|
50
|
+
ws: "prodWs"
|
|
51
|
+
};
|
|
52
|
+
const getBotProxyInput = (item) => {
|
|
53
|
+
const keys = proxyKeys(!!item.sandbox);
|
|
54
|
+
const proxy = item.proxy || defaultProxy();
|
|
55
|
+
return {
|
|
56
|
+
"proxy:api": proxy[keys.api] || defaultProxy()[keys.api],
|
|
57
|
+
"proxy:ws": proxy[keys.ws] || defaultProxy()[keys.ws]
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
const proxyFromInput = (item, previous) => {
|
|
61
|
+
const def = defaultProxy();
|
|
62
|
+
const sandbox = toBool(item.sandbox, previous?.sandbox ?? false);
|
|
63
|
+
const previousSandbox = previous?.sandbox ?? sandbox;
|
|
64
|
+
const keys = proxyKeys(sandbox);
|
|
65
|
+
const previousVisibleKeys = proxyKeys(previousSandbox);
|
|
66
|
+
const previousProxy = previous?.proxy;
|
|
67
|
+
const base = {
|
|
68
|
+
...def,
|
|
69
|
+
...previousProxy
|
|
70
|
+
};
|
|
71
|
+
const envChanged = !!previous && previousSandbox !== sandbox;
|
|
72
|
+
const rawApi = toStringValue(item["proxy:api"]).trim();
|
|
73
|
+
const rawWs = toStringValue(item["proxy:ws"]).trim();
|
|
74
|
+
const previousVisibleApi = previousProxy?.[previousVisibleKeys.api] || def[previousVisibleKeys.api];
|
|
75
|
+
const previousVisibleWs = previousProxy?.[previousVisibleKeys.ws] || def[previousVisibleKeys.ws];
|
|
76
|
+
const api = envChanged && rawApi === previousVisibleApi ? base[keys.api] || def[keys.api] : rawApi || base[keys.api] || def[keys.api];
|
|
77
|
+
const previousApi = previousProxy?.[keys.api] || def[keys.api];
|
|
78
|
+
const previousWs = previousProxy?.[keys.ws] || def[keys.ws];
|
|
79
|
+
const wsInput = envChanged && rawWs === previousVisibleWs ? base[keys.ws] || def[keys.ws] : rawWs;
|
|
80
|
+
let ws = wsInput || previousWs || def[keys.ws];
|
|
81
|
+
const previousAutoWs = buildFallbackWsUrlFromApi(previousApi);
|
|
82
|
+
if (!wsInput || wsInput === previousWs && previousWs === previousAutoWs && api !== previousApi) ws = buildFallbackWsUrlFromApi(api);
|
|
83
|
+
return normalizeProxyConfig({
|
|
84
|
+
...base,
|
|
85
|
+
[keys.api]: api,
|
|
86
|
+
tokenApi: base.tokenApi || def.tokenApi,
|
|
87
|
+
[keys.ws]: ws
|
|
88
|
+
});
|
|
89
|
+
};
|
|
6
90
|
var web_config_default = defineConfig({
|
|
7
91
|
info: {
|
|
8
92
|
id: pkg().name,
|
|
@@ -23,120 +107,140 @@ var web_config_default = defineConfig({
|
|
|
23
107
|
name: item.name,
|
|
24
108
|
appId: item.appId,
|
|
25
109
|
secret: item.secret,
|
|
26
|
-
|
|
27
|
-
sandboxApi: item.sandboxApi,
|
|
28
|
-
tokenApi: item.tokenApi,
|
|
110
|
+
"event:type": String(item.event?.type ?? 2),
|
|
29
111
|
sandbox: item.sandbox,
|
|
30
112
|
qqEnable: item.qqEnable,
|
|
31
113
|
guildEnable: item.guildEnable,
|
|
32
114
|
guildMode: item.guildMode === 1,
|
|
33
115
|
regex: item.regex.map((r) => `${r.reg} ${r.rep}`),
|
|
34
116
|
"keyboard:enable": item.keyboard?.enable !== false,
|
|
117
|
+
"markdown:enable": item.markdown?.enable !== false,
|
|
35
118
|
"messageCache:enable": item.messageCache?.enable === true,
|
|
36
119
|
"messageCache:self": item.messageCache?.self === true,
|
|
37
|
-
|
|
120
|
+
...getBotProxyInput(item)
|
|
38
121
|
});
|
|
39
122
|
});
|
|
40
|
-
return [components.
|
|
41
|
-
|
|
42
|
-
|
|
123
|
+
return [components.divider.horizontal("bot-section", {
|
|
124
|
+
description: "机器人账号",
|
|
125
|
+
descPosition: 5
|
|
126
|
+
}), components.accordionPro.create("qqbot", data, {
|
|
127
|
+
label: "QQ 官方机器人列表",
|
|
128
|
+
description: "每一项对应一个 QQ 官方机器人账号。新增机器人时先填 AppID 和 Secret,再按需调整接收方式、场景能力和发送能力。",
|
|
43
129
|
children: {
|
|
44
130
|
key: "qqbotConfig",
|
|
45
131
|
children: [
|
|
132
|
+
components.radio.group("event:type", {
|
|
133
|
+
label: "事件接收方式",
|
|
134
|
+
description: "QQ 官方机器人只有 Webhook 推送和 WebSocket 主动连接两种接收方式。不确定时选择 WebSocket;如果 QQ 后台已启用 Webhook,可在下方高级设置填写第三方 Webhook 转 WebSocket 服务地址。",
|
|
135
|
+
defaultValue: "2",
|
|
136
|
+
radio: [
|
|
137
|
+
components.radio.create("0", {
|
|
138
|
+
label: "关闭接收",
|
|
139
|
+
value: "0",
|
|
140
|
+
description: "停用这个机器人,不连接 WebSocket,也不接收 Webhook 事件。"
|
|
141
|
+
}),
|
|
142
|
+
components.radio.create("1", {
|
|
143
|
+
label: "Webhook 推送",
|
|
144
|
+
value: "1",
|
|
145
|
+
description: "由 QQ 官方把事件推送到 Karin 的 /qqbot/webhook 路由。通常需要公网地址,并在 QQ 后台配置回调地址。"
|
|
146
|
+
}),
|
|
147
|
+
components.radio.create("2", {
|
|
148
|
+
label: "WebSocket 主动连接",
|
|
149
|
+
value: "2",
|
|
150
|
+
description: "适配器主动连接 WebSocket 地址接收事件。默认连接 QQ 官方网关;如果 QQ 后台已开 Webhook,可改为第三方 Webhook 转 WebSocket 服务地址。"
|
|
151
|
+
})
|
|
152
|
+
]
|
|
153
|
+
}),
|
|
154
|
+
components.divider.horizontal("bot-basic-section", {
|
|
155
|
+
description: "基础信息",
|
|
156
|
+
descPosition: 5
|
|
157
|
+
}),
|
|
46
158
|
components.input.create("name", {
|
|
47
|
-
label: "
|
|
48
|
-
description: "
|
|
159
|
+
label: "机器人显示名称",
|
|
160
|
+
description: "只用于 Karin 配置页和日志里识别这个机器人,不影响 QQ 平台资料。扫码登录写入配置时通常会自动填充。"
|
|
49
161
|
}),
|
|
50
162
|
components.input.create("appId", {
|
|
51
|
-
label: "AppID",
|
|
52
|
-
description: "
|
|
163
|
+
label: "机器人 AppID",
|
|
164
|
+
description: "QQ 开放平台机器人应用的 AppID,是识别机器人账号的唯一编号。填错会导致鉴权和收发消息失败。",
|
|
53
165
|
isRequired: true
|
|
54
166
|
}),
|
|
55
167
|
components.input.create("secret", {
|
|
56
|
-
label: "Secret",
|
|
57
|
-
description: "
|
|
58
|
-
isRequired: true
|
|
59
|
-
}),
|
|
60
|
-
components.input.create("prodApi", {
|
|
61
|
-
label: "正式环境 API",
|
|
62
|
-
defaultValue: "https://api.sgroup.qq.com",
|
|
63
|
-
isRequired: true
|
|
64
|
-
}),
|
|
65
|
-
components.input.create("sandboxApi", {
|
|
66
|
-
label: "沙盒环境 API",
|
|
67
|
-
defaultValue: "https://sandbox.api.sgroup.qq.com",
|
|
168
|
+
label: "机器人 Secret",
|
|
169
|
+
description: "QQ 开放平台机器人应用的 Secret,用于获取 access token。请不要泄露;扫码授权会刷新 Secret,旧 Secret 会立即失效。",
|
|
68
170
|
isRequired: true
|
|
69
171
|
}),
|
|
70
|
-
components.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
isRequired: true
|
|
172
|
+
components.divider.horizontal("bot-scene-section", {
|
|
173
|
+
description: "场景能力",
|
|
174
|
+
descPosition: 5
|
|
74
175
|
}),
|
|
75
176
|
components.switch.create("sandbox", {
|
|
76
|
-
label: "
|
|
77
|
-
description: "
|
|
177
|
+
label: "使用沙盒环境",
|
|
178
|
+
description: "开启后这个机器人会使用沙盒环境的 OpenAPI 和 WebSocket 地址;关闭时使用正式环境地址。正式上线机器人请关闭。",
|
|
78
179
|
defaultSelected: false
|
|
79
180
|
}),
|
|
80
181
|
components.switch.create("qqEnable", {
|
|
81
|
-
label: "QQ
|
|
82
|
-
description: "
|
|
182
|
+
label: "启用 QQ 私聊 / 群聊",
|
|
183
|
+
description: "开启后会处理 QQ 单聊和群聊里的消息事件;如果这个机器人只用于频道,可以关闭。",
|
|
83
184
|
defaultSelected: true
|
|
84
185
|
}),
|
|
85
186
|
components.switch.create("guildEnable", {
|
|
86
|
-
label: "
|
|
87
|
-
description: "
|
|
187
|
+
label: "启用频道消息",
|
|
188
|
+
description: "开启后会处理 QQ 频道消息事件;如果这个机器人只用于私聊或群聊,可以关闭。",
|
|
88
189
|
defaultSelected: true
|
|
89
190
|
}),
|
|
90
191
|
components.switch.create("guildMode", {
|
|
91
|
-
label: "
|
|
92
|
-
description: "
|
|
192
|
+
label: "频道私域机器人模式",
|
|
193
|
+
description: "关闭时按公域机器人处理,通常只接收 @ 机器人相关消息;开启时按私域机器人处理,可接收更多频道消息,需确认机器人权限匹配。",
|
|
93
194
|
defaultSelected: false
|
|
94
195
|
}),
|
|
196
|
+
components.divider.horizontal("bot-message-section", {
|
|
197
|
+
description: "消息发送",
|
|
198
|
+
descPosition: 5
|
|
199
|
+
}),
|
|
95
200
|
components.input.group("regex", {
|
|
96
201
|
data: [],
|
|
97
202
|
label: "消息正则替换",
|
|
98
|
-
description: "
|
|
203
|
+
description: "收到文本消息后,先按这里的规则替换内容,再交给 Karin 插件处理。每行格式是“正则表达式 替换内容”,中间用空格分隔;例如“^/ #”会把“/菜单”改成“#菜单”。不懂正则可以保留默认或清空。",
|
|
99
204
|
template: components.input.create("regex", {
|
|
100
|
-
label: "
|
|
205
|
+
label: "一条替换规则",
|
|
101
206
|
placeholder: "^/ #"
|
|
102
207
|
})
|
|
103
208
|
}),
|
|
104
209
|
components.switch.create("keyboard:enable", {
|
|
105
|
-
label: "
|
|
106
|
-
description: "
|
|
210
|
+
label: "把链接自动转成按钮",
|
|
211
|
+
description: "开启后,发送文本里出现的 http(s) 链接会尽量转成 QQ keyboard 按钮,用户可以直接点按钮打开链接。该能力依赖 Markdown 通道。",
|
|
212
|
+
defaultSelected: true
|
|
213
|
+
}),
|
|
214
|
+
components.switch.create("markdown:enable", {
|
|
215
|
+
label: "启用 Markdown 发送通道",
|
|
216
|
+
description: "开启后普通文本和图片优先合并为 QQ Markdown 消息,Markdown 里的图片会以内嵌图片形式发送;关闭后普通图片会按官方富媒体单独上传发送。插件显式传入的 segment.markdown 不受此开关影响。",
|
|
107
217
|
defaultSelected: true
|
|
108
218
|
}),
|
|
219
|
+
components.divider.horizontal("bot-cache-section", {
|
|
220
|
+
description: "消息缓存",
|
|
221
|
+
descPosition: 5
|
|
222
|
+
}),
|
|
109
223
|
components.switch.create("messageCache:enable", {
|
|
110
|
-
label: "
|
|
111
|
-
description: "
|
|
224
|
+
label: "缓存收到的消息到数据库",
|
|
225
|
+
description: "开启后会把最近一天收到的消息写入本地数据库,供 bot.getMsg 等查询使用;收到的图片、语音、视频等富媒体也会保存到本地。消息量大时会明显占用磁盘空间。",
|
|
112
226
|
defaultSelected: false
|
|
113
227
|
}),
|
|
114
228
|
components.switch.create("messageCache:self", {
|
|
115
|
-
label: "
|
|
116
|
-
description: "
|
|
229
|
+
label: "同时缓存机器人自己发出的消息",
|
|
230
|
+
description: "只有开启“缓存收到的消息到数据库”后才生效。开启后,机器人发送成功的消息也会写入缓存,方便之后通过消息 ID 查询。",
|
|
117
231
|
defaultSelected: false
|
|
118
232
|
}),
|
|
119
|
-
components.
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
label: "Webhook",
|
|
131
|
-
value: "1",
|
|
132
|
-
description: "QQ 官方主动推送事件到本机"
|
|
133
|
-
}),
|
|
134
|
-
components.radio.create("2", {
|
|
135
|
-
label: "WebSocket",
|
|
136
|
-
value: "2",
|
|
137
|
-
description: "主动连接 QQ 官方 WebSocket 网关接收事件(推荐)"
|
|
138
|
-
})
|
|
139
|
-
]
|
|
233
|
+
components.divider.horizontal("bot-proxy-section", {
|
|
234
|
+
description: "连接代理(高级设置:通常只在使用 Webhook 转 WebSocket 服务时填写,除非你知道你在做什么,否则不建议更改)",
|
|
235
|
+
descPosition: 5
|
|
236
|
+
}),
|
|
237
|
+
components.input.create("proxy:ws", {
|
|
238
|
+
label: "WebSocket 接入地址",
|
|
239
|
+
description: "事件接收方式为 WebSocket 时连接的地址。常见用途是填写第三方 Webhook 转 WebSocket 服务地址,因为 QQ 后台开启 Webhook 后通常无法再直连官方 WebSocket。不填会使用当前环境的官方默认网关。"
|
|
240
|
+
}),
|
|
241
|
+
components.input.create("proxy:api", {
|
|
242
|
+
label: "OpenAPI 反代地址",
|
|
243
|
+
description: "用于发送消息、上传媒体、查询网关和获取机器人资料的 QQ OpenAPI 根地址。多数 Webhook 转 WebSocket 场景不用改这里;只有 OpenAPI 请求也需要走反代时才填写。"
|
|
140
244
|
})
|
|
141
245
|
]
|
|
142
246
|
}
|
|
@@ -147,41 +251,65 @@ var web_config_default = defineConfig({
|
|
|
147
251
|
success: false,
|
|
148
252
|
message: "保存失败:配置格式错误"
|
|
149
253
|
};
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const
|
|
254
|
+
const prevConfig = readConfigFile();
|
|
255
|
+
let data;
|
|
256
|
+
try {
|
|
257
|
+
data = input.qqbot.map((item) => {
|
|
258
|
+
const previous = prevConfig.find((cfg) => cfg.appId === toStringValue(item.appId));
|
|
259
|
+
const sandbox = toBool(item.sandbox, previous?.sandbox ?? false);
|
|
260
|
+
const qqEnable = toBool(item.qqEnable, previous?.qqEnable ?? true);
|
|
261
|
+
const guildEnable = toBool(item.guildEnable, previous?.guildEnable ?? true);
|
|
262
|
+
const guildMode = toBool(item.guildMode, previous?.guildMode === 1) ? 1 : 0;
|
|
263
|
+
const eventType = Number(toStringValue(item["event:type"], String(previous?.event?.type ?? 0)));
|
|
264
|
+
const keyboardEnable = toBool(item["keyboard:enable"], previous?.keyboard?.enable ?? true);
|
|
265
|
+
const markdownEnable = toBool(item["markdown:enable"], previous?.markdown?.enable ?? true);
|
|
266
|
+
const messageCacheEnable = toBool(item["messageCache:enable"], previous?.messageCache?.enable ?? false);
|
|
267
|
+
const messageCacheSelf = toBool(item["messageCache:self"], previous?.messageCache?.self ?? false);
|
|
268
|
+
const regex = toStringList(item.regex).map((str) => {
|
|
269
|
+
const parts = str.split(" ");
|
|
270
|
+
return {
|
|
271
|
+
reg: parts[0]?.replace(/^<|>$/g, "") || "",
|
|
272
|
+
rep: parts[1]?.replace(/^<|>$/g, "") || ""
|
|
273
|
+
};
|
|
274
|
+
});
|
|
275
|
+
const proxy = proxyFromInput(item, previous);
|
|
155
276
|
return {
|
|
156
|
-
|
|
157
|
-
|
|
277
|
+
name: toStringValue(item.name),
|
|
278
|
+
appId: toStringValue(item.appId),
|
|
279
|
+
secret: toStringValue(item.secret),
|
|
280
|
+
proxy,
|
|
281
|
+
sandbox,
|
|
282
|
+
qqEnable,
|
|
283
|
+
guildEnable,
|
|
284
|
+
guildMode,
|
|
285
|
+
regex,
|
|
286
|
+
keyboard: { enable: keyboardEnable },
|
|
287
|
+
markdown: { enable: markdownEnable },
|
|
288
|
+
messageCache: {
|
|
289
|
+
enable: messageCacheEnable,
|
|
290
|
+
self: messageCacheSelf
|
|
291
|
+
},
|
|
292
|
+
event: { type: eventType }
|
|
158
293
|
};
|
|
159
294
|
});
|
|
295
|
+
} catch (err) {
|
|
160
296
|
return {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
secret: item.secret || "",
|
|
164
|
-
prodApi: item.prodApi || "https://api.sgroup.qq.com",
|
|
165
|
-
sandboxApi: item.sandboxApi || "https://sandbox.api.sgroup.qq.com",
|
|
166
|
-
tokenApi: item.tokenApi || "https://bots.qq.com/app/getAppAccessToken",
|
|
167
|
-
sandbox: !!item.sandbox,
|
|
168
|
-
qqEnable: !!item.qqEnable,
|
|
169
|
-
guildEnable: !!item.guildEnable,
|
|
170
|
-
guildMode,
|
|
171
|
-
regex,
|
|
172
|
-
keyboard: { enable: item["keyboard:enable"] !== false },
|
|
173
|
-
messageCache: {
|
|
174
|
-
enable: !!item["messageCache:enable"],
|
|
175
|
-
self: !!item["messageCache:self"]
|
|
176
|
-
},
|
|
177
|
-
event: { type: eventType }
|
|
297
|
+
success: false,
|
|
298
|
+
message: `保存失败:代理地址格式错误:${err?.message || "unknown"}`
|
|
178
299
|
};
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
300
|
+
}
|
|
301
|
+
try {
|
|
302
|
+
writeConfig(data);
|
|
303
|
+
return {
|
|
304
|
+
success: true,
|
|
305
|
+
message: "保存成功"
|
|
306
|
+
};
|
|
307
|
+
} catch (err) {
|
|
308
|
+
return {
|
|
309
|
+
success: false,
|
|
310
|
+
message: `保存失败:${err?.message || "unknown"}`
|
|
311
|
+
};
|
|
312
|
+
}
|
|
185
313
|
}
|
|
186
314
|
});
|
|
187
315
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@karinjs/adapter-qqbot",
|
|
3
|
-
"version": "2.1
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"description": "karin adapter for QQ Official Bot (2.0)",
|
|
5
5
|
"homepage": "https://github.com/KarinJS/karin-plugin-adapter-qqbot",
|
|
6
6
|
"bugs": {
|
|
@@ -40,9 +40,9 @@
|
|
|
40
40
|
"@types/qrcode": "^1.5.6",
|
|
41
41
|
"eslint": "^9.39.4",
|
|
42
42
|
"neostandard": "^0.13.0",
|
|
43
|
-
"node-karin": "
|
|
43
|
+
"node-karin": "1.16.3",
|
|
44
44
|
"tsdown": "^0.22.3",
|
|
45
|
-
"tsx": "^4.
|
|
45
|
+
"tsx": "^4.23.0",
|
|
46
46
|
"typescript": "^6.0.3"
|
|
47
47
|
},
|
|
48
48
|
"publishConfig": {
|
package/dist/config-DKa7596f.js
DELETED
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
import { common, karinPathBase, logger, requireFileSync, watch } from "node-karin";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import { fileURLToPath } from "url";
|
|
4
|
-
import fs from "node:fs";
|
|
5
|
-
|
|
6
|
-
//#region src/root.ts
|
|
7
|
-
/** 当前文件的绝对路径 */
|
|
8
|
-
const filePath = fileURLToPath(import.meta.url);
|
|
9
|
-
/** 插件包绝对路径 */
|
|
10
|
-
const dirPath = path.resolve(filePath, "../..");
|
|
11
|
-
/** 插件包的名称 */
|
|
12
|
-
const basename = path.basename(dirPath);
|
|
13
|
-
|
|
14
|
-
//#endregion
|
|
15
|
-
//#region src/utils/logger.ts
|
|
16
|
-
const PREFIX = "[QQ Official Bot]";
|
|
17
|
-
const m = {
|
|
18
|
-
trace: (...a) => logger.trace(PREFIX, ...a),
|
|
19
|
-
debug: (...a) => logger.debug(PREFIX, ...a),
|
|
20
|
-
info: (...a) => logger.info(PREFIX, ...a),
|
|
21
|
-
warn: (...a) => logger.warn(PREFIX, ...a),
|
|
22
|
-
error: (...a) => logger.error(PREFIX, ...a),
|
|
23
|
-
fatal: (...a) => logger.fatal(PREFIX, ...a),
|
|
24
|
-
mark: (...a) => logger.mark(PREFIX, ...a)
|
|
25
|
-
};
|
|
26
|
-
/**
|
|
27
|
-
* QQBot 日志函数
|
|
28
|
-
* - log('info', '消息')
|
|
29
|
-
* - log.info('消息')
|
|
30
|
-
*
|
|
31
|
-
* 日志级别由 karin 框架的 log.level 控制
|
|
32
|
-
*/
|
|
33
|
-
function log(level, ...args) {
|
|
34
|
-
m[level](...args);
|
|
35
|
-
}
|
|
36
|
-
Object.assign(log, m);
|
|
37
|
-
|
|
38
|
-
//#endregion
|
|
39
|
-
//#region src/utils/plugin.ts
|
|
40
|
-
/**
|
|
41
|
-
* 读取当前插件的 package.json。
|
|
42
|
-
*
|
|
43
|
-
* @returns package.json 内容。
|
|
44
|
-
*/
|
|
45
|
-
const pkg = () => requireFileSync(`${dirPath}/package.json`);
|
|
46
|
-
/** 当前插件 npm 包名,如 @karinjs/adapter-qqbot。 */
|
|
47
|
-
const pluginName = pkg().name;
|
|
48
|
-
/** 文件系统目录名:把 npm 包名里的 `/` 规范化为 `-`,与 Karin 框架对齐。 */
|
|
49
|
-
const pluginDirName = pluginName.replace(/\//g, "-");
|
|
50
|
-
|
|
51
|
-
//#endregion
|
|
52
|
-
//#region src/utils/config.ts
|
|
53
|
-
let cache;
|
|
54
|
-
const cacheMap = {};
|
|
55
|
-
/** 延迟注入,避免与 core/index.ts 循环依赖 */
|
|
56
|
-
let _createBot;
|
|
57
|
-
let _destroyBot;
|
|
58
|
-
const bindHandlers = (createBot, destroyBot) => {
|
|
59
|
-
_createBot = createBot;
|
|
60
|
-
_destroyBot = destroyBot;
|
|
61
|
-
};
|
|
62
|
-
/** 配置目录:${karinPathBase}/@karinjs-adapter-qqbot/config */
|
|
63
|
-
const dirConfig = `${karinPathBase}/${pluginDirName}/config`;
|
|
64
|
-
/**
|
|
65
|
-
* 读取配置
|
|
66
|
-
*/
|
|
67
|
-
const config = () => {
|
|
68
|
-
const cfgPath = `${dirConfig}/config.json`;
|
|
69
|
-
if (!fs.existsSync(cfgPath)) {
|
|
70
|
-
fs.mkdirSync(dirConfig, { recursive: true });
|
|
71
|
-
fs.writeFileSync(cfgPath, JSON.stringify([], null, 2));
|
|
72
|
-
}
|
|
73
|
-
if (cache) return cache;
|
|
74
|
-
const result = formatConfig(requireFileSync(cfgPath));
|
|
75
|
-
cache = result;
|
|
76
|
-
result.forEach((v) => {
|
|
77
|
-
cacheMap[v.appId] = v;
|
|
78
|
-
});
|
|
79
|
-
return result;
|
|
80
|
-
};
|
|
81
|
-
/**
|
|
82
|
-
* 获取单 bot 配置
|
|
83
|
-
*/
|
|
84
|
-
const getConfig = (appid) => cacheMap[appid];
|
|
85
|
-
/**
|
|
86
|
-
* 写入配置
|
|
87
|
-
*/
|
|
88
|
-
const writeConfig = (data) => {
|
|
89
|
-
fs.mkdirSync(dirConfig, { recursive: true });
|
|
90
|
-
fs.writeFileSync(`${dirConfig}/config.json`, JSON.stringify(data, null, 2));
|
|
91
|
-
};
|
|
92
|
-
/**
|
|
93
|
-
* 用默认值补齐用户配置
|
|
94
|
-
*/
|
|
95
|
-
const formatConfig = (user) => {
|
|
96
|
-
const def = getDefaultConfig()[0];
|
|
97
|
-
return user.map((item) => ({
|
|
98
|
-
...def,
|
|
99
|
-
...item,
|
|
100
|
-
keyboard: {
|
|
101
|
-
...def.keyboard,
|
|
102
|
-
...item.keyboard
|
|
103
|
-
},
|
|
104
|
-
messageCache: {
|
|
105
|
-
...def.messageCache,
|
|
106
|
-
...item.messageCache
|
|
107
|
-
},
|
|
108
|
-
event: {
|
|
109
|
-
...def.event,
|
|
110
|
-
...item.event
|
|
111
|
-
}
|
|
112
|
-
}));
|
|
113
|
-
};
|
|
114
|
-
/**
|
|
115
|
-
* 默认配置
|
|
116
|
-
*/
|
|
117
|
-
const getDefaultConfig = () => [{
|
|
118
|
-
name: "",
|
|
119
|
-
appId: "",
|
|
120
|
-
secret: "",
|
|
121
|
-
prodApi: "https://api.sgroup.qq.com",
|
|
122
|
-
sandboxApi: "https://sandbox.api.sgroup.qq.com",
|
|
123
|
-
tokenApi: "https://bots.qq.com/app/getAppAccessToken",
|
|
124
|
-
sandbox: false,
|
|
125
|
-
qqEnable: true,
|
|
126
|
-
guildEnable: true,
|
|
127
|
-
guildMode: 0,
|
|
128
|
-
regex: [{
|
|
129
|
-
reg: "^/",
|
|
130
|
-
rep: "#"
|
|
131
|
-
}],
|
|
132
|
-
keyboard: { enable: true },
|
|
133
|
-
messageCache: {
|
|
134
|
-
enable: false,
|
|
135
|
-
self: false
|
|
136
|
-
},
|
|
137
|
-
event: { type: 2 }
|
|
138
|
-
}];
|
|
139
|
-
/**
|
|
140
|
-
* 监听配置文件,比较前后差异决定重建 / 销毁 bot
|
|
141
|
-
*/
|
|
142
|
-
setTimeout(() => {
|
|
143
|
-
watch(`${dirConfig}/config.json`, (old, now) => {
|
|
144
|
-
cache = formatConfig(now);
|
|
145
|
-
cache.forEach((v) => {
|
|
146
|
-
cacheMap[v.appId] = v;
|
|
147
|
-
});
|
|
148
|
-
const diff = common.diffArray(old, now);
|
|
149
|
-
diff.removed.forEach((v) => _destroyBot?.(v.appId));
|
|
150
|
-
if (diff.added.length > 0) {
|
|
151
|
-
const ids = new Set(diff.added.map((v) => v.appId));
|
|
152
|
-
cache.forEach((v) => {
|
|
153
|
-
if (!ids.has(v.appId)) return;
|
|
154
|
-
if (v.event.type === 0) return;
|
|
155
|
-
_createBot?.(v);
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
diff.common.forEach((curr) => {
|
|
159
|
-
const prev = old.find((c) => c.appId === curr.appId);
|
|
160
|
-
if (!prev) return;
|
|
161
|
-
if (JSON.stringify(prev) === JSON.stringify(curr)) return;
|
|
162
|
-
logger.info(`[QQ Official Bot][配置监听] 配置已变更: ${curr.appId},重新初始化`);
|
|
163
|
-
_destroyBot?.(prev.appId);
|
|
164
|
-
if (curr.event.type !== 0) _createBot?.(curr);
|
|
165
|
-
});
|
|
166
|
-
});
|
|
167
|
-
}, 2e3);
|
|
168
|
-
|
|
169
|
-
//#endregion
|
|
170
|
-
export { writeConfig as a, log as c, getDefaultConfig as i, basename as l, config as n, pkg as o, getConfig as r, pluginDirName as s, bindHandlers as t };
|
package/dist/utils-BPbnNAix.js
DELETED