@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.
Files changed (60) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +18 -3
  3. package/adapters/napcat.js +2 -8
  4. package/adapters/napcat.ts +2 -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 +6 -6
  42. package/lib/http-endpoint.js +24 -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 +6 -41
  49. package/lib/ws-endpoint.js +26 -157
  50. package/lib/wss-endpoint.d.ts +6 -6
  51. package/lib/wss-endpoint.js +25 -13
  52. package/package.json +15 -14
  53. package/src/client.ts +79 -0
  54. package/src/http-endpoint.ts +31 -20
  55. package/src/index.ts +4 -7
  56. package/src/side-event-dispatch.ts +4 -4
  57. package/src/ws-endpoint.ts +29 -202
  58. package/src/wss-endpoint.ts +32 -21
  59. package/lib/napcat-agent-deps.js +0 -33
  60. package/src/napcat-agent-deps.ts +0 -95
@@ -1,14 +1,18 @@
1
+ import { Endpoint } from 'zhin.js/adapter';
1
2
  /**
2
3
  * NapCat reverse WSS endpoint — accepts inbound WebSocket from NapCat.
3
4
  */
4
5
  import { clearInterval } from 'node:timers';
5
- import type { EndpointInstance, EndpointManagement, EndpointSendRequest } from 'zhin.js/adapter';
6
- import type { MessageGateway, SideEventGateway } from '@zhin.js/core/runtime';
6
+ import {
7
+ createRecallEndpointControl,
8
+ type EndpointControl,
9
+ type EndpointManagement,
10
+ type EndpointSendRequest,
11
+ } from 'zhin.js/adapter';
7
12
  import type { HttpHost, WsConnection } 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,
@@ -29,6 +33,7 @@ import {
29
33
  } from './protocol.js';
30
34
  import { receiveNapCatSideEvent } from './side-event-dispatch.js';
31
35
  import { createNapCatContentPort } from './onebot-get-msg.js';
36
+ import { NapcatClient } from './client.js';
32
37
  import {
33
38
  callNapCatWsAction,
34
39
  handleNapCatWsMessage,
@@ -44,19 +49,19 @@ import { verifyNapCatAccessToken } from './wss-auth.js';
44
49
 
45
50
  export interface NapCatWssEndpointOptions {
46
51
  readonly id: CapabilityId;
47
- readonly gateway: MessageGateway;
48
- readonly sideEvents?: SideEventGateway;
49
52
  readonly http: HttpHost;
50
53
  readonly config: NapCatWssConfig;
51
54
  }
52
55
 
53
- export class NapCatWssEndpoint implements EndpointInstance {
56
+ export class NapCatWssEndpoint extends Endpoint<NapcatClient> {
57
+ readonly client = new NapcatClient((action, params) => this.#callApi(action, params));
54
58
  readonly #logger!: ReturnType<typeof getAdapterLogger>;
55
59
 
56
60
  readonly #options: NapCatWssEndpointOptions;
57
61
  readonly #inboundDeduper = new InboundMessageDeduper();
58
- readonly management: EndpointManagement = createNapCatEndpointManagement(this);
59
- readonly content = createNapCatContentPort((action, params) => this.callApi(action, params));
62
+ readonly management: EndpointManagement = createNapCatEndpointManagement(this.client);
63
+ readonly control: EndpointControl = createRecallEndpointControl((id) => this.recallMessage(id));
64
+ readonly content = createNapCatContentPort((action, params) => this.client.callApi(action, params));
60
65
  #ws?: NapCatWsSocket;
61
66
  #wsRelease?: () => void;
62
67
  #heartbeatTimer?: NodeJS.Timeout;
@@ -64,9 +69,9 @@ export class NapCatWssEndpoint implements EndpointInstance {
64
69
  #pending = new Map<string, NapCatPendingAction>();
65
70
  #open = false;
66
71
  #started = false;
67
- #unregisterAgent?: () => void;
68
72
 
69
73
  constructor(options: NapCatWssEndpointOptions) {
74
+ super();
70
75
  this.#logger = getAdapterLogger('napcat', options.config.id);
71
76
  this.#options = options;
72
77
  }
@@ -74,10 +79,6 @@ export class NapCatWssEndpoint implements EndpointInstance {
74
79
  async start(): Promise<void> {
75
80
  if (this.#started) return;
76
81
  this.#started = true;
77
- this.#unregisterAgent = registerNapcatAgentEndpoint(
78
- this.#options.config.id,
79
- this as unknown as NapCatWsEndpoint,
80
- );
81
82
  const handle = this.#options.http.ws(this.#options.config.path);
82
83
  this.#wsRelease = handle.onConnection((connection) => {
83
84
  this.#acceptConnection(connection);
@@ -100,8 +101,6 @@ export class NapCatWssEndpoint implements EndpointInstance {
100
101
 
101
102
  async stop(): Promise<void> {
102
103
  this.#open = false;
103
- this.#unregisterAgent?.();
104
- this.#unregisterAgent = undefined;
105
104
  this.#wsRelease?.();
106
105
  this.#wsRelease = undefined;
107
106
  if (this.#heartbeatTimer) {
@@ -124,26 +123,32 @@ export class NapCatWssEndpoint implements EndpointInstance {
124
123
  async send({ conversation, payload }: EndpointSendRequest): Promise<string> {
125
124
  const message = formatOutboundSegments(payload);
126
125
  const { action, params } = buildSendAction(napcatOutboundTarget(conversation), message);
127
- const data = await this.callApi(action, params) as { message_id?: number | string } | undefined;
126
+ const data = await this.client.callApi(action, params) as { message_id?: number | string } | undefined;
128
127
  return data?.message_id != null ? String(data.message_id) : '';
129
128
  }
130
129
 
131
130
  async recallMessage(messageId: string): Promise<void> {
132
131
  if (!messageId) return;
133
- await this.callApi('delete_msg', { message_id: Number(messageId) });
132
+ await this.client.callApi('delete_msg', { message_id: Number(messageId) });
134
133
  }
135
134
 
136
- callApi(action: string, params: Record<string, unknown> = {}): Promise<unknown> {
135
+ #callApi(action: string, params: Record<string, unknown> = {}): Promise<unknown> {
137
136
  return callNapCatWsAction(this.#ws, this.#pending, this.#requestId, action, params);
138
137
  }
139
138
 
140
139
  admit(ev: NapCatEvent): void {
141
140
  if (!this.#open) return;
141
+ void this.emitPlatform(napCatPlatformEventName(ev), ev).catch((error) => {
142
+ this.#logger.warn(formatCompact({
143
+ op: 'napcat_platform_event_failed',
144
+ error: error instanceof Error ? error.message : String(error),
145
+ }));
146
+ });
142
147
  if (!isMessageEvent(ev)) {
143
148
  receiveNapCatSideEvent(
144
- this.#options.sideEvents,
149
+ (name, payload) => this.emit(name, payload),
145
150
  this.#options.config.id,
146
- this,
151
+ this.client,
147
152
  ev,
148
153
  this.#logger,
149
154
  );
@@ -158,7 +163,7 @@ export class NapCatWssEndpoint implements EndpointInstance {
158
163
  const conversation = napcatInboundConversation(String(this.#options.id), ev);
159
164
  const nickname = senderNickname(ev);
160
165
  const mentioned = isNapCatBotMentioned(ev);
161
- void this.#options.gateway.receive({
166
+ void this.emit('message.receive', {
162
167
  conversation,
163
168
  message: { conversation, id: msgId },
164
169
  content: formatInboundContent(ev),
@@ -229,3 +234,9 @@ export class NapCatWssEndpoint implements EndpointInstance {
229
234
  }));
230
235
  }
231
236
  }
237
+
238
+ function napCatPlatformEventName(ev: NapCatEvent): string {
239
+ return [ev.post_type, ev.message_type ?? ev.notice_type ?? ev.request_type, ev.sub_type]
240
+ .filter(Boolean)
241
+ .join('.');
242
+ }
@@ -1,33 +0,0 @@
1
- /**
2
- * Agent tool deps for napcat.
3
- * Endpoints register themselves on start; tools look up by config name / endpoint id.
4
- */
5
- const endpoints = new Map();
6
- let override = null;
7
- export function registerNapcatAgentEndpoint(endpointKey, endpoint) {
8
- endpoints.set(endpointKey, endpoint);
9
- return () => {
10
- if (endpoints.get(endpointKey) === endpoint) {
11
- endpoints.delete(endpointKey);
12
- }
13
- };
14
- }
15
- /** Optional override used by tests / transitional callers. Pass `null` to clear. */
16
- export function setNapcatAgentDeps(deps) {
17
- override = deps;
18
- }
19
- function lookup(endpointKey) {
20
- const registered = endpoints.get(endpointKey);
21
- if (!registered)
22
- throw new Error(`Endpoint ${endpointKey} not found`);
23
- return registered;
24
- }
25
- export function getNapcatAgentDeps() {
26
- if (override)
27
- return override;
28
- return { getEndpoint: lookup };
29
- }
30
- /** Convenience for agent/tools (unchanged call sites). */
31
- export function getEndpoint(endpointKey) {
32
- return getNapcatAgentDeps().getEndpoint(endpointKey);
33
- }
@@ -1,95 +0,0 @@
1
- /**
2
- * Agent tool deps for napcat.
3
- * Endpoints register themselves on start; tools look up by config name / endpoint id.
4
- */
5
-
6
- export interface NapcatAgentEndpoint {
7
- callApi(action: string, params?: Record<string, unknown>): Promise<unknown>;
8
- setTitle(groupId: number, userId: number, title: string, duration?: number): Promise<boolean>;
9
- sendLike(userId: number, times?: number): Promise<unknown>;
10
- deleteFriend(userId: number): Promise<unknown>;
11
- markMsgAsRead(messageId: number): Promise<unknown>;
12
- ocrImage(image: string): Promise<unknown>;
13
- setQQProfile(
14
- nickname: string,
15
- company?: string,
16
- email?: string,
17
- college?: string,
18
- personalNote?: string,
19
- ): Promise<unknown>;
20
- setGroupPortrait(groupId: number, file: string): Promise<unknown>;
21
- setEssenceMsg(messageId: number): Promise<unknown>;
22
- deleteEssenceMsg(messageId: number): Promise<unknown>;
23
- getEssenceMsgList(groupId: number): Promise<unknown>;
24
- sendGroupSign(groupId: number): Promise<unknown>;
25
- sendGroupNotice(groupId: number, content: string, image?: string): Promise<unknown>;
26
- getGroupNotice(groupId: number): Promise<unknown>;
27
- deleteGroupNotice(groupId: number, noticeId: string): Promise<unknown>;
28
- uploadGroupFile(groupId: number, file: string, name: string, folder?: string): Promise<unknown>;
29
- getGroupRootFiles(groupId: number): Promise<unknown>;
30
- getGroupFileUrl(groupId: number, fileId: string, busid: number): Promise<unknown>;
31
- downloadFile(url: string, threadCount?: number, headers?: string[]): Promise<unknown>;
32
- setOnlineStatus(status: number, extStatus: number): Promise<unknown>;
33
- setQQAvatar(file: string): Promise<unknown>;
34
- forwardFriendSingleMsg(userId: number, messageId: number): Promise<unknown>;
35
- forwardGroupSingleMsg(groupId: number, messageId: number): Promise<unknown>;
36
- translateEn2Zh(sourceText: string): Promise<unknown>;
37
- setMsgEmojiLike(messageId: number, emojiId: string): Promise<unknown>;
38
- sendForwardMsg(messageType: 'private' | 'group', id: number, messages: unknown[]): Promise<unknown>;
39
- getFriendMsgHistory(userId: number, messageSeq?: number, count?: number): Promise<unknown>;
40
- getGroupMsgHistory(groupId: number, messageSeq?: number, count?: number): Promise<unknown>;
41
- setSelfLongnick(longnick: string): Promise<unknown>;
42
- getGroupInfoEx(groupId: number): Promise<unknown>;
43
- sendPoke(userId: number, groupId?: number): Promise<unknown>;
44
- ncGetUserStatus(userId: number): Promise<unknown>;
45
- getGroupShutList(groupId: number): Promise<unknown>;
46
- getMiniAppArk(
47
- type: string,
48
- title: string,
49
- desc: string,
50
- picUrl: string,
51
- jumpUrl: string,
52
- ): Promise<unknown>;
53
- getAiCharacters(groupId: number): Promise<unknown>;
54
- sendGroupAiRecord(groupId: number, characterId: string, text: string): Promise<unknown>;
55
- }
56
-
57
- export interface NapcatAgentDeps {
58
- getEndpoint: (endpointKey: string) => NapcatAgentEndpoint;
59
- }
60
-
61
- const endpoints = new Map<string, NapcatAgentEndpoint>();
62
- let override: NapcatAgentDeps | null = null;
63
-
64
- export function registerNapcatAgentEndpoint(
65
- endpointKey: string,
66
- endpoint: NapcatAgentEndpoint,
67
- ): () => void {
68
- endpoints.set(endpointKey, endpoint);
69
- return () => {
70
- if (endpoints.get(endpointKey) === endpoint) {
71
- endpoints.delete(endpointKey);
72
- }
73
- };
74
- }
75
-
76
- /** Optional override used by tests / transitional callers. Pass `null` to clear. */
77
- export function setNapcatAgentDeps(deps: NapcatAgentDeps | null): void {
78
- override = deps;
79
- }
80
-
81
- function lookup(endpointKey: string): NapcatAgentEndpoint {
82
- const registered = endpoints.get(endpointKey);
83
- if (!registered) throw new Error(`Endpoint ${endpointKey} not found`);
84
- return registered;
85
- }
86
-
87
- export function getNapcatAgentDeps(): NapcatAgentDeps {
88
- if (override) return override;
89
- return { getEndpoint: lookup };
90
- }
91
-
92
- /** Convenience for agent/tools (unchanged call sites). */
93
- export function getEndpoint(endpointKey: string): NapcatAgentEndpoint {
94
- return getNapcatAgentDeps().getEndpoint(endpointKey);
95
- }