@zhin.js/adapter-qq 5.0.2 → 5.0.3
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/CHANGELOG.md +41 -0
- package/README.md +51 -417
- package/adapters/qq.ts +45 -0
- package/agent/tools/add_role.ts +2 -2
- package/agent/tools/channel_info.ts +2 -2
- package/agent/tools/create_role.ts +2 -2
- package/agent/tools/list_channels.ts +2 -2
- package/agent/tools/list_guilds.ts +2 -2
- package/agent/tools/list_roles.ts +2 -2
- package/agent/tools/member_detail.ts +2 -2
- package/agent/tools/remove_role.ts +2 -2
- package/lib/endpoint.d.ts +69 -0
- package/lib/endpoint.js +315 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.js +6 -0
- package/lib/platform-permit.d.ts +16 -0
- package/lib/{src/platform-permit.js → platform-permit.js} +1 -2
- package/lib/protocol.d.ts +96 -0
- package/lib/protocol.js +129 -0
- package/lib/qq-agent-deps.d.ts +21 -0
- package/lib/qq-agent-deps.js +30 -0
- package/lib/webhook.d.ts +18 -0
- package/lib/webhook.js +100 -0
- package/lib/ws.d.ts +24 -0
- package/lib/ws.js +118 -0
- package/package.json +44 -40
- package/plugin.ts +13 -0
- package/schema.json +51 -0
- package/src/endpoint.ts +314 -600
- package/src/index.ts +56 -186
- package/src/platform-permit.ts +1 -1
- package/src/protocol.ts +229 -0
- package/src/qq-agent-deps.ts +49 -12
- package/src/webhook.ts +127 -0
- package/src/ws.ts +172 -0
- package/client/Dashboard.tsx +0 -230
- package/client/index.tsx +0 -11
- package/client/tsconfig.json +0 -7
- package/client/utils/api.ts +0 -30
- package/dist/index.js +0 -30
- package/lib/agent/tools/add_role.js +0 -23
- package/lib/agent/tools/add_role.js.map +0 -1
- package/lib/agent/tools/channel_info.js +0 -19
- package/lib/agent/tools/channel_info.js.map +0 -1
- package/lib/agent/tools/create_role.js +0 -22
- package/lib/agent/tools/create_role.js.map +0 -1
- package/lib/agent/tools/list_channels.js +0 -20
- package/lib/agent/tools/list_channels.js.map +0 -1
- package/lib/agent/tools/list_guilds.js +0 -17
- package/lib/agent/tools/list_guilds.js.map +0 -1
- package/lib/agent/tools/list_roles.js +0 -20
- package/lib/agent/tools/list_roles.js.map +0 -1
- package/lib/agent/tools/member_detail.js +0 -20
- package/lib/agent/tools/member_detail.js.map +0 -1
- package/lib/agent/tools/remove_role.js +0 -23
- package/lib/agent/tools/remove_role.js.map +0 -1
- package/lib/package.json +0 -105
- package/lib/src/adapter.js +0 -81
- package/lib/src/adapter.js.map +0 -1
- package/lib/src/endpoint.js +0 -600
- package/lib/src/endpoint.js.map +0 -1
- package/lib/src/gateway-config.js +0 -32
- package/lib/src/gateway-config.js.map +0 -1
- package/lib/src/group-at-normalize.js +0 -68
- package/lib/src/group-at-normalize.js.map +0 -1
- package/lib/src/inbound-action.js +0 -57
- package/lib/src/inbound-action.js.map +0 -1
- package/lib/src/inbound-normalize.js +0 -47
- package/lib/src/inbound-normalize.js.map +0 -1
- package/lib/src/index.js +0 -194
- package/lib/src/index.js.map +0 -1
- package/lib/src/mention-enrich.js +0 -52
- package/lib/src/mention-enrich.js.map +0 -1
- package/lib/src/outbound-keyboard.js +0 -100
- package/lib/src/outbound-keyboard.js.map +0 -1
- package/lib/src/outbound-markdown.js +0 -189
- package/lib/src/outbound-markdown.js.map +0 -1
- package/lib/src/outbound-media.js +0 -51
- package/lib/src/outbound-media.js.map +0 -1
- package/lib/src/outbound-mixed-media.js +0 -78
- package/lib/src/outbound-mixed-media.js.map +0 -1
- package/lib/src/platform-permit.js.map +0 -1
- package/lib/src/qq-agent-deps.js +0 -10
- package/lib/src/qq-agent-deps.js.map +0 -1
- package/lib/src/qq-bind-api.js +0 -90
- package/lib/src/qq-bind-api.js.map +0 -1
- package/lib/src/qq-bind-flow.js +0 -86
- package/lib/src/qq-bind-flow.js.map +0 -1
- package/lib/src/qq-bind-persist.js +0 -52
- package/lib/src/qq-bind-persist.js.map +0 -1
- package/lib/src/qq-endpoint-manager.js +0 -159
- package/lib/src/qq-endpoint-manager.js.map +0 -1
- package/lib/src/sdk-version.js +0 -19
- package/lib/src/sdk-version.js.map +0 -1
- package/lib/src/segment-mapper.js +0 -2
- package/lib/src/segment-mapper.js.map +0 -1
- package/lib/src/types.js +0 -2
- package/lib/src/types.js.map +0 -1
- package/plugin.yml +0 -3
- package/src/adapter.ts +0 -97
- package/src/gateway-config.ts +0 -48
- package/src/group-at-normalize.ts +0 -75
- package/src/inbound-action.ts +0 -87
- package/src/inbound-normalize.ts +0 -57
- package/src/mention-enrich.ts +0 -71
- package/src/outbound-keyboard.ts +0 -117
- package/src/outbound-markdown.ts +0 -212
- package/src/outbound-media.ts +0 -58
- package/src/outbound-mixed-media.ts +0 -101
- package/src/qq-bind-api.ts +0 -145
- package/src/qq-bind-flow.ts +0 -127
- package/src/qq-bind-persist.ts +0 -71
- package/src/qq-endpoint-manager.ts +0 -199
- package/src/sdk-version.ts +0 -21
- package/src/segment-mapper.ts +0 -1
- package/src/types.ts +0 -52
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent tool deps for qq.
|
|
3
|
+
* Endpoints register themselves on start; tools look up by config name / endpoint id.
|
|
4
|
+
*/
|
|
5
|
+
export interface QqAgentEndpoint {
|
|
6
|
+
getGuilds(): Promise<unknown[]>;
|
|
7
|
+
getChannels(guildId: string): Promise<unknown[]>;
|
|
8
|
+
getChannelInfo(channelId: string): Promise<unknown>;
|
|
9
|
+
getGuildMember(guildId: string, userId: string): Promise<unknown>;
|
|
10
|
+
getGuildRoles(guildId: string): Promise<unknown[]>;
|
|
11
|
+
createGuildRole(guildId: string, name: string, color?: number): Promise<unknown>;
|
|
12
|
+
addMemberRole(guildId: string, channelId: string, userId: string, roleId: string): Promise<boolean>;
|
|
13
|
+
removeMemberRole(guildId: string, channelId: string, userId: string, roleId: string): Promise<boolean>;
|
|
14
|
+
}
|
|
15
|
+
export interface QqAgentDeps {
|
|
16
|
+
getEndpoint: (endpointId: string) => QqAgentEndpoint;
|
|
17
|
+
}
|
|
18
|
+
export declare function registerQqAgentEndpoint(endpointId: string, endpoint: QqAgentEndpoint): () => void;
|
|
19
|
+
/** Optional override used by tests / transitional callers. Pass `null` to clear. */
|
|
20
|
+
export declare function setQqAgentDeps(deps: QqAgentDeps | null): void;
|
|
21
|
+
export declare function getQqAgentDeps(): QqAgentDeps;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent tool deps for qq.
|
|
3
|
+
* Endpoints register themselves on start; tools look up by config name / endpoint id.
|
|
4
|
+
*/
|
|
5
|
+
const endpoints = new Map();
|
|
6
|
+
let override = null;
|
|
7
|
+
export function registerQqAgentEndpoint(endpointId, endpoint) {
|
|
8
|
+
endpoints.set(endpointId, endpoint);
|
|
9
|
+
return () => {
|
|
10
|
+
if (endpoints.get(endpointId) === endpoint) {
|
|
11
|
+
endpoints.delete(endpointId);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/** Optional override used by tests / transitional callers. Pass `null` to clear. */
|
|
16
|
+
export function setQqAgentDeps(deps) {
|
|
17
|
+
override = deps;
|
|
18
|
+
}
|
|
19
|
+
export function getQqAgentDeps() {
|
|
20
|
+
if (override)
|
|
21
|
+
return override;
|
|
22
|
+
return {
|
|
23
|
+
getEndpoint(endpointId) {
|
|
24
|
+
const registered = endpoints.get(endpointId);
|
|
25
|
+
if (!registered)
|
|
26
|
+
throw new Error(`Endpoint ${endpointId} 不存在`);
|
|
27
|
+
return registered;
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
package/lib/webhook.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
import type { HttpHost, HttpRouteRegistration } from '@zhin.js/host-http';
|
|
3
|
+
import type { ResolvedQqHttpConfig } from './protocol.js';
|
|
4
|
+
import type { QqBotTransport } from './ws.js';
|
|
5
|
+
export type QqHttpBotTransport = QqBotTransport & {
|
|
6
|
+
middleware: (ctx: unknown, next: () => Promise<void>) => Promise<unknown>;
|
|
7
|
+
};
|
|
8
|
+
export type CreateQqHttpBot = (config: ResolvedQqHttpConfig) => QqHttpBotTransport;
|
|
9
|
+
export interface QqWebhookHandler {
|
|
10
|
+
readonly config: ResolvedQqHttpConfig;
|
|
11
|
+
getBot(): (QqHttpBotTransport & {
|
|
12
|
+
middleware?: QqHttpBotTransport['middleware'];
|
|
13
|
+
}) | null;
|
|
14
|
+
}
|
|
15
|
+
export declare function registerQqWebhookRoutes(http: HttpHost, handler: QqWebhookHandler): HttpRouteRegistration[];
|
|
16
|
+
export declare function handleQqWebhookRequest(request: IncomingMessage, response: ServerResponse, handler: QqWebhookHandler): Promise<void>;
|
|
17
|
+
export declare function readRequestBodyText(request: IncomingMessage): Promise<string>;
|
|
18
|
+
export declare function defaultCreateHttpBot(config: ResolvedQqHttpConfig): QqHttpBotTransport;
|
package/lib/webhook.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QQ HTTP webhook / middleware inbound via httpHostToken POST.
|
|
3
|
+
*/
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { Bot, ReceiverMode } from 'qq-official-bot';
|
|
6
|
+
import { getLogger } from '@zhin.js/logger';
|
|
7
|
+
const logger = getLogger('qq');
|
|
8
|
+
export function registerQqWebhookRoutes(http, handler) {
|
|
9
|
+
const webhookPath = handler.config.webhookPath;
|
|
10
|
+
return [
|
|
11
|
+
http.route('POST', webhookPath, async (request, response) => {
|
|
12
|
+
await handleQqWebhookRequest(request, response, handler);
|
|
13
|
+
}, { summary: 'QQ webhook callback', tags: ['qq'] }),
|
|
14
|
+
];
|
|
15
|
+
}
|
|
16
|
+
export async function handleQqWebhookRequest(request, response, handler) {
|
|
17
|
+
const bot = handler.getBot();
|
|
18
|
+
if (!bot?.middleware) {
|
|
19
|
+
response.writeHead(503, { 'Content-Type': 'text/plain' });
|
|
20
|
+
response.end('QQ receiver not ready');
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
let parsedBody;
|
|
25
|
+
const raw = await readRequestBodyText(request);
|
|
26
|
+
if (raw) {
|
|
27
|
+
try {
|
|
28
|
+
parsedBody = JSON.parse(raw);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
parsedBody = undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
await bot.middleware({
|
|
35
|
+
req: request,
|
|
36
|
+
res: response,
|
|
37
|
+
request: { body: parsedBody },
|
|
38
|
+
}, async () => undefined);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
logger.error('QQ webhook error:', error);
|
|
42
|
+
if (!response.headersSent) {
|
|
43
|
+
response.writeHead(500, { 'Content-Type': 'text/plain' });
|
|
44
|
+
response.end('Internal Server Error');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export async function readRequestBodyText(request) {
|
|
49
|
+
const chunks = [];
|
|
50
|
+
let size = 0;
|
|
51
|
+
for await (const chunk of request) {
|
|
52
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
53
|
+
size += buffer.length;
|
|
54
|
+
if (size > 1_048_576) {
|
|
55
|
+
request.destroy();
|
|
56
|
+
throw new Error('Request body exceeds 1MB');
|
|
57
|
+
}
|
|
58
|
+
chunks.push(buffer);
|
|
59
|
+
}
|
|
60
|
+
return Buffer.concat(chunks).toString('utf8');
|
|
61
|
+
}
|
|
62
|
+
export function defaultCreateHttpBot(config) {
|
|
63
|
+
const bot = new Bot({
|
|
64
|
+
appid: config.appid,
|
|
65
|
+
secret: config.secret,
|
|
66
|
+
mode: ReceiverMode.MIDDLEWARE,
|
|
67
|
+
platform: 'koa',
|
|
68
|
+
sandbox: config.sandbox,
|
|
69
|
+
dataDir: path.join(process.cwd(), 'data', 'qq'),
|
|
70
|
+
});
|
|
71
|
+
return {
|
|
72
|
+
start: () => bot.start().then(() => undefined),
|
|
73
|
+
stop: () => bot.stop().then(() => undefined),
|
|
74
|
+
on: (event, listener) => {
|
|
75
|
+
bot.on(event, listener);
|
|
76
|
+
},
|
|
77
|
+
removeAllListeners: () => {
|
|
78
|
+
bot.removeAllListeners(undefined);
|
|
79
|
+
},
|
|
80
|
+
sendPrivateMessage: (userId, message) => bot.sendPrivateMessage(userId, message),
|
|
81
|
+
sendGroupMessage: (groupId, message) => bot.sendGroupMessage(groupId, message),
|
|
82
|
+
sendGuildMessage: (channelId, message) => bot.sendGuildMessage(channelId, message),
|
|
83
|
+
sendDirectMessage: (guildId, message) => bot.sendDirectMessage(guildId, message),
|
|
84
|
+
getGuilds: () => bot.guildService.getList(),
|
|
85
|
+
getChannels: (guildId) => bot.channelService.getList(guildId),
|
|
86
|
+
getChannelInfo: (channelId) => bot.channelService.getInfo(channelId),
|
|
87
|
+
getGuildMember: (guildId, userId) => bot.memberService.getGuildMemberInfo(guildId, userId),
|
|
88
|
+
getGuildRoles: (guildId) => bot.guildService.getRoles(guildId),
|
|
89
|
+
createGuildRole: (guildId, name, color) => bot.guildService.createRole(guildId, { name, color: color || 0, hoist: 0 }),
|
|
90
|
+
addMemberRole: async (guildId, channelId, userId, roleId) => {
|
|
91
|
+
await bot.memberService.addMemberRole(guildId, channelId, userId, roleId);
|
|
92
|
+
return true;
|
|
93
|
+
},
|
|
94
|
+
removeMemberRole: async (guildId, channelId, userId, roleId) => {
|
|
95
|
+
await bot.memberService.removeMemberRole(guildId, channelId, userId, roleId);
|
|
96
|
+
return true;
|
|
97
|
+
},
|
|
98
|
+
middleware: (ctx, next) => bot.middleware(ctx, next),
|
|
99
|
+
};
|
|
100
|
+
}
|
package/lib/ws.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { QqInboundMessage, ResolvedQqWebsocketConfig } from './protocol.js';
|
|
2
|
+
/** Minimal bot surface used by the endpoint (real qq-official-bot or test mock). */
|
|
3
|
+
export interface QqBotTransport {
|
|
4
|
+
start(): Promise<void>;
|
|
5
|
+
stop(): Promise<void>;
|
|
6
|
+
on(event: string, listener: (...args: unknown[]) => void): void;
|
|
7
|
+
removeAllListeners(): void;
|
|
8
|
+
sendPrivateMessage(userId: string, message: string): Promise<unknown>;
|
|
9
|
+
sendGroupMessage(groupId: string, message: string): Promise<unknown>;
|
|
10
|
+
sendGuildMessage(channelId: string, message: string): Promise<unknown>;
|
|
11
|
+
sendDirectMessage?(guildId: string, message: string): Promise<unknown>;
|
|
12
|
+
getGuilds(): Promise<unknown[]>;
|
|
13
|
+
getChannels(guildId: string): Promise<unknown[]>;
|
|
14
|
+
getChannelInfo(channelId: string): Promise<unknown>;
|
|
15
|
+
getGuildMember(guildId: string, userId: string): Promise<unknown>;
|
|
16
|
+
getGuildRoles(guildId: string): Promise<unknown[]>;
|
|
17
|
+
createGuildRole(guildId: string, name: string, color?: number): Promise<unknown>;
|
|
18
|
+
addMemberRole(guildId: string, channelId: string, userId: string, roleId: string): Promise<boolean>;
|
|
19
|
+
removeMemberRole(guildId: string, channelId: string, userId: string, roleId: string): Promise<boolean>;
|
|
20
|
+
}
|
|
21
|
+
export type CreateQqBot = (config: ResolvedQqWebsocketConfig) => QqBotTransport;
|
|
22
|
+
export declare function bindQqBotInboundEvents(bot: QqBotTransport, admitRaw: (raw: unknown) => void): void;
|
|
23
|
+
export declare function normalizeQqMessage(raw: unknown): QqInboundMessage | null;
|
|
24
|
+
export declare function defaultCreateBot(config: ResolvedQqWebsocketConfig): QqBotTransport;
|
package/lib/ws.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QQ WebSocket transport: bot factory and inbound message normalization.
|
|
3
|
+
*/
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { Bot, ReceiverMode } from 'qq-official-bot';
|
|
6
|
+
import { getLevel, toLog4jsLevel } from '@zhin.js/logger';
|
|
7
|
+
export function bindQqBotInboundEvents(bot, admitRaw) {
|
|
8
|
+
bot.on('message.group', admitRaw);
|
|
9
|
+
bot.on('message.guild', admitRaw);
|
|
10
|
+
bot.on('message.private', admitRaw);
|
|
11
|
+
}
|
|
12
|
+
export function normalizeQqMessage(raw) {
|
|
13
|
+
if (!raw || typeof raw !== 'object')
|
|
14
|
+
return null;
|
|
15
|
+
const msg = raw;
|
|
16
|
+
if (msg.message_id == null)
|
|
17
|
+
return null;
|
|
18
|
+
let channelKind = 'private';
|
|
19
|
+
let channelId = '';
|
|
20
|
+
if (msg.message_type === 'guild') {
|
|
21
|
+
channelKind = msg.sub_type === 'direct' ? 'direct' : 'channel';
|
|
22
|
+
channelId = channelKind === 'direct'
|
|
23
|
+
? String(msg.guild_id ?? '')
|
|
24
|
+
: String(msg.channel_id ?? '');
|
|
25
|
+
}
|
|
26
|
+
else if (msg.message_type === 'group') {
|
|
27
|
+
channelKind = 'group';
|
|
28
|
+
channelId = String(msg.group_id ?? msg.group_openid ?? '');
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
channelKind = 'private';
|
|
32
|
+
channelId = String(msg.user_id ?? msg.author?.user_openid ?? msg.author?.id ?? '');
|
|
33
|
+
}
|
|
34
|
+
if (!channelId)
|
|
35
|
+
return null;
|
|
36
|
+
const authorId = String(msg.sender?.user_id
|
|
37
|
+
?? msg.user_id
|
|
38
|
+
?? msg.author?.member_openid
|
|
39
|
+
?? msg.author?.user_openid
|
|
40
|
+
?? msg.author?.id
|
|
41
|
+
?? '');
|
|
42
|
+
const content = extractTextContent(msg.message) || msg.raw_message || '';
|
|
43
|
+
const rawRoles = msg.member?.roles ?? msg.sender?.roles;
|
|
44
|
+
const authorRoles = Array.isArray(rawRoles) ? rawRoles.map(String) : undefined;
|
|
45
|
+
// 群 GROUP_AT_MESSAGE_CREATE 仅 @ 机器人时下发;频道 AT 事件看 mentions[].bot
|
|
46
|
+
const mentioned = channelKind === 'group'
|
|
47
|
+
|| (Array.isArray(msg.mentions) && msg.mentions.some((m) => m?.bot === true));
|
|
48
|
+
return {
|
|
49
|
+
id: String(msg.message_id),
|
|
50
|
+
content,
|
|
51
|
+
channelKind,
|
|
52
|
+
channelId,
|
|
53
|
+
authorId,
|
|
54
|
+
authorName: msg.sender?.user_name || msg.author?.username || authorId,
|
|
55
|
+
authorRoles,
|
|
56
|
+
timestamp: Date.now(),
|
|
57
|
+
guildId: msg.guild_id != null ? String(msg.guild_id) : undefined,
|
|
58
|
+
rawMessage: msg.raw_message,
|
|
59
|
+
...(mentioned ? { mentioned: true } : {}),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function extractTextContent(message) {
|
|
63
|
+
if (typeof message === 'string')
|
|
64
|
+
return message;
|
|
65
|
+
if (!Array.isArray(message))
|
|
66
|
+
return '';
|
|
67
|
+
return message
|
|
68
|
+
.map((seg) => {
|
|
69
|
+
if (!seg || typeof seg !== 'object')
|
|
70
|
+
return '';
|
|
71
|
+
const item = seg;
|
|
72
|
+
if (item.type === 'text')
|
|
73
|
+
return String(item.data?.text ?? item.text ?? '');
|
|
74
|
+
return '';
|
|
75
|
+
})
|
|
76
|
+
.join('');
|
|
77
|
+
}
|
|
78
|
+
export function defaultCreateBot(config) {
|
|
79
|
+
const bot = new Bot({
|
|
80
|
+
appid: config.appid,
|
|
81
|
+
secret: config.secret,
|
|
82
|
+
mode: ReceiverMode.WEBSOCKET,
|
|
83
|
+
sandbox: config.sandbox,
|
|
84
|
+
dataDir: path.join(process.cwd(), 'data', 'qq'),
|
|
85
|
+
logLevel: toLog4jsLevel(getLevel()),
|
|
86
|
+
...(config.intents ? { intents: config.intents } : {}),
|
|
87
|
+
...(config.accessTokenUrl ? { accessTokenUrl: config.accessTokenUrl } : {}),
|
|
88
|
+
...(config.gatewayUrl ? { gatewayUrl: config.gatewayUrl } : {}),
|
|
89
|
+
});
|
|
90
|
+
return {
|
|
91
|
+
start: () => bot.start().then(() => undefined),
|
|
92
|
+
stop: () => bot.stop().then(() => undefined),
|
|
93
|
+
on: (event, listener) => {
|
|
94
|
+
bot.on(event, listener);
|
|
95
|
+
},
|
|
96
|
+
removeAllListeners: () => {
|
|
97
|
+
bot.removeAllListeners(undefined);
|
|
98
|
+
},
|
|
99
|
+
sendPrivateMessage: (userId, message) => bot.sendPrivateMessage(userId, message),
|
|
100
|
+
sendGroupMessage: (groupId, message) => bot.sendGroupMessage(groupId, message),
|
|
101
|
+
sendGuildMessage: (channelId, message) => bot.sendGuildMessage(channelId, message),
|
|
102
|
+
sendDirectMessage: (guildId, message) => bot.sendDirectMessage(guildId, message),
|
|
103
|
+
getGuilds: () => bot.guildService.getList(),
|
|
104
|
+
getChannels: (guildId) => bot.channelService.getList(guildId),
|
|
105
|
+
getChannelInfo: (channelId) => bot.channelService.getInfo(channelId),
|
|
106
|
+
getGuildMember: (guildId, userId) => bot.memberService.getGuildMemberInfo(guildId, userId),
|
|
107
|
+
getGuildRoles: (guildId) => bot.guildService.getRoles(guildId),
|
|
108
|
+
createGuildRole: (guildId, name, color) => bot.guildService.createRole(guildId, { name, color: color || 0, hoist: 0 }),
|
|
109
|
+
addMemberRole: async (guildId, channelId, userId, roleId) => {
|
|
110
|
+
await bot.memberService.addMemberRole(guildId, channelId, userId, roleId);
|
|
111
|
+
return true;
|
|
112
|
+
},
|
|
113
|
+
removeMemberRole: async (guildId, channelId, userId, roleId) => {
|
|
114
|
+
await bot.memberService.removeMemberRole(guildId, channelId, userId, roleId);
|
|
115
|
+
return true;
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-qq",
|
|
3
|
-
"version": "5.0.
|
|
4
|
-
"description": "Zhin.js adapter for
|
|
3
|
+
"version": "5.0.3",
|
|
4
|
+
"description": "Zhin.js QQ Official adapter for Plugin Runtime (WebSocket gateway)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
7
7
|
"types": "./lib/index.d.ts",
|
|
@@ -34,59 +34,49 @@
|
|
|
34
34
|
"directory": "plugins/adapters/qq"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"qq-official-bot": "^1.2.3"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"@
|
|
41
|
-
"@
|
|
42
|
-
"
|
|
43
|
-
"typescript": "^6.0.3",
|
|
44
|
-
"zod": "^4.4.3",
|
|
45
|
-
"@zhin.js/cli": "1.0.93",
|
|
46
|
-
"@zhin.js/client": "2.0.5",
|
|
47
|
-
"@zhin.js/contract": "1.0.3",
|
|
48
|
-
"@zhin.js/host-api": "2.0.5",
|
|
49
|
-
"@zhin.js/host-router": "2.0.3",
|
|
50
|
-
"@zhin.js/logger": "1.0.74",
|
|
51
|
-
"zhin.js": "4.1.2",
|
|
52
|
-
"@zhin.js/agent": "1.0.3"
|
|
37
|
+
"qq-official-bot": "^1.2.3",
|
|
38
|
+
"@zhin.js/adapter": "1.0.1",
|
|
39
|
+
"@zhin.js/core": "1.3.5",
|
|
40
|
+
"@zhin.js/host-http": "1.0.1",
|
|
41
|
+
"@zhin.js/logger": "1.0.75",
|
|
42
|
+
"@zhin.js/plugin-runtime": "1.0.1"
|
|
53
43
|
},
|
|
54
44
|
"peerDependencies": {
|
|
55
45
|
"zod": "^4.0.0",
|
|
56
|
-
"@zhin.js/
|
|
57
|
-
"@zhin.js/
|
|
58
|
-
"@zhin.js/
|
|
59
|
-
"@zhin.js/
|
|
60
|
-
"
|
|
61
|
-
"zhin.js": "4.1.2",
|
|
62
|
-
"@zhin.js/agent": "1.0.3"
|
|
46
|
+
"@zhin.js/adapter": "1.0.1",
|
|
47
|
+
"@zhin.js/agent": "1.0.4",
|
|
48
|
+
"@zhin.js/core": "1.3.5",
|
|
49
|
+
"@zhin.js/plugin-runtime": "1.0.1",
|
|
50
|
+
"zhin.js": "4.1.3"
|
|
63
51
|
},
|
|
64
52
|
"peerDependenciesMeta": {
|
|
65
|
-
"
|
|
66
|
-
"optional": true
|
|
67
|
-
},
|
|
68
|
-
"@zhin.js/client": {
|
|
53
|
+
"zhin.js": {
|
|
69
54
|
"optional": true
|
|
70
55
|
},
|
|
71
|
-
"@zhin.js/
|
|
72
|
-
"optional": true
|
|
73
|
-
},
|
|
74
|
-
"@zhin.js/host-api": {
|
|
56
|
+
"@zhin.js/agent": {
|
|
75
57
|
"optional": true
|
|
76
58
|
},
|
|
77
59
|
"zod": {
|
|
78
60
|
"optional": true
|
|
79
61
|
}
|
|
80
62
|
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@types/node": "^26.1.0",
|
|
65
|
+
"typescript": "^6.0.3",
|
|
66
|
+
"vitest": "^4.1.10",
|
|
67
|
+
"zod": "^4.4.3",
|
|
68
|
+
"@zhin.js/agent": "1.0.4",
|
|
69
|
+
"@zhin.js/host-http": "1.0.1",
|
|
70
|
+
"zhin.js": "4.1.3"
|
|
71
|
+
},
|
|
81
72
|
"files": [
|
|
73
|
+
"adapters",
|
|
74
|
+
"plugin.ts",
|
|
75
|
+
"schema.json",
|
|
82
76
|
"src",
|
|
83
77
|
"lib",
|
|
84
|
-
"client",
|
|
85
|
-
"dist",
|
|
86
78
|
"agent",
|
|
87
|
-
"plugin.yml",
|
|
88
79
|
"README.md",
|
|
89
|
-
"node",
|
|
90
80
|
"CHANGELOG.md"
|
|
91
81
|
],
|
|
92
82
|
"publishConfig": {
|
|
@@ -96,9 +86,23 @@
|
|
|
96
86
|
"engines": {
|
|
97
87
|
"node": "^20.19.0 || >=22.12.0"
|
|
98
88
|
},
|
|
89
|
+
"zhin": {
|
|
90
|
+
"protocol": 1,
|
|
91
|
+
"type": "plugin",
|
|
92
|
+
"entry": "./plugin.ts",
|
|
93
|
+
"engine": "^1.0.0",
|
|
94
|
+
"runtime": "trusted",
|
|
95
|
+
"features": [
|
|
96
|
+
{
|
|
97
|
+
"package": "@zhin.js/adapter",
|
|
98
|
+
"api": "^1.0.0"
|
|
99
|
+
}
|
|
100
|
+
],
|
|
101
|
+
"plugins": []
|
|
102
|
+
},
|
|
99
103
|
"scripts": {
|
|
100
|
-
"build": "
|
|
101
|
-
"clean": "rimraf lib
|
|
102
|
-
"
|
|
104
|
+
"build": "tsc",
|
|
105
|
+
"clean": "rimraf lib",
|
|
106
|
+
"test": "NODE_OPTIONS=--experimental-strip-types vitest run --root ../../.. plugins/adapters/qq/tests"
|
|
103
107
|
}
|
|
104
108
|
}
|
package/plugin.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { definePlugin } from '@zhin.js/plugin-runtime';
|
|
2
|
+
import { registerQqPlatformPermitChecker } from './src/platform-permit.js';
|
|
3
|
+
|
|
4
|
+
export default definePlugin({
|
|
5
|
+
name: 'qq',
|
|
6
|
+
metadata: {
|
|
7
|
+
displayName: 'QQ Official WebSocket Adapter',
|
|
8
|
+
},
|
|
9
|
+
setup() {
|
|
10
|
+
// 平台权限门禁:guild_owner / guild_admin / manage_roles / manage_channels(agent 工具 platformPermit)
|
|
11
|
+
return registerQqPlatformPermitChecker();
|
|
12
|
+
},
|
|
13
|
+
});
|
package/schema.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"additionalProperties": false,
|
|
5
|
+
"properties": {
|
|
6
|
+
"name": {
|
|
7
|
+
"type": "string",
|
|
8
|
+
"default": "qq-bot"
|
|
9
|
+
},
|
|
10
|
+
"appid": {
|
|
11
|
+
"type": "string"
|
|
12
|
+
},
|
|
13
|
+
"secret": {
|
|
14
|
+
"type": "string"
|
|
15
|
+
},
|
|
16
|
+
"mode": {
|
|
17
|
+
"type": "string",
|
|
18
|
+
"enum": ["websocket", "webhook", "middleware"],
|
|
19
|
+
"default": "websocket",
|
|
20
|
+
"description": "WebSocket gateway (default). webhook/middleware use httpHostToken POST."
|
|
21
|
+
},
|
|
22
|
+
"sandbox": {
|
|
23
|
+
"type": "boolean",
|
|
24
|
+
"default": false
|
|
25
|
+
},
|
|
26
|
+
"intents": {
|
|
27
|
+
"type": "array",
|
|
28
|
+
"items": { "type": "string" }
|
|
29
|
+
},
|
|
30
|
+
"accessTokenUrl": {
|
|
31
|
+
"type": "string"
|
|
32
|
+
},
|
|
33
|
+
"gatewayUrl": {
|
|
34
|
+
"type": "string"
|
|
35
|
+
},
|
|
36
|
+
"webhookPath": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"default": "/qq/webhook",
|
|
39
|
+
"description": "POST path on httpHostToken for webhook/middleware modes."
|
|
40
|
+
},
|
|
41
|
+
"port": {
|
|
42
|
+
"type": "number",
|
|
43
|
+
"description": "Legacy standalone webhook port (unused with httpHostToken)."
|
|
44
|
+
},
|
|
45
|
+
"path": {
|
|
46
|
+
"type": "string",
|
|
47
|
+
"description": "Legacy standalone webhook path (unused with httpHostToken)."
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"required": ["appid", "secret"]
|
|
51
|
+
}
|