@zhin.js/adapter-napcat 7.0.0 → 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.
Files changed (60) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +18 -3
  3. package/adapters/napcat.js +1 -8
  4. package/adapters/napcat.ts +1 -8
  5. package/agent/tools/ai_tts.ts +4 -6
  6. package/agent/tools/del_group_notice.ts +4 -6
  7. package/agent/tools/delete_essence_msg.ts +4 -6
  8. package/agent/tools/delete_friend.ts +4 -6
  9. package/agent/tools/download_file.ts +4 -6
  10. package/agent/tools/forward_single_msg.ts +4 -8
  11. package/agent/tools/get_ai_characters.ts +4 -6
  12. package/agent/tools/get_essence_list.ts +4 -6
  13. package/agent/tools/get_friend_msg_history.ts +4 -6
  14. package/agent/tools/get_group_file_url.ts +4 -6
  15. package/agent/tools/get_group_info_ex.ts +4 -6
  16. package/agent/tools/get_group_msg_history.ts +4 -6
  17. package/agent/tools/get_group_notice.ts +4 -6
  18. package/agent/tools/get_group_root_files.ts +4 -6
  19. package/agent/tools/get_group_shut_list.ts +4 -6
  20. package/agent/tools/get_mini_app_ark.ts +4 -6
  21. package/agent/tools/get_user_status.ts +4 -6
  22. package/agent/tools/group_sign.ts +4 -6
  23. package/agent/tools/mark_msg_as_read.ts +4 -6
  24. package/agent/tools/ocr_image.ts +4 -6
  25. package/agent/tools/send_forward_msg.ts +4 -8
  26. package/agent/tools/send_group_notice.ts +4 -6
  27. package/agent/tools/send_like.ts +4 -6
  28. package/agent/tools/send_poke.ts +4 -6
  29. package/agent/tools/set_avatar.ts +4 -6
  30. package/agent/tools/set_emoji_reaction.ts +4 -6
  31. package/agent/tools/set_essence_msg.ts +4 -6
  32. package/agent/tools/set_group_portrait.ts +4 -6
  33. package/agent/tools/set_online_status.ts +4 -6
  34. package/agent/tools/set_profile.ts +4 -6
  35. package/agent/tools/set_signature.ts +4 -6
  36. package/agent/tools/set_title.ts +4 -6
  37. package/agent/tools/translate.ts +4 -6
  38. package/agent/tools/upload_group_file.ts +4 -6
  39. package/lib/{napcat-agent-deps.d.ts → client.d.ts} +15 -14
  40. package/lib/client.js +62 -0
  41. package/lib/http-endpoint.d.ts +5 -6
  42. package/lib/http-endpoint.js +22 -12
  43. package/lib/index.d.ts +1 -1
  44. package/lib/index.js +1 -1
  45. package/lib/napcat-endpoint-commands.d.ts +1 -1
  46. package/lib/side-event-dispatch.d.ts +2 -2
  47. package/lib/side-event-dispatch.js +3 -3
  48. package/lib/ws-endpoint.d.ts +5 -41
  49. package/lib/ws-endpoint.js +24 -156
  50. package/lib/wss-endpoint.d.ts +5 -6
  51. package/lib/wss-endpoint.js +23 -13
  52. package/package.json +15 -14
  53. package/src/client.ts +79 -0
  54. package/src/http-endpoint.ts +24 -20
  55. package/src/index.ts +4 -7
  56. package/src/side-event-dispatch.ts +4 -4
  57. package/src/ws-endpoint.ts +26 -202
  58. package/src/wss-endpoint.ts +25 -21
  59. package/lib/napcat-agent-deps.js +0 -33
  60. package/src/napcat-agent-deps.ts +0 -95
@@ -1,26 +1,28 @@
1
+ import { Endpoint } from 'zhin.js/adapter';
1
2
  import { createRecallEndpointControl, } from 'zhin.js/adapter';
2
3
  import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
3
4
  import { createNapCatEndpointManagement } from './endpoint-management.js';
4
- import { registerNapcatAgentEndpoint } from './napcat-agent-deps.js';
5
5
  import { InboundMessageDeduper, isNapCatBotMentioned, isSelfMessage, normalizeMessage, } from './napcat-inbound.js';
6
6
  import { buildSendAction, callNapCatHttpAction, formatInboundContent, formatOutboundSegments, isMessageEvent, napcatInboundConversation, napcatOutboundTarget, senderNickname, senderUserId, } from './protocol.js';
7
7
  import { receiveNapCatSideEvent } from './side-event-dispatch.js';
8
8
  import { createNapCatContentPort } from './onebot-get-msg.js';
9
+ import { NapcatClient } from './client.js';
9
10
  import { readRequestBody } from './webhook.js';
10
11
  import { verifyNapCatAccessToken } from './wss-auth.js';
11
- export class NapCatHttpEndpoint {
12
+ export class NapCatHttpEndpoint extends Endpoint {
13
+ client = new NapcatClient((action, params) => this.#callApi(action, params));
12
14
  #logger;
13
15
  #options;
14
16
  #inboundDeduper = new InboundMessageDeduper();
15
- management = createNapCatEndpointManagement(this);
17
+ management = createNapCatEndpointManagement(this.client);
16
18
  control = createRecallEndpointControl((id) => this.recallMessage(id));
17
- content = createNapCatContentPort((action, params) => this.callApi(action, params));
19
+ content = createNapCatContentPort((action, params) => this.client.callApi(action, params));
18
20
  #callHttpAction;
19
21
  #routeReleases = [];
20
22
  #open = false;
21
23
  #started = false;
22
- #unregisterAgent;
23
24
  constructor(options) {
25
+ super();
24
26
  this.#logger = getAdapterLogger('napcat', options.config.id);
25
27
  this.#options = options;
26
28
  this.#callHttpAction = options.callHttpAction ?? callNapCatHttpAction;
@@ -29,7 +31,6 @@ export class NapCatHttpEndpoint {
29
31
  if (this.#started)
30
32
  return;
31
33
  this.#started = true;
32
- this.#unregisterAgent = registerNapcatAgentEndpoint(this.#options.config.id, this);
33
34
  this.#setupRoutes();
34
35
  this.#logger.info(formatCompact({
35
36
  op: 'listen',
@@ -48,8 +49,6 @@ export class NapCatHttpEndpoint {
48
49
  this.#open = false;
49
50
  for (const release of this.#routeReleases.splice(0))
50
51
  release();
51
- this.#unregisterAgent?.();
52
- this.#unregisterAgent = undefined;
53
52
  this.#inboundDeduper.clear();
54
53
  this.#started = false;
55
54
  this.#logger.debug(formatCompact({ op: 'disconnect' }));
@@ -74,9 +73,9 @@ export class NapCatHttpEndpoint {
74
73
  async recallMessage(messageId) {
75
74
  if (!messageId)
76
75
  return;
77
- await this.callApi('delete_msg', { message_id: Number(messageId) });
76
+ await this.client.callApi('delete_msg', { message_id: Number(messageId) });
78
77
  }
79
- callApi(action, params = {}) {
78
+ #callApi(action, params = {}) {
80
79
  return this.#callHttpAction({
81
80
  http_url: this.#options.config.http_url,
82
81
  access_token: this.#options.config.access_token,
@@ -85,8 +84,14 @@ export class NapCatHttpEndpoint {
85
84
  admit(ev) {
86
85
  if (!this.#open)
87
86
  return;
87
+ void this.emitPlatform(napCatPlatformEventName(ev), ev).catch((error) => {
88
+ this.#logger.warn(formatCompact({
89
+ op: 'napcat_platform_event_failed',
90
+ error: error instanceof Error ? error.message : String(error),
91
+ }));
92
+ });
88
93
  if (!isMessageEvent(ev)) {
89
- receiveNapCatSideEvent(this.#options.sideEvents, this.#options.config.id, this, ev, this.#logger);
94
+ receiveNapCatSideEvent((name, payload) => this.emit(name, payload), this.#options.config.id, this.client, ev, this.#logger);
90
95
  return;
91
96
  }
92
97
  if (isSelfMessage(ev))
@@ -100,7 +105,7 @@ export class NapCatHttpEndpoint {
100
105
  const conversation = napcatInboundConversation(String(this.#options.id), ev);
101
106
  const nickname = senderNickname(ev);
102
107
  const mentioned = isNapCatBotMentioned(ev);
103
- void this.#options.gateway.receive({
108
+ void this.emit('message.receive', {
104
109
  conversation,
105
110
  message: { conversation, id: msgId },
106
111
  content: formatInboundContent(ev),
@@ -165,3 +170,8 @@ export class NapCatHttpEndpoint {
165
170
  }
166
171
  }
167
172
  }
173
+ function napCatPlatformEventName(ev) {
174
+ return [ev.post_type, ev.message_type ?? ev.notice_type ?? ev.request_type, ev.sub_type]
175
+ .filter(Boolean)
176
+ .join('.');
177
+ }
package/lib/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { buildSendAction, buildWsConnectOptions, callNapCatHttpAction, formatInboundContent, formatOutboundSegments, getChannelId, isMessageEvent, mediaRefToOneBotFile, napcatInboundConversation, napcatOutboundTarget, resolveNapCatConfig, senderNickname, senderUserId, type MessageSegment, type NapCatActionRequest, type NapCatActionResponse, type NapCatAdapterConfig, type NapCatConfigBase, type NapCatEndpointConfig, type NapCatEvent, type NapCatHttpConfig, type NapCatMessageEvent, type NapCatSender, type NapCatWireSegment, type NapCatWsConfig, type NapCatWssConfig, type ParsedSendTarget, type ResolvedNapCatConfig, } from './protocol.js';
2
2
  export { InboundMessageDeduper, isNapCatBotMentioned, isSelfMessage, normalizeMessage, } from './napcat-inbound.js';
3
- export { getEndpoint, getNapcatAgentDeps, registerNapcatAgentEndpoint, setNapcatAgentDeps, type NapcatAgentDeps, type NapcatAgentEndpoint, } from './napcat-agent-deps.js';
3
+ export { napcatClient, type NapcatClient, type NapcatClientEventMap, } from './client.js';
4
4
  export { parseOneBotGetMsgResponse } from './onebot-get-msg.js';
5
5
  export { NapCatWsEndpoint, type NapCatWsEndpointOptions, } from './ws-endpoint.js';
6
6
  export { NapCatWssEndpoint, type NapCatWssEndpointOptions, } from './wss-endpoint.js';
package/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export { buildSendAction, buildWsConnectOptions, callNapCatHttpAction, formatInboundContent, formatOutboundSegments, getChannelId, isMessageEvent, mediaRefToOneBotFile, napcatInboundConversation, napcatOutboundTarget, resolveNapCatConfig, senderNickname, senderUserId, } from './protocol.js';
2
2
  export { InboundMessageDeduper, isNapCatBotMentioned, isSelfMessage, normalizeMessage, } from './napcat-inbound.js';
3
- export { getEndpoint, getNapcatAgentDeps, registerNapcatAgentEndpoint, setNapcatAgentDeps, } from './napcat-agent-deps.js';
3
+ export { napcatClient, } from './client.js';
4
4
  export { parseOneBotGetMsgResponse } from './onebot-get-msg.js';
5
5
  export { NapCatWsEndpoint, } from './ws-endpoint.js';
6
6
  export { NapCatWssEndpoint, } from './wss-endpoint.js';
@@ -1 +1 @@
1
- export declare const napcatEndpointCommands: import("@zhin.js/adapter").EndpointCommands<Readonly<import("@zhin.js/command").CommandDefinition<unknown, unknown, import("@zhin.js/command").CommandMessage>>>;
1
+ export declare const napcatEndpointCommands: import("@zhin.js/adapter").EndpointCommands<Readonly<import("@zhin.js/command").CommandDefinition<unknown, unknown, import("@zhin.js/command").CommandMessage, string | undefined>>>;
@@ -1,7 +1,7 @@
1
- import type { SideEventGateway } from '@zhin.js/core/runtime';
1
+ import type { EndpointEventEmitter } from 'zhin.js/adapter';
2
2
  import { type getAdapterLogger } from '@zhin.js/logger';
3
3
  import type { NapCatEvent } from './protocol.js';
4
4
  export interface NapCatSideEventCaller {
5
5
  callApi(action: string, params?: Record<string, unknown>): Promise<unknown>;
6
6
  }
7
- export declare function receiveNapCatSideEvent(sideEvents: SideEventGateway | undefined, endpointKey: string, caller: NapCatSideEventCaller, raw: NapCatEvent, logger: ReturnType<typeof getAdapterLogger>): void;
7
+ export declare function receiveNapCatSideEvent(emit: EndpointEventEmitter, endpointKey: string, caller: NapCatSideEventCaller, raw: NapCatEvent, logger: ReturnType<typeof getAdapterLogger>): void;
@@ -1,14 +1,14 @@
1
1
  import { receiveOneBotLikeSideEvent } from '@zhin.js/core';
2
2
  import { formatCompact } from '@zhin.js/logger';
3
- export function receiveNapCatSideEvent(sideEvents, endpointKey, caller, raw, logger) {
4
- if (!sideEvents)
3
+ export function receiveNapCatSideEvent(emit, endpointKey, caller, raw, logger) {
4
+ if (!emit)
5
5
  return;
6
6
  const record = raw;
7
7
  const postType = String(record.post_type ?? '');
8
8
  const requestType = String(record.request_type ?? '');
9
9
  const isRequest = postType === 'request' || postType.startsWith('request.');
10
10
  const isFriend = requestType === 'friend' || postType.includes('friend');
11
- void receiveOneBotLikeSideEvent(sideEvents, {
11
+ void receiveOneBotLikeSideEvent(emit, {
12
12
  adapter: 'napcat',
13
13
  endpointKey,
14
14
  platform: 'napcat',
@@ -1,17 +1,17 @@
1
- import { type EndpointControl, type EndpointInstance, type EndpointManagement, type EndpointSendRequest } from 'zhin.js/adapter';
2
- import type { MessageGateway, SideEventGateway } from '@zhin.js/core/runtime';
1
+ import { Endpoint } from 'zhin.js/adapter';
2
+ import { type EndpointControl, type EndpointManagement, type EndpointSendRequest } from 'zhin.js/adapter';
3
3
  import type { CapabilityId } from 'zhin.js';
4
4
  import { type NapCatEvent, type NapCatWsConfig } from './protocol.js';
5
5
  import { type NapCatWsCreateOptions, type NapCatWsSocket } from './ws-types.js';
6
+ import { NapcatClient } from './client.js';
6
7
  export interface NapCatWsEndpointOptions {
7
8
  readonly id: CapabilityId;
8
- readonly gateway: MessageGateway;
9
- readonly sideEvents?: SideEventGateway;
10
9
  readonly config: NapCatWsConfig;
11
10
  readonly createWebSocket?: (url: string, options: NapCatWsCreateOptions) => NapCatWsSocket;
12
11
  }
13
- export declare class NapCatWsEndpoint implements EndpointInstance {
12
+ export declare class NapCatWsEndpoint extends Endpoint<NapcatClient> {
14
13
  #private;
14
+ readonly client: NapcatClient;
15
15
  readonly management: EndpointManagement;
16
16
  readonly control: EndpointControl;
17
17
  readonly content: import("@zhin.js/adapter").EndpointContentPort;
@@ -22,42 +22,6 @@ export declare class NapCatWsEndpoint implements EndpointInstance {
22
22
  stop(): Promise<void>;
23
23
  send({ conversation, payload }: EndpointSendRequest): Promise<string>;
24
24
  recallMessage(messageId: string): Promise<void>;
25
- callApi(action: string, params?: Record<string, unknown>): Promise<unknown>;
26
- setTitle(groupId: number, userId: number, title: string, duration?: number): Promise<boolean>;
27
- sendLike(userId: number, times?: number): Promise<unknown>;
28
- deleteFriend(userId: number): Promise<unknown>;
29
- markMsgAsRead(messageId: number): Promise<unknown>;
30
- ocrImage(image: string): Promise<unknown>;
31
- setQQProfile(nickname: string, company?: string, email?: string, college?: string, personalNote?: string): Promise<unknown>;
32
- setGroupPortrait(groupId: number, file: string): Promise<unknown>;
33
- setEssenceMsg(messageId: number): Promise<unknown>;
34
- deleteEssenceMsg(messageId: number): Promise<unknown>;
35
- getEssenceMsgList(groupId: number): Promise<unknown>;
36
- sendGroupSign(groupId: number): Promise<unknown>;
37
- sendGroupNotice(groupId: number, content: string, image?: string): Promise<unknown>;
38
- getGroupNotice(groupId: number): Promise<unknown>;
39
- deleteGroupNotice(groupId: number, noticeId: string): Promise<unknown>;
40
- uploadGroupFile(groupId: number, file: string, name: string, folder?: string): Promise<unknown>;
41
- getGroupRootFiles(groupId: number): Promise<unknown>;
42
- getGroupFileUrl(groupId: number, fileId: string, busid: number): Promise<unknown>;
43
- downloadFile(url: string, threadCount?: number, headers?: string[]): Promise<unknown>;
44
- setOnlineStatus(status: number, extStatus: number): Promise<unknown>;
45
- setQQAvatar(file: string): Promise<unknown>;
46
- forwardFriendSingleMsg(userId: number, messageId: number): Promise<unknown>;
47
- forwardGroupSingleMsg(groupId: number, messageId: number): Promise<unknown>;
48
- translateEn2Zh(sourceText: string): Promise<unknown>;
49
- setMsgEmojiLike(messageId: number, emojiId: string): Promise<unknown>;
50
- sendForwardMsg(messageType: 'private' | 'group', id: number, messages: unknown[]): Promise<unknown>;
51
- getFriendMsgHistory(userId: number, messageSeq?: number, count?: number): Promise<unknown>;
52
- getGroupMsgHistory(groupId: number, messageSeq?: number, count?: number): Promise<unknown>;
53
- setSelfLongnick(longnick: string): Promise<unknown>;
54
- getGroupInfoEx(groupId: number): Promise<unknown>;
55
- sendPoke(userId: number, groupId?: number): Promise<unknown>;
56
- ncGetUserStatus(userId: number): Promise<unknown>;
57
- getGroupShutList(groupId: number): Promise<unknown>;
58
- getMiniAppArk(type: string, title: string, desc: string, picUrl: string, jumpUrl: string): Promise<unknown>;
59
- getAiCharacters(groupId: number): Promise<unknown>;
60
- sendGroupAiRecord(groupId: number, characterId: string, text: string): Promise<unknown>;
61
25
  /** Test / internal: admit a parsed event when the endpoint is open. */
62
26
  admit(ev: NapCatEvent): void;
63
27
  }
@@ -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
  */
@@ -5,26 +6,27 @@ import WebSocket from 'ws';
5
6
  import { createRecallEndpointControl, createEndpointLifecycle, } from 'zhin.js/adapter';
6
7
  import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
7
8
  import { createNapCatEndpointManagement } from './endpoint-management.js';
8
- import { registerNapcatAgentEndpoint } from './napcat-agent-deps.js';
9
9
  import { InboundMessageDeduper, isNapCatBotMentioned, isSelfMessage, normalizeMessage, } from './napcat-inbound.js';
10
10
  import { buildSendAction, buildWsConnectOptions, formatInboundContent, formatOutboundSegments, isMessageEvent, napcatInboundConversation, napcatOutboundTarget, senderNickname, senderUserId, } from './protocol.js';
11
11
  import { receiveNapCatSideEvent } from './side-event-dispatch.js';
12
12
  import { callNapCatWsAction, handleNapCatWsMessage, rejectAllPending, } from './ws-transport.js';
13
13
  import { createNapCatContentPort } from './onebot-get-msg.js';
14
- export class NapCatWsEndpoint {
14
+ import { NapcatClient } from './client.js';
15
+ export class NapCatWsEndpoint extends Endpoint {
16
+ client = new NapcatClient((action, params) => this.#callApi(action, params));
15
17
  #logger;
16
18
  #options;
17
19
  #inboundDeduper = new InboundMessageDeduper();
18
- management = createNapCatEndpointManagement(this);
20
+ management = createNapCatEndpointManagement(this.client);
19
21
  control = createRecallEndpointControl((id) => this.recallMessage(id));
20
- content = createNapCatContentPort((action, params) => this.callApi(action, params));
22
+ content = createNapCatContentPort((action, params) => this.client.callApi(action, params));
21
23
  #lifecycle;
22
24
  #ws;
23
25
  #requestId = { value: 0 };
24
26
  #pending = new Map();
25
27
  #open = false;
26
- #unregisterAgent;
27
28
  constructor(options) {
29
+ super();
28
30
  this.#logger = getAdapterLogger('napcat', options.config.id);
29
31
  this.#options = options;
30
32
  this.#lifecycle = createEndpointLifecycle({
@@ -41,16 +43,7 @@ export class NapCatWsEndpoint {
41
43
  async start() {
42
44
  if (this.#lifecycle.started)
43
45
  return;
44
- this.#unregisterAgent = registerNapcatAgentEndpoint(this.#options.config.id, this);
45
- try {
46
- await this.#lifecycle.start((handle) => this.#connect(handle));
47
- }
48
- catch (err) {
49
- // start 失败复位由基座保证;agent 注册/反注册是适配器专有依赖,留在适配器侧
50
- this.#unregisterAgent?.();
51
- this.#unregisterAgent = undefined;
52
- throw err;
53
- }
46
+ await this.#lifecycle.start((handle) => this.#connect(handle));
54
47
  }
55
48
  open() {
56
49
  this.#open = true;
@@ -61,8 +54,6 @@ export class NapCatWsEndpoint {
61
54
  async stop() {
62
55
  this.#open = false;
63
56
  await this.#lifecycle.stop();
64
- this.#unregisterAgent?.();
65
- this.#unregisterAgent = undefined;
66
57
  rejectAllPending(this.#pending);
67
58
  this.#inboundDeduper.clear();
68
59
  if (this.#ws) {
@@ -78,7 +69,7 @@ export class NapCatWsEndpoint {
78
69
  async send({ conversation, payload }) {
79
70
  const message = formatOutboundSegments(payload);
80
71
  const { action, params } = buildSendAction(napcatOutboundTarget(conversation), message);
81
- const data = await this.callApi(action, params);
72
+ const data = await this.client.callApi(action, params);
82
73
  const messageId = data?.message_id != null ? String(data.message_id) : '';
83
74
  this.#logger.debug(formatCompact({
84
75
  op: 'napcat_send',
@@ -91,151 +82,23 @@ export class NapCatWsEndpoint {
91
82
  async recallMessage(messageId) {
92
83
  if (!messageId)
93
84
  return;
94
- await this.callApi('delete_msg', { message_id: Number(messageId) });
85
+ await this.client.callApi('delete_msg', { message_id: Number(messageId) });
95
86
  }
96
- callApi(action, params = {}) {
87
+ #callApi(action, params = {}) {
97
88
  return callNapCatWsAction(this.#ws, this.#pending, this.#requestId, action, params);
98
89
  }
99
- // ── Agent-facing API wrappers ─────────────────────────────────────
100
- async setTitle(groupId, userId, title, duration = -1) {
101
- await this.callApi('set_group_special_title', {
102
- group_id: groupId,
103
- user_id: userId,
104
- special_title: title,
105
- duration,
106
- });
107
- return true;
108
- }
109
- sendLike(userId, times = 1) {
110
- return this.callApi('send_like', { user_id: userId, times });
111
- }
112
- deleteFriend(userId) {
113
- return this.callApi('delete_friend', { user_id: userId });
114
- }
115
- markMsgAsRead(messageId) {
116
- return this.callApi('mark_msg_as_read', { message_id: messageId });
117
- }
118
- ocrImage(image) {
119
- return this.callApi('ocr_image', { image });
120
- }
121
- setQQProfile(nickname, company, email, college, personalNote) {
122
- return this.callApi('set_qq_profile', {
123
- nickname,
124
- company,
125
- email,
126
- college,
127
- personal_note: personalNote,
128
- });
129
- }
130
- setGroupPortrait(groupId, file) {
131
- return this.callApi('set_group_portrait', { group_id: groupId, file });
132
- }
133
- setEssenceMsg(messageId) {
134
- return this.callApi('set_essence_msg', { message_id: messageId });
135
- }
136
- deleteEssenceMsg(messageId) {
137
- return this.callApi('delete_essence_msg', { message_id: messageId });
138
- }
139
- getEssenceMsgList(groupId) {
140
- return this.callApi('get_essence_msg_list', { group_id: groupId });
141
- }
142
- sendGroupSign(groupId) {
143
- return this.callApi('send_group_sign', { group_id: groupId });
144
- }
145
- sendGroupNotice(groupId, content, image) {
146
- return this.callApi('_send_group_notice', { group_id: groupId, content, image });
147
- }
148
- getGroupNotice(groupId) {
149
- return this.callApi('_get_group_notice', { group_id: groupId });
150
- }
151
- deleteGroupNotice(groupId, noticeId) {
152
- return this.callApi('_del_group_notice', { group_id: groupId, notice_id: noticeId });
153
- }
154
- uploadGroupFile(groupId, file, name, folder) {
155
- return this.callApi('upload_group_file', { group_id: groupId, file, name, folder });
156
- }
157
- getGroupRootFiles(groupId) {
158
- return this.callApi('get_group_root_files', { group_id: groupId });
159
- }
160
- getGroupFileUrl(groupId, fileId, busid) {
161
- return this.callApi('get_group_file_url', { group_id: groupId, file_id: fileId, busid });
162
- }
163
- downloadFile(url, threadCount = 1, headers) {
164
- return this.callApi('download_file', { url, thread_count: threadCount, headers });
165
- }
166
- setOnlineStatus(status, extStatus) {
167
- return this.callApi('set_online_status', { status, ext_status: extStatus });
168
- }
169
- setQQAvatar(file) {
170
- return this.callApi('set_qq_avatar', { file });
171
- }
172
- forwardFriendSingleMsg(userId, messageId) {
173
- return this.callApi('forward_friend_single_msg', { user_id: userId, message_id: messageId });
174
- }
175
- forwardGroupSingleMsg(groupId, messageId) {
176
- return this.callApi('forward_group_single_msg', { group_id: groupId, message_id: messageId });
177
- }
178
- translateEn2Zh(sourceText) {
179
- return this.callApi('translate_en2zh', { source_text: sourceText });
180
- }
181
- setMsgEmojiLike(messageId, emojiId) {
182
- return this.callApi('set_msg_emoji_like', { message_id: messageId, emoji_id: emojiId });
183
- }
184
- sendForwardMsg(messageType, id, messages) {
185
- return this.callApi('send_forward_msg', {
186
- message_type: messageType,
187
- [messageType === 'group' ? 'group_id' : 'user_id']: id,
188
- messages,
189
- });
190
- }
191
- getFriendMsgHistory(userId, messageSeq, count) {
192
- return this.callApi('get_friend_msg_history', {
193
- user_id: userId,
194
- message_seq: messageSeq,
195
- count,
196
- });
197
- }
198
- getGroupMsgHistory(groupId, messageSeq, count) {
199
- return this.callApi('get_group_msg_history', {
200
- group_id: groupId,
201
- message_seq: messageSeq,
202
- count,
203
- });
204
- }
205
- setSelfLongnick(longnick) {
206
- return this.callApi('set_self_longnick', { longNick: longnick });
207
- }
208
- getGroupInfoEx(groupId) {
209
- return this.callApi('get_group_info_ex', { group_id: groupId });
210
- }
211
- sendPoke(userId, groupId) {
212
- return this.callApi('send_poke', { user_id: userId, group_id: groupId });
213
- }
214
- ncGetUserStatus(userId) {
215
- return this.callApi('nc_get_user_status', { user_id: userId });
216
- }
217
- getGroupShutList(groupId) {
218
- return this.callApi('get_group_shut_list', { group_id: groupId });
219
- }
220
- getMiniAppArk(type, title, desc, picUrl, jumpUrl) {
221
- return this.callApi('get_mini_app_ark', { type, title, desc, picUrl, jumpUrl });
222
- }
223
- getAiCharacters(groupId) {
224
- return this.callApi('get_ai_characters', { group_id: groupId });
225
- }
226
- sendGroupAiRecord(groupId, characterId, text) {
227
- return this.callApi('send_group_ai_record', {
228
- group_id: groupId,
229
- character: characterId,
230
- text,
231
- });
232
- }
233
90
  /** Test / internal: admit a parsed event when the endpoint is open. */
234
91
  admit(ev) {
235
92
  if (!this.#open)
236
93
  return;
94
+ void this.emitPlatform(napCatPlatformEventName(ev), ev).catch((error) => {
95
+ this.#logger.warn(formatCompact({
96
+ op: 'napcat_platform_event_failed',
97
+ error: error instanceof Error ? error.message : String(error),
98
+ }));
99
+ });
237
100
  if (!isMessageEvent(ev)) {
238
- receiveNapCatSideEvent(this.#options.sideEvents, this.#options.config.id, this, ev, this.#logger);
101
+ receiveNapCatSideEvent((name, payload) => this.emit(name, payload), this.#options.config.id, this.client, ev, this.#logger);
239
102
  return;
240
103
  }
241
104
  if (isSelfMessage(ev))
@@ -250,7 +113,7 @@ export class NapCatWsEndpoint {
250
113
  const content = formatInboundContent(ev);
251
114
  const nickname = senderNickname(ev);
252
115
  const mentioned = isNapCatBotMentioned(ev);
253
- void this.#options.gateway.receive({
116
+ void this.emit('message.receive', {
254
117
  conversation,
255
118
  message: { conversation, id: msgId },
256
119
  content,
@@ -371,3 +234,8 @@ export class NapCatWsEndpoint {
371
234
  });
372
235
  }
373
236
  }
237
+ function napCatPlatformEventName(ev) {
238
+ return [ev.post_type, ev.message_type ?? ev.notice_type ?? ev.request_type, ev.sub_type]
239
+ .filter(Boolean)
240
+ .join('.');
241
+ }
@@ -1,17 +1,17 @@
1
- import { type EndpointControl, type EndpointInstance, type EndpointManagement, type EndpointSendRequest } from 'zhin.js/adapter';
2
- import type { MessageGateway, SideEventGateway } from '@zhin.js/core/runtime';
1
+ import { Endpoint } from 'zhin.js/adapter';
2
+ import { type EndpointControl, type EndpointManagement, type EndpointSendRequest } from 'zhin.js/adapter';
3
3
  import type { HttpHost } from '@zhin.js/host-http';
4
4
  import type { CapabilityId } from 'zhin.js';
5
5
  import { type NapCatEvent, type NapCatWssConfig } from './protocol.js';
6
+ import { NapcatClient } from './client.js';
6
7
  export interface NapCatWssEndpointOptions {
7
8
  readonly id: CapabilityId;
8
- readonly gateway: MessageGateway;
9
- readonly sideEvents?: SideEventGateway;
10
9
  readonly http: HttpHost;
11
10
  readonly config: NapCatWssConfig;
12
11
  }
13
- export declare class NapCatWssEndpoint implements EndpointInstance {
12
+ export declare class NapCatWssEndpoint extends Endpoint<NapcatClient> {
14
13
  #private;
14
+ readonly client: NapcatClient;
15
15
  readonly management: EndpointManagement;
16
16
  readonly control: EndpointControl;
17
17
  readonly content: import("@zhin.js/adapter").EndpointContentPort;
@@ -22,6 +22,5 @@ export declare class NapCatWssEndpoint implements EndpointInstance {
22
22
  stop(): Promise<void>;
23
23
  send({ conversation, payload }: EndpointSendRequest): Promise<string>;
24
24
  recallMessage(messageId: string): Promise<void>;
25
- callApi(action: string, params?: Record<string, unknown>): Promise<unknown>;
26
25
  admit(ev: NapCatEvent): void;
27
26
  }
@@ -1,3 +1,4 @@
1
+ import { Endpoint } from 'zhin.js/adapter';
1
2
  /**
2
3
  * NapCat reverse WSS endpoint — accepts inbound WebSocket from NapCat.
3
4
  */
@@ -5,20 +6,21 @@ import { clearInterval } from 'node:timers';
5
6
  import { createRecallEndpointControl, } from 'zhin.js/adapter';
6
7
  import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
7
8
  import { createNapCatEndpointManagement } from './endpoint-management.js';
8
- import { registerNapcatAgentEndpoint } from './napcat-agent-deps.js';
9
9
  import { InboundMessageDeduper, isNapCatBotMentioned, isSelfMessage, normalizeMessage, } from './napcat-inbound.js';
10
10
  import { buildSendAction, formatInboundContent, formatOutboundSegments, isMessageEvent, napcatInboundConversation, napcatOutboundTarget, senderNickname, senderUserId, } from './protocol.js';
11
11
  import { receiveNapCatSideEvent } from './side-event-dispatch.js';
12
12
  import { createNapCatContentPort } from './onebot-get-msg.js';
13
+ import { NapcatClient } from './client.js';
13
14
  import { callNapCatWsAction, handleNapCatWsMessage, rejectAllPending, startNapCatHeartbeat, } from './ws-transport.js';
14
15
  import { verifyNapCatAccessToken } from './wss-auth.js';
15
- export class NapCatWssEndpoint {
16
+ export class NapCatWssEndpoint extends Endpoint {
17
+ client = new NapcatClient((action, params) => this.#callApi(action, params));
16
18
  #logger;
17
19
  #options;
18
20
  #inboundDeduper = new InboundMessageDeduper();
19
- management = createNapCatEndpointManagement(this);
21
+ management = createNapCatEndpointManagement(this.client);
20
22
  control = createRecallEndpointControl((id) => this.recallMessage(id));
21
- content = createNapCatContentPort((action, params) => this.callApi(action, params));
23
+ content = createNapCatContentPort((action, params) => this.client.callApi(action, params));
22
24
  #ws;
23
25
  #wsRelease;
24
26
  #heartbeatTimer;
@@ -26,8 +28,8 @@ export class NapCatWssEndpoint {
26
28
  #pending = new Map();
27
29
  #open = false;
28
30
  #started = false;
29
- #unregisterAgent;
30
31
  constructor(options) {
32
+ super();
31
33
  this.#logger = getAdapterLogger('napcat', options.config.id);
32
34
  this.#options = options;
33
35
  }
@@ -35,7 +37,6 @@ export class NapCatWssEndpoint {
35
37
  if (this.#started)
36
38
  return;
37
39
  this.#started = true;
38
- this.#unregisterAgent = registerNapcatAgentEndpoint(this.#options.config.id, this);
39
40
  const handle = this.#options.http.ws(this.#options.config.path);
40
41
  this.#wsRelease = handle.onConnection((connection) => {
41
42
  this.#acceptConnection(connection);
@@ -55,8 +56,6 @@ export class NapCatWssEndpoint {
55
56
  }
56
57
  async stop() {
57
58
  this.#open = false;
58
- this.#unregisterAgent?.();
59
- this.#unregisterAgent = undefined;
60
59
  this.#wsRelease?.();
61
60
  this.#wsRelease = undefined;
62
61
  if (this.#heartbeatTimer) {
@@ -79,22 +78,28 @@ export class NapCatWssEndpoint {
79
78
  async send({ conversation, payload }) {
80
79
  const message = formatOutboundSegments(payload);
81
80
  const { action, params } = buildSendAction(napcatOutboundTarget(conversation), message);
82
- const data = await this.callApi(action, params);
81
+ const data = await this.client.callApi(action, params);
83
82
  return data?.message_id != null ? String(data.message_id) : '';
84
83
  }
85
84
  async recallMessage(messageId) {
86
85
  if (!messageId)
87
86
  return;
88
- await this.callApi('delete_msg', { message_id: Number(messageId) });
87
+ await this.client.callApi('delete_msg', { message_id: Number(messageId) });
89
88
  }
90
- callApi(action, params = {}) {
89
+ #callApi(action, params = {}) {
91
90
  return callNapCatWsAction(this.#ws, this.#pending, this.#requestId, action, params);
92
91
  }
93
92
  admit(ev) {
94
93
  if (!this.#open)
95
94
  return;
95
+ void this.emitPlatform(napCatPlatformEventName(ev), ev).catch((error) => {
96
+ this.#logger.warn(formatCompact({
97
+ op: 'napcat_platform_event_failed',
98
+ error: error instanceof Error ? error.message : String(error),
99
+ }));
100
+ });
96
101
  if (!isMessageEvent(ev)) {
97
- receiveNapCatSideEvent(this.#options.sideEvents, this.#options.config.id, this, ev, this.#logger);
102
+ receiveNapCatSideEvent((name, payload) => this.emit(name, payload), this.#options.config.id, this.client, ev, this.#logger);
98
103
  return;
99
104
  }
100
105
  if (isSelfMessage(ev))
@@ -108,7 +113,7 @@ export class NapCatWssEndpoint {
108
113
  const conversation = napcatInboundConversation(String(this.#options.id), ev);
109
114
  const nickname = senderNickname(ev);
110
115
  const mentioned = isNapCatBotMentioned(ev);
111
- void this.#options.gateway.receive({
116
+ void this.emit('message.receive', {
112
117
  conversation,
113
118
  message: { conversation, id: msgId },
114
119
  content: formatInboundContent(ev),
@@ -175,3 +180,8 @@ export class NapCatWssEndpoint {
175
180
  }));
176
181
  }
177
182
  }
183
+ function napCatPlatformEventName(ev) {
184
+ return [ev.post_type, ev.message_type ?? ev.notice_type ?? ev.request_type, ev.sub_type]
185
+ .filter(Boolean)
186
+ .join('.');
187
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/adapter-napcat",
3
- "version": "7.0.0",
3
+ "version": "7.0.1",
4
4
  "description": "Zhin.js NapCat adapter for Plugin Runtime (WebSocket client, OneBot11 + NapCat extensions)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -43,12 +43,13 @@
43
43
  },
44
44
  "dependencies": {
45
45
  "ws": "^8.21.1",
46
- "@zhin.js/adapter": "1.2.0",
47
- "@zhin.js/core": "1.5.13",
48
- "@zhin.js/host-http": "1.0.12",
46
+ "@zhin.js/adapter": "1.2.1",
47
+ "@zhin.js/core": "1.5.14",
48
+ "@zhin.js/feature-kit": "1.0.13",
49
+ "@zhin.js/host-http": "1.0.13",
49
50
  "@zhin.js/im-contract": "1.0.4",
50
- "@zhin.js/logger": "1.0.76",
51
- "@zhin.js/permission": "1.0.3"
51
+ "@zhin.js/logger": "1.0.77",
52
+ "@zhin.js/permission": "1.0.4"
52
53
  },
53
54
  "devDependencies": {
54
55
  "@types/node": "^26.1.2",
@@ -56,17 +57,17 @@
56
57
  "typescript": "^6.0.3",
57
58
  "vitest": "^4.1.10",
58
59
  "zod": "^4.4.3",
59
- "@zhin.js/agent": "1.1.15",
60
- "@zhin.js/host-http": "1.0.12",
61
- "zhin.js": "6.0.13"
60
+ "@zhin.js/agent": "1.1.16",
61
+ "@zhin.js/host-http": "1.0.13",
62
+ "zhin.js": "6.0.14"
62
63
  },
63
64
  "peerDependencies": {
64
65
  "zod": "^4.0.0",
65
- "@zhin.js/adapter": "1.2.0",
66
- "@zhin.js/agent": "1.1.15",
67
- "@zhin.js/command": "1.0.15",
68
- "@zhin.js/core": "1.5.13",
69
- "zhin.js": "6.0.13"
66
+ "@zhin.js/adapter": "1.2.1",
67
+ "@zhin.js/agent": "1.1.16",
68
+ "@zhin.js/command": "1.0.16",
69
+ "@zhin.js/core": "1.5.14",
70
+ "zhin.js": "6.0.14"
70
71
  },
71
72
  "peerDependenciesMeta": {
72
73
  "@zhin.js/agent": {