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