@zhin.js/adapter-napcat 6.0.14 → 7.0.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/CHANGELOG.md +36 -0
- package/README.md +18 -3
- package/adapters/napcat.js +2 -8
- package/adapters/napcat.ts +2 -8
- package/agent/tools/ai_tts.ts +4 -6
- package/agent/tools/del_group_notice.ts +4 -6
- package/agent/tools/delete_essence_msg.ts +4 -6
- package/agent/tools/delete_friend.ts +4 -6
- package/agent/tools/download_file.ts +4 -6
- package/agent/tools/forward_single_msg.ts +4 -8
- package/agent/tools/get_ai_characters.ts +4 -6
- package/agent/tools/get_essence_list.ts +4 -6
- package/agent/tools/get_friend_msg_history.ts +4 -6
- package/agent/tools/get_group_file_url.ts +4 -6
- package/agent/tools/get_group_info_ex.ts +4 -6
- package/agent/tools/get_group_msg_history.ts +4 -6
- package/agent/tools/get_group_notice.ts +4 -6
- package/agent/tools/get_group_root_files.ts +4 -6
- package/agent/tools/get_group_shut_list.ts +4 -6
- package/agent/tools/get_mini_app_ark.ts +4 -6
- package/agent/tools/get_user_status.ts +4 -6
- package/agent/tools/group_sign.ts +4 -6
- package/agent/tools/mark_msg_as_read.ts +4 -6
- package/agent/tools/ocr_image.ts +4 -6
- package/agent/tools/send_forward_msg.ts +4 -8
- package/agent/tools/send_group_notice.ts +4 -6
- package/agent/tools/send_like.ts +4 -6
- package/agent/tools/send_poke.ts +4 -6
- package/agent/tools/set_avatar.ts +4 -6
- package/agent/tools/set_emoji_reaction.ts +4 -6
- package/agent/tools/set_essence_msg.ts +4 -6
- package/agent/tools/set_group_portrait.ts +4 -6
- package/agent/tools/set_online_status.ts +4 -6
- package/agent/tools/set_profile.ts +4 -6
- package/agent/tools/set_signature.ts +4 -6
- package/agent/tools/set_title.ts +4 -6
- package/agent/tools/translate.ts +4 -6
- package/agent/tools/upload_group_file.ts +4 -6
- package/lib/{napcat-agent-deps.d.ts → client.d.ts} +15 -14
- package/lib/client.js +62 -0
- package/lib/http-endpoint.d.ts +6 -6
- package/lib/http-endpoint.js +24 -12
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/napcat-endpoint-commands.d.ts +1 -1
- package/lib/side-event-dispatch.d.ts +2 -2
- package/lib/side-event-dispatch.js +3 -3
- package/lib/ws-endpoint.d.ts +6 -41
- package/lib/ws-endpoint.js +26 -157
- package/lib/wss-endpoint.d.ts +6 -6
- package/lib/wss-endpoint.js +25 -13
- package/package.json +15 -14
- package/src/client.ts +79 -0
- package/src/http-endpoint.ts +31 -20
- package/src/index.ts +4 -7
- package/src/side-event-dispatch.ts +4 -4
- package/src/ws-endpoint.ts +29 -202
- package/src/wss-endpoint.ts +32 -21
- package/lib/napcat-agent-deps.js +0 -33
- package/src/napcat-agent-deps.ts +0 -95
package/src/client.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { defineEndpointClient } from 'zhin.js/adapter';
|
|
2
|
+
import type { NapCatEvent } from './protocol.js';
|
|
3
|
+
|
|
4
|
+
export type NapcatApiCall = (
|
|
5
|
+
action: string,
|
|
6
|
+
params?: Record<string, unknown>,
|
|
7
|
+
) => Promise<unknown>;
|
|
8
|
+
|
|
9
|
+
/** Transport-independent NapCat protocol Client produced by every Endpoint mode. */
|
|
10
|
+
export class NapcatClient {
|
|
11
|
+
constructor(readonly callApi: NapcatApiCall) {}
|
|
12
|
+
|
|
13
|
+
async setTitle(groupId: number, userId: number, title: string, duration = -1): Promise<boolean> {
|
|
14
|
+
await this.callApi('set_group_special_title', {
|
|
15
|
+
group_id: groupId,
|
|
16
|
+
user_id: userId,
|
|
17
|
+
special_title: title,
|
|
18
|
+
duration,
|
|
19
|
+
});
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
sendLike(userId: number, times = 1) { return this.callApi('send_like', { user_id: userId, times }); }
|
|
24
|
+
deleteFriend(userId: number) { return this.callApi('delete_friend', { user_id: userId }); }
|
|
25
|
+
markMsgAsRead(messageId: number) { return this.callApi('mark_msg_as_read', { message_id: messageId }); }
|
|
26
|
+
ocrImage(image: string) { return this.callApi('ocr_image', { image }); }
|
|
27
|
+
setQQProfile(nickname: string, company?: string, email?: string, college?: string, personalNote?: string) {
|
|
28
|
+
return this.callApi('set_qq_profile', { nickname, company, email, college, personal_note: personalNote });
|
|
29
|
+
}
|
|
30
|
+
setGroupPortrait(groupId: number, file: string) { return this.callApi('set_group_portrait', { group_id: groupId, file }); }
|
|
31
|
+
setEssenceMsg(messageId: number) { return this.callApi('set_essence_msg', { message_id: messageId }); }
|
|
32
|
+
deleteEssenceMsg(messageId: number) { return this.callApi('delete_essence_msg', { message_id: messageId }); }
|
|
33
|
+
getEssenceMsgList(groupId: number) { return this.callApi('get_essence_msg_list', { group_id: groupId }); }
|
|
34
|
+
sendGroupSign(groupId: number) { return this.callApi('send_group_sign', { group_id: groupId }); }
|
|
35
|
+
sendGroupNotice(groupId: number, content: string, image?: string) { return this.callApi('_send_group_notice', { group_id: groupId, content, image }); }
|
|
36
|
+
getGroupNotice(groupId: number) { return this.callApi('_get_group_notice', { group_id: groupId }); }
|
|
37
|
+
deleteGroupNotice(groupId: number, noticeId: string) { return this.callApi('_del_group_notice', { group_id: groupId, notice_id: noticeId }); }
|
|
38
|
+
uploadGroupFile(groupId: number, file: string, name: string, folder?: string) { return this.callApi('upload_group_file', { group_id: groupId, file, name, folder }); }
|
|
39
|
+
getGroupRootFiles(groupId: number) { return this.callApi('get_group_root_files', { group_id: groupId }); }
|
|
40
|
+
getGroupFileUrl(groupId: number, fileId: string, busid: number) { return this.callApi('get_group_file_url', { group_id: groupId, file_id: fileId, busid }); }
|
|
41
|
+
downloadFile(url: string, threadCount = 1, headers?: string[]) { return this.callApi('download_file', { url, thread_count: threadCount, headers }); }
|
|
42
|
+
setOnlineStatus(status: number, extStatus: number) { return this.callApi('set_online_status', { status, ext_status: extStatus }); }
|
|
43
|
+
setQQAvatar(file: string) { return this.callApi('set_qq_avatar', { file }); }
|
|
44
|
+
forwardFriendSingleMsg(userId: number, messageId: number) { return this.callApi('forward_friend_single_msg', { user_id: userId, message_id: messageId }); }
|
|
45
|
+
forwardGroupSingleMsg(groupId: number, messageId: number) { return this.callApi('forward_group_single_msg', { group_id: groupId, message_id: messageId }); }
|
|
46
|
+
translateEn2Zh(sourceText: string) { return this.callApi('translate_en2zh', { source_text: sourceText }); }
|
|
47
|
+
setMsgEmojiLike(messageId: number, emojiId: string) { return this.callApi('set_msg_emoji_like', { message_id: messageId, emoji_id: emojiId }); }
|
|
48
|
+
sendForwardMsg(messageType: 'private' | 'group', id: number, messages: unknown[]) {
|
|
49
|
+
return this.callApi('send_forward_msg', {
|
|
50
|
+
message_type: messageType,
|
|
51
|
+
[messageType === 'group' ? 'group_id' : 'user_id']: id,
|
|
52
|
+
messages,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
getFriendMsgHistory(userId: number, messageSeq?: number, count?: number) { return this.callApi('get_friend_msg_history', { user_id: userId, message_seq: messageSeq, count }); }
|
|
56
|
+
getGroupMsgHistory(groupId: number, messageSeq?: number, count?: number) { return this.callApi('get_group_msg_history', { group_id: groupId, message_seq: messageSeq, count }); }
|
|
57
|
+
setSelfLongnick(longnick: string) { return this.callApi('set_self_longnick', { longNick: longnick }); }
|
|
58
|
+
getGroupInfoEx(groupId: number) { return this.callApi('get_group_info_ex', { group_id: groupId }); }
|
|
59
|
+
sendPoke(userId: number, groupId?: number) { return this.callApi('send_poke', { user_id: userId, group_id: groupId }); }
|
|
60
|
+
ncGetUserStatus(userId: number) { return this.callApi('nc_get_user_status', { user_id: userId }); }
|
|
61
|
+
getGroupShutList(groupId: number) { return this.callApi('get_group_shut_list', { group_id: groupId }); }
|
|
62
|
+
getMiniAppArk(type: string, title: string, desc: string, picUrl: string, jumpUrl: string) { return this.callApi('get_mini_app_ark', { type, title, desc, picUrl, jumpUrl }); }
|
|
63
|
+
getAiCharacters(groupId: number) { return this.callApi('get_ai_characters', { group_id: groupId }); }
|
|
64
|
+
sendGroupAiRecord(groupId: number, characterId: string, text: string) {
|
|
65
|
+
return this.callApi('send_group_ai_record', { group_id: groupId, character: characterId, text });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export type NapcatClientEventMap = Record<string, NapCatEvent>;
|
|
69
|
+
|
|
70
|
+
declare module '@zhin.js/feature-kit' {
|
|
71
|
+
interface AdapterClientRegistry {
|
|
72
|
+
readonly napcat: {
|
|
73
|
+
readonly client: NapcatClient;
|
|
74
|
+
readonly events: NapcatClientEventMap;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export const napcatClient = defineEndpointClient<NapcatClient, NapcatClientEventMap>('napcat');
|
package/src/http-endpoint.ts
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
|
+
import { Endpoint } from 'zhin.js/adapter';
|
|
1
2
|
/**
|
|
2
3
|
* NapCat HTTP endpoint — POST inbound events + HTTP API outbound.
|
|
3
4
|
*/
|
|
4
5
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
5
|
-
import
|
|
6
|
-
|
|
6
|
+
import {
|
|
7
|
+
createRecallEndpointControl,
|
|
8
|
+
type EndpointControl,
|
|
9
|
+
type EndpointManagement,
|
|
10
|
+
type EndpointSendRequest,
|
|
11
|
+
} from 'zhin.js/adapter';
|
|
7
12
|
import type { HttpHost, HttpRouteRegistration } from '@zhin.js/host-http';
|
|
8
13
|
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
9
14
|
import type { CapabilityId } from 'zhin.js';
|
|
10
15
|
import { createNapCatEndpointManagement } from './endpoint-management.js';
|
|
11
|
-
import { registerNapcatAgentEndpoint } from './napcat-agent-deps.js';
|
|
12
16
|
import {
|
|
13
17
|
InboundMessageDeduper,
|
|
14
18
|
isNapCatBotMentioned,
|
|
@@ -30,33 +34,34 @@ import {
|
|
|
30
34
|
} from './protocol.js';
|
|
31
35
|
import { receiveNapCatSideEvent } from './side-event-dispatch.js';
|
|
32
36
|
import { createNapCatContentPort } from './onebot-get-msg.js';
|
|
37
|
+
import { NapcatClient } from './client.js';
|
|
33
38
|
import { readRequestBody } from './webhook.js';
|
|
34
39
|
import { NapCatWsEndpoint } from './ws-endpoint.js';
|
|
35
40
|
import { verifyNapCatAccessToken } from './wss-auth.js';
|
|
36
41
|
|
|
37
42
|
export interface NapCatHttpEndpointOptions {
|
|
38
43
|
readonly id: CapabilityId;
|
|
39
|
-
readonly gateway: MessageGateway;
|
|
40
|
-
readonly sideEvents?: SideEventGateway;
|
|
41
44
|
readonly http: HttpHost;
|
|
42
45
|
readonly config: NapCatHttpConfig;
|
|
43
46
|
readonly callHttpAction?: typeof callNapCatHttpAction;
|
|
44
47
|
}
|
|
45
48
|
|
|
46
|
-
export class NapCatHttpEndpoint
|
|
49
|
+
export class NapCatHttpEndpoint extends Endpoint<NapcatClient> {
|
|
50
|
+
readonly client = new NapcatClient((action, params) => this.#callApi(action, params));
|
|
47
51
|
readonly #logger!: ReturnType<typeof getAdapterLogger>;
|
|
48
52
|
|
|
49
53
|
readonly #options: NapCatHttpEndpointOptions;
|
|
50
54
|
readonly #inboundDeduper = new InboundMessageDeduper();
|
|
51
|
-
readonly management: EndpointManagement = createNapCatEndpointManagement(this);
|
|
52
|
-
readonly
|
|
55
|
+
readonly management: EndpointManagement = createNapCatEndpointManagement(this.client);
|
|
56
|
+
readonly control: EndpointControl = createRecallEndpointControl((id) => this.recallMessage(id));
|
|
57
|
+
readonly content = createNapCatContentPort((action, params) => this.client.callApi(action, params));
|
|
53
58
|
readonly #callHttpAction: typeof callNapCatHttpAction;
|
|
54
59
|
#routeReleases: HttpRouteRegistration[] = [];
|
|
55
60
|
#open = false;
|
|
56
61
|
#started = false;
|
|
57
|
-
#unregisterAgent?: () => void;
|
|
58
62
|
|
|
59
63
|
constructor(options: NapCatHttpEndpointOptions) {
|
|
64
|
+
super();
|
|
60
65
|
this.#logger = getAdapterLogger('napcat', options.config.id);
|
|
61
66
|
this.#options = options;
|
|
62
67
|
this.#callHttpAction = options.callHttpAction ?? callNapCatHttpAction;
|
|
@@ -65,10 +70,6 @@ export class NapCatHttpEndpoint implements EndpointInstance {
|
|
|
65
70
|
async start(): Promise<void> {
|
|
66
71
|
if (this.#started) return;
|
|
67
72
|
this.#started = true;
|
|
68
|
-
this.#unregisterAgent = registerNapcatAgentEndpoint(
|
|
69
|
-
this.#options.config.id,
|
|
70
|
-
this as unknown as NapCatWsEndpoint,
|
|
71
|
-
);
|
|
72
73
|
this.#setupRoutes();
|
|
73
74
|
this.#logger.info(formatCompact({
|
|
74
75
|
op: 'listen',
|
|
@@ -89,8 +90,6 @@ export class NapCatHttpEndpoint implements EndpointInstance {
|
|
|
89
90
|
async stop(): Promise<void> {
|
|
90
91
|
this.#open = false;
|
|
91
92
|
for (const release of this.#routeReleases.splice(0)) release();
|
|
92
|
-
this.#unregisterAgent?.();
|
|
93
|
-
this.#unregisterAgent = undefined;
|
|
94
93
|
this.#inboundDeduper.clear();
|
|
95
94
|
this.#started = false;
|
|
96
95
|
this.#logger.debug(formatCompact({ op: 'disconnect' }));
|
|
@@ -120,10 +119,10 @@ export class NapCatHttpEndpoint implements EndpointInstance {
|
|
|
120
119
|
|
|
121
120
|
async recallMessage(messageId: string): Promise<void> {
|
|
122
121
|
if (!messageId) return;
|
|
123
|
-
await this.callApi('delete_msg', { message_id: Number(messageId) });
|
|
122
|
+
await this.client.callApi('delete_msg', { message_id: Number(messageId) });
|
|
124
123
|
}
|
|
125
124
|
|
|
126
|
-
callApi(action: string, params: Record<string, unknown> = {}): Promise<unknown> {
|
|
125
|
+
#callApi(action: string, params: Record<string, unknown> = {}): Promise<unknown> {
|
|
127
126
|
return this.#callHttpAction(
|
|
128
127
|
{
|
|
129
128
|
http_url: this.#options.config.http_url,
|
|
@@ -136,11 +135,17 @@ export class NapCatHttpEndpoint implements EndpointInstance {
|
|
|
136
135
|
|
|
137
136
|
admit(ev: NapCatEvent): void {
|
|
138
137
|
if (!this.#open) return;
|
|
138
|
+
void this.emitPlatform(napCatPlatformEventName(ev), ev).catch((error) => {
|
|
139
|
+
this.#logger.warn(formatCompact({
|
|
140
|
+
op: 'napcat_platform_event_failed',
|
|
141
|
+
error: error instanceof Error ? error.message : String(error),
|
|
142
|
+
}));
|
|
143
|
+
});
|
|
139
144
|
if (!isMessageEvent(ev)) {
|
|
140
145
|
receiveNapCatSideEvent(
|
|
141
|
-
this
|
|
146
|
+
(name, payload) => this.emit(name, payload),
|
|
142
147
|
this.#options.config.id,
|
|
143
|
-
this,
|
|
148
|
+
this.client,
|
|
144
149
|
ev,
|
|
145
150
|
this.#logger,
|
|
146
151
|
);
|
|
@@ -155,7 +160,7 @@ export class NapCatHttpEndpoint implements EndpointInstance {
|
|
|
155
160
|
const conversation = napcatInboundConversation(String(this.#options.id), ev);
|
|
156
161
|
const nickname = senderNickname(ev);
|
|
157
162
|
const mentioned = isNapCatBotMentioned(ev);
|
|
158
|
-
void this
|
|
163
|
+
void this.emit('message.receive', {
|
|
159
164
|
conversation,
|
|
160
165
|
message: { conversation, id: msgId },
|
|
161
166
|
content: formatInboundContent(ev),
|
|
@@ -221,3 +226,9 @@ export class NapCatHttpEndpoint implements EndpointInstance {
|
|
|
221
226
|
}
|
|
222
227
|
}
|
|
223
228
|
}
|
|
229
|
+
|
|
230
|
+
function napCatPlatformEventName(ev: NapCatEvent): string {
|
|
231
|
+
return [ev.post_type, ev.message_type ?? ev.notice_type ?? ev.request_type, ev.sub_type]
|
|
232
|
+
.filter(Boolean)
|
|
233
|
+
.join('.');
|
|
234
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -37,13 +37,10 @@ export {
|
|
|
37
37
|
} from './napcat-inbound.js';
|
|
38
38
|
|
|
39
39
|
export {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
type NapcatAgentDeps,
|
|
45
|
-
type NapcatAgentEndpoint,
|
|
46
|
-
} from './napcat-agent-deps.js';
|
|
40
|
+
napcatClient,
|
|
41
|
+
type NapcatClient,
|
|
42
|
+
type NapcatClientEventMap,
|
|
43
|
+
} from './client.js';
|
|
47
44
|
|
|
48
45
|
export { parseOneBotGetMsgResponse } from './onebot-get-msg.js';
|
|
49
46
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { receiveOneBotLikeSideEvent } from '@zhin.js/core';
|
|
2
|
-
import type {
|
|
2
|
+
import type { EndpointEventEmitter } from 'zhin.js/adapter';
|
|
3
3
|
import { formatCompact, type getAdapterLogger } from '@zhin.js/logger';
|
|
4
4
|
import type { NapCatEvent } from './protocol.js';
|
|
5
5
|
|
|
@@ -8,19 +8,19 @@ export interface NapCatSideEventCaller {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export function receiveNapCatSideEvent(
|
|
11
|
-
|
|
11
|
+
emit: EndpointEventEmitter,
|
|
12
12
|
endpointKey: string,
|
|
13
13
|
caller: NapCatSideEventCaller,
|
|
14
14
|
raw: NapCatEvent,
|
|
15
15
|
logger: ReturnType<typeof getAdapterLogger>,
|
|
16
16
|
): void {
|
|
17
|
-
if (!
|
|
17
|
+
if (!emit) return;
|
|
18
18
|
const record = raw as Record<string, unknown>;
|
|
19
19
|
const postType = String(record.post_type ?? '');
|
|
20
20
|
const requestType = String(record.request_type ?? '');
|
|
21
21
|
const isRequest = postType === 'request' || postType.startsWith('request.');
|
|
22
22
|
const isFriend = requestType === 'friend' || postType.includes('friend');
|
|
23
|
-
void receiveOneBotLikeSideEvent(
|
|
23
|
+
void receiveOneBotLikeSideEvent(emit, {
|
|
24
24
|
adapter: 'napcat',
|
|
25
25
|
endpointKey,
|
|
26
26
|
platform: 'napcat',
|
package/src/ws-endpoint.ts
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
+
import { Endpoint } from 'zhin.js/adapter';
|
|
1
2
|
/**
|
|
2
3
|
* NapCat WS client endpoint — outbound connect to NapCat.
|
|
3
4
|
*/
|
|
4
5
|
import WebSocket from 'ws';
|
|
5
6
|
import {
|
|
7
|
+
createRecallEndpointControl,
|
|
6
8
|
createEndpointLifecycle,
|
|
7
9
|
type EndpointConnectHandle,
|
|
8
|
-
type
|
|
10
|
+
type EndpointControl,
|
|
9
11
|
type EndpointLifecycle,
|
|
10
12
|
type EndpointManagement,
|
|
11
13
|
type EndpointSendRequest,
|
|
12
14
|
} from 'zhin.js/adapter';
|
|
13
|
-
import type { MessageGateway, SideEventGateway } from '@zhin.js/core/runtime';
|
|
14
15
|
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
15
16
|
import type { CapabilityId } from 'zhin.js';
|
|
16
17
|
import { createNapCatEndpointManagement } from './endpoint-management.js';
|
|
17
|
-
import { registerNapcatAgentEndpoint } from './napcat-agent-deps.js';
|
|
18
18
|
import {
|
|
19
19
|
InboundMessageDeduper,
|
|
20
20
|
isNapCatBotMentioned,
|
|
@@ -46,11 +46,10 @@ import {
|
|
|
46
46
|
type NapCatWsSocket,
|
|
47
47
|
} from './ws-types.js';
|
|
48
48
|
import { createNapCatContentPort } from './onebot-get-msg.js';
|
|
49
|
+
import { NapcatClient } from './client.js';
|
|
49
50
|
|
|
50
51
|
export interface NapCatWsEndpointOptions {
|
|
51
52
|
readonly id: CapabilityId;
|
|
52
|
-
readonly gateway: MessageGateway;
|
|
53
|
-
readonly sideEvents?: SideEventGateway;
|
|
54
53
|
readonly config: NapCatWsConfig;
|
|
55
54
|
readonly createWebSocket?: (
|
|
56
55
|
url: string,
|
|
@@ -58,21 +57,23 @@ export interface NapCatWsEndpointOptions {
|
|
|
58
57
|
) => NapCatWsSocket;
|
|
59
58
|
}
|
|
60
59
|
|
|
61
|
-
export class NapCatWsEndpoint
|
|
60
|
+
export class NapCatWsEndpoint extends Endpoint<NapcatClient> {
|
|
61
|
+
readonly client = new NapcatClient((action, params) => this.#callApi(action, params));
|
|
62
62
|
readonly #logger!: ReturnType<typeof getAdapterLogger>;
|
|
63
63
|
|
|
64
64
|
readonly #options: NapCatWsEndpointOptions;
|
|
65
65
|
readonly #inboundDeduper = new InboundMessageDeduper();
|
|
66
|
-
readonly management: EndpointManagement = createNapCatEndpointManagement(this);
|
|
67
|
-
readonly
|
|
66
|
+
readonly management: EndpointManagement = createNapCatEndpointManagement(this.client);
|
|
67
|
+
readonly control: EndpointControl = createRecallEndpointControl((id) => this.recallMessage(id));
|
|
68
|
+
readonly content = createNapCatContentPort((action, params) => this.client.callApi(action, params));
|
|
68
69
|
readonly #lifecycle: EndpointLifecycle;
|
|
69
70
|
#ws?: NapCatWsSocket;
|
|
70
71
|
#requestId = { value: 0 };
|
|
71
72
|
#pending = new Map<string, NapCatPendingAction>();
|
|
72
73
|
#open = false;
|
|
73
|
-
#unregisterAgent?: () => void;
|
|
74
74
|
|
|
75
75
|
constructor(options: NapCatWsEndpointOptions) {
|
|
76
|
+
super();
|
|
76
77
|
this.#logger = getAdapterLogger('napcat', options.config.id);
|
|
77
78
|
this.#options = options;
|
|
78
79
|
this.#lifecycle = createEndpointLifecycle({
|
|
@@ -89,15 +90,7 @@ export class NapCatWsEndpoint implements EndpointInstance {
|
|
|
89
90
|
|
|
90
91
|
async start(): Promise<void> {
|
|
91
92
|
if (this.#lifecycle.started) return;
|
|
92
|
-
this.#
|
|
93
|
-
try {
|
|
94
|
-
await this.#lifecycle.start((handle) => this.#connect(handle));
|
|
95
|
-
} catch (err) {
|
|
96
|
-
// start 失败复位由基座保证;agent 注册/反注册是适配器专有依赖,留在适配器侧
|
|
97
|
-
this.#unregisterAgent?.();
|
|
98
|
-
this.#unregisterAgent = undefined;
|
|
99
|
-
throw err;
|
|
100
|
-
}
|
|
93
|
+
await this.#lifecycle.start((handle) => this.#connect(handle));
|
|
101
94
|
}
|
|
102
95
|
|
|
103
96
|
open(): void {
|
|
@@ -111,8 +104,6 @@ export class NapCatWsEndpoint implements EndpointInstance {
|
|
|
111
104
|
async stop(): Promise<void> {
|
|
112
105
|
this.#open = false;
|
|
113
106
|
await this.#lifecycle.stop();
|
|
114
|
-
this.#unregisterAgent?.();
|
|
115
|
-
this.#unregisterAgent = undefined;
|
|
116
107
|
rejectAllPending(this.#pending);
|
|
117
108
|
this.#inboundDeduper.clear();
|
|
118
109
|
if (this.#ws) {
|
|
@@ -128,7 +119,7 @@ export class NapCatWsEndpoint implements EndpointInstance {
|
|
|
128
119
|
async send({ conversation, payload }: EndpointSendRequest): Promise<string> {
|
|
129
120
|
const message = formatOutboundSegments(payload);
|
|
130
121
|
const { action, params } = buildSendAction(napcatOutboundTarget(conversation), message);
|
|
131
|
-
const data = await this.callApi(action, params) as { message_id?: number | string } | undefined;
|
|
122
|
+
const data = await this.client.callApi(action, params) as { message_id?: number | string } | undefined;
|
|
132
123
|
const messageId = data?.message_id != null ? String(data.message_id) : '';
|
|
133
124
|
this.#logger.debug(formatCompact({
|
|
134
125
|
op: 'napcat_send',
|
|
@@ -141,197 +132,27 @@ export class NapCatWsEndpoint implements EndpointInstance {
|
|
|
141
132
|
|
|
142
133
|
async recallMessage(messageId: string): Promise<void> {
|
|
143
134
|
if (!messageId) return;
|
|
144
|
-
await this.callApi('delete_msg', { message_id: Number(messageId) });
|
|
135
|
+
await this.client.callApi('delete_msg', { message_id: Number(messageId) });
|
|
145
136
|
}
|
|
146
137
|
|
|
147
|
-
callApi(action: string, params: Record<string, unknown> = {}): Promise<unknown> {
|
|
138
|
+
#callApi(action: string, params: Record<string, unknown> = {}): Promise<unknown> {
|
|
148
139
|
return callNapCatWsAction(this.#ws, this.#pending, this.#requestId, action, params);
|
|
149
140
|
}
|
|
150
141
|
|
|
151
|
-
// ── Agent-facing API wrappers ─────────────────────────────────────
|
|
152
|
-
|
|
153
|
-
async setTitle(groupId: number, userId: number, title: string, duration = -1): Promise<boolean> {
|
|
154
|
-
await this.callApi('set_group_special_title', {
|
|
155
|
-
group_id: groupId,
|
|
156
|
-
user_id: userId,
|
|
157
|
-
special_title: title,
|
|
158
|
-
duration,
|
|
159
|
-
});
|
|
160
|
-
return true;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
sendLike(userId: number, times = 1) {
|
|
164
|
-
return this.callApi('send_like', { user_id: userId, times });
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
deleteFriend(userId: number) {
|
|
168
|
-
return this.callApi('delete_friend', { user_id: userId });
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
markMsgAsRead(messageId: number) {
|
|
172
|
-
return this.callApi('mark_msg_as_read', { message_id: messageId });
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
ocrImage(image: string) {
|
|
176
|
-
return this.callApi('ocr_image', { image });
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
setQQProfile(
|
|
180
|
-
nickname: string,
|
|
181
|
-
company?: string,
|
|
182
|
-
email?: string,
|
|
183
|
-
college?: string,
|
|
184
|
-
personalNote?: string,
|
|
185
|
-
) {
|
|
186
|
-
return this.callApi('set_qq_profile', {
|
|
187
|
-
nickname,
|
|
188
|
-
company,
|
|
189
|
-
email,
|
|
190
|
-
college,
|
|
191
|
-
personal_note: personalNote,
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
setGroupPortrait(groupId: number, file: string) {
|
|
196
|
-
return this.callApi('set_group_portrait', { group_id: groupId, file });
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
setEssenceMsg(messageId: number) {
|
|
200
|
-
return this.callApi('set_essence_msg', { message_id: messageId });
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
deleteEssenceMsg(messageId: number) {
|
|
204
|
-
return this.callApi('delete_essence_msg', { message_id: messageId });
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
getEssenceMsgList(groupId: number) {
|
|
208
|
-
return this.callApi('get_essence_msg_list', { group_id: groupId });
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
sendGroupSign(groupId: number) {
|
|
212
|
-
return this.callApi('send_group_sign', { group_id: groupId });
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
sendGroupNotice(groupId: number, content: string, image?: string) {
|
|
216
|
-
return this.callApi('_send_group_notice', { group_id: groupId, content, image });
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
getGroupNotice(groupId: number) {
|
|
220
|
-
return this.callApi('_get_group_notice', { group_id: groupId });
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
deleteGroupNotice(groupId: number, noticeId: string) {
|
|
224
|
-
return this.callApi('_del_group_notice', { group_id: groupId, notice_id: noticeId });
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
uploadGroupFile(groupId: number, file: string, name: string, folder?: string) {
|
|
228
|
-
return this.callApi('upload_group_file', { group_id: groupId, file, name, folder });
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
getGroupRootFiles(groupId: number) {
|
|
232
|
-
return this.callApi('get_group_root_files', { group_id: groupId });
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
getGroupFileUrl(groupId: number, fileId: string, busid: number) {
|
|
236
|
-
return this.callApi('get_group_file_url', { group_id: groupId, file_id: fileId, busid });
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
downloadFile(url: string, threadCount = 1, headers?: string[]) {
|
|
240
|
-
return this.callApi('download_file', { url, thread_count: threadCount, headers });
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
setOnlineStatus(status: number, extStatus: number) {
|
|
244
|
-
return this.callApi('set_online_status', { status, ext_status: extStatus });
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
setQQAvatar(file: string) {
|
|
248
|
-
return this.callApi('set_qq_avatar', { file });
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
forwardFriendSingleMsg(userId: number, messageId: number) {
|
|
252
|
-
return this.callApi('forward_friend_single_msg', { user_id: userId, message_id: messageId });
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
forwardGroupSingleMsg(groupId: number, messageId: number) {
|
|
256
|
-
return this.callApi('forward_group_single_msg', { group_id: groupId, message_id: messageId });
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
translateEn2Zh(sourceText: string) {
|
|
260
|
-
return this.callApi('translate_en2zh', { source_text: sourceText });
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
setMsgEmojiLike(messageId: number, emojiId: string) {
|
|
264
|
-
return this.callApi('set_msg_emoji_like', { message_id: messageId, emoji_id: emojiId });
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
sendForwardMsg(messageType: 'private' | 'group', id: number, messages: unknown[]) {
|
|
268
|
-
return this.callApi('send_forward_msg', {
|
|
269
|
-
message_type: messageType,
|
|
270
|
-
[messageType === 'group' ? 'group_id' : 'user_id']: id,
|
|
271
|
-
messages,
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
getFriendMsgHistory(userId: number, messageSeq?: number, count?: number) {
|
|
276
|
-
return this.callApi('get_friend_msg_history', {
|
|
277
|
-
user_id: userId,
|
|
278
|
-
message_seq: messageSeq,
|
|
279
|
-
count,
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
getGroupMsgHistory(groupId: number, messageSeq?: number, count?: number) {
|
|
284
|
-
return this.callApi('get_group_msg_history', {
|
|
285
|
-
group_id: groupId,
|
|
286
|
-
message_seq: messageSeq,
|
|
287
|
-
count,
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
setSelfLongnick(longnick: string) {
|
|
292
|
-
return this.callApi('set_self_longnick', { longNick: longnick });
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
getGroupInfoEx(groupId: number) {
|
|
296
|
-
return this.callApi('get_group_info_ex', { group_id: groupId });
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
sendPoke(userId: number, groupId?: number) {
|
|
300
|
-
return this.callApi('send_poke', { user_id: userId, group_id: groupId });
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
ncGetUserStatus(userId: number) {
|
|
304
|
-
return this.callApi('nc_get_user_status', { user_id: userId });
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
getGroupShutList(groupId: number) {
|
|
308
|
-
return this.callApi('get_group_shut_list', { group_id: groupId });
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
getMiniAppArk(type: string, title: string, desc: string, picUrl: string, jumpUrl: string) {
|
|
312
|
-
return this.callApi('get_mini_app_ark', { type, title, desc, picUrl, jumpUrl });
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
getAiCharacters(groupId: number) {
|
|
316
|
-
return this.callApi('get_ai_characters', { group_id: groupId });
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
sendGroupAiRecord(groupId: number, characterId: string, text: string) {
|
|
320
|
-
return this.callApi('send_group_ai_record', {
|
|
321
|
-
group_id: groupId,
|
|
322
|
-
character: characterId,
|
|
323
|
-
text,
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
|
|
327
142
|
/** Test / internal: admit a parsed event when the endpoint is open. */
|
|
328
143
|
admit(ev: NapCatEvent): void {
|
|
329
144
|
if (!this.#open) return;
|
|
145
|
+
void this.emitPlatform(napCatPlatformEventName(ev), ev).catch((error) => {
|
|
146
|
+
this.#logger.warn(formatCompact({
|
|
147
|
+
op: 'napcat_platform_event_failed',
|
|
148
|
+
error: error instanceof Error ? error.message : String(error),
|
|
149
|
+
}));
|
|
150
|
+
});
|
|
330
151
|
if (!isMessageEvent(ev)) {
|
|
331
152
|
receiveNapCatSideEvent(
|
|
332
|
-
this
|
|
153
|
+
(name, payload) => this.emit(name, payload),
|
|
333
154
|
this.#options.config.id,
|
|
334
|
-
this,
|
|
155
|
+
this.client,
|
|
335
156
|
ev,
|
|
336
157
|
this.#logger,
|
|
337
158
|
);
|
|
@@ -347,7 +168,7 @@ export class NapCatWsEndpoint implements EndpointInstance {
|
|
|
347
168
|
const content = formatInboundContent(ev);
|
|
348
169
|
const nickname = senderNickname(ev);
|
|
349
170
|
const mentioned = isNapCatBotMentioned(ev);
|
|
350
|
-
void this
|
|
171
|
+
void this.emit('message.receive', {
|
|
351
172
|
conversation,
|
|
352
173
|
message: { conversation, id: msgId },
|
|
353
174
|
content,
|
|
@@ -472,3 +293,9 @@ export class NapCatWsEndpoint implements EndpointInstance {
|
|
|
472
293
|
});
|
|
473
294
|
}
|
|
474
295
|
}
|
|
296
|
+
|
|
297
|
+
function napCatPlatformEventName(ev: NapCatEvent): string {
|
|
298
|
+
return [ev.post_type, ev.message_type ?? ev.notice_type ?? ev.request_type, ev.sub_type]
|
|
299
|
+
.filter(Boolean)
|
|
300
|
+
.join('.');
|
|
301
|
+
}
|