@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,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,16 +6,13 @@ import { clearInterval } from 'node:timers';
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, WsConnection } 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,
@@ -35,6 +33,7 @@ import {
35
33
  } from './protocol.js';
36
34
  import { receiveNapCatSideEvent } from './side-event-dispatch.js';
37
35
  import { createNapCatContentPort } from './onebot-get-msg.js';
36
+ import { NapcatClient } from './client.js';
38
37
  import {
39
38
  callNapCatWsAction,
40
39
  handleNapCatWsMessage,
@@ -50,20 +49,19 @@ import { verifyNapCatAccessToken } from './wss-auth.js';
50
49
 
51
50
  export interface NapCatWssEndpointOptions {
52
51
  readonly id: CapabilityId;
53
- readonly gateway: MessageGateway;
54
- readonly sideEvents?: SideEventGateway;
55
52
  readonly http: HttpHost;
56
53
  readonly config: NapCatWssConfig;
57
54
  }
58
55
 
59
- export class NapCatWssEndpoint implements EndpointInstance {
56
+ export class NapCatWssEndpoint extends Endpoint<NapcatClient> {
57
+ readonly client = new NapcatClient((action, params) => this.#callApi(action, params));
60
58
  readonly #logger!: ReturnType<typeof getAdapterLogger>;
61
59
 
62
60
  readonly #options: NapCatWssEndpointOptions;
63
61
  readonly #inboundDeduper = new InboundMessageDeduper();
64
- readonly management: EndpointManagement = createNapCatEndpointManagement(this);
62
+ readonly management: EndpointManagement = createNapCatEndpointManagement(this.client);
65
63
  readonly control: EndpointControl = createRecallEndpointControl((id) => this.recallMessage(id));
66
- readonly content = createNapCatContentPort((action, params) => this.callApi(action, params));
64
+ readonly content = createNapCatContentPort((action, params) => this.client.callApi(action, params));
67
65
  #ws?: NapCatWsSocket;
68
66
  #wsRelease?: () => void;
69
67
  #heartbeatTimer?: NodeJS.Timeout;
@@ -71,9 +69,9 @@ export class NapCatWssEndpoint implements EndpointInstance {
71
69
  #pending = new Map<string, NapCatPendingAction>();
72
70
  #open = false;
73
71
  #started = false;
74
- #unregisterAgent?: () => void;
75
72
 
76
73
  constructor(options: NapCatWssEndpointOptions) {
74
+ super();
77
75
  this.#logger = getAdapterLogger('napcat', options.config.id);
78
76
  this.#options = options;
79
77
  }
@@ -81,10 +79,6 @@ export class NapCatWssEndpoint implements EndpointInstance {
81
79
  async start(): Promise<void> {
82
80
  if (this.#started) return;
83
81
  this.#started = true;
84
- this.#unregisterAgent = registerNapcatAgentEndpoint(
85
- this.#options.config.id,
86
- this as unknown as NapCatWsEndpoint,
87
- );
88
82
  const handle = this.#options.http.ws(this.#options.config.path);
89
83
  this.#wsRelease = handle.onConnection((connection) => {
90
84
  this.#acceptConnection(connection);
@@ -107,8 +101,6 @@ export class NapCatWssEndpoint implements EndpointInstance {
107
101
 
108
102
  async stop(): Promise<void> {
109
103
  this.#open = false;
110
- this.#unregisterAgent?.();
111
- this.#unregisterAgent = undefined;
112
104
  this.#wsRelease?.();
113
105
  this.#wsRelease = undefined;
114
106
  if (this.#heartbeatTimer) {
@@ -131,26 +123,32 @@ export class NapCatWssEndpoint implements EndpointInstance {
131
123
  async send({ conversation, payload }: EndpointSendRequest): Promise<string> {
132
124
  const message = formatOutboundSegments(payload);
133
125
  const { action, params } = buildSendAction(napcatOutboundTarget(conversation), message);
134
- 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;
135
127
  return data?.message_id != null ? String(data.message_id) : '';
136
128
  }
137
129
 
138
130
  async recallMessage(messageId: string): Promise<void> {
139
131
  if (!messageId) return;
140
- await this.callApi('delete_msg', { message_id: Number(messageId) });
132
+ await this.client.callApi('delete_msg', { message_id: Number(messageId) });
141
133
  }
142
134
 
143
- callApi(action: string, params: Record<string, unknown> = {}): Promise<unknown> {
135
+ #callApi(action: string, params: Record<string, unknown> = {}): Promise<unknown> {
144
136
  return callNapCatWsAction(this.#ws, this.#pending, this.#requestId, action, params);
145
137
  }
146
138
 
147
139
  admit(ev: NapCatEvent): void {
148
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
+ });
149
147
  if (!isMessageEvent(ev)) {
150
148
  receiveNapCatSideEvent(
151
- this.#options.sideEvents,
149
+ (name, payload) => this.emit(name, payload),
152
150
  this.#options.config.id,
153
- this,
151
+ this.client,
154
152
  ev,
155
153
  this.#logger,
156
154
  );
@@ -165,7 +163,7 @@ export class NapCatWssEndpoint implements EndpointInstance {
165
163
  const conversation = napcatInboundConversation(String(this.#options.id), ev);
166
164
  const nickname = senderNickname(ev);
167
165
  const mentioned = isNapCatBotMentioned(ev);
168
- void this.#options.gateway.receive({
166
+ void this.emit('message.receive', {
169
167
  conversation,
170
168
  message: { conversation, id: msgId },
171
169
  content: formatInboundContent(ev),
@@ -236,3 +234,9 @@ export class NapCatWssEndpoint implements EndpointInstance {
236
234
  }));
237
235
  }
238
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
- }