@zhin.js/adapter-napcat 6.0.1 → 6.0.3
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 +24 -0
- package/README.md +2 -2
- package/lib/http-endpoint.d.ts +2 -5
- package/lib/http-endpoint.js +8 -9
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/protocol.d.ts +9 -3
- package/lib/protocol.js +28 -21
- package/lib/ws-endpoint.d.ts +2 -5
- package/lib/ws-endpoint.js +8 -9
- package/lib/wss-endpoint.d.ts +2 -5
- package/lib/wss-endpoint.js +7 -8
- package/package.json +14 -13
- package/src/http-endpoint.ts +10 -10
- package/src/index.ts +2 -2
- package/src/protocol.ts +30 -20
- package/src/ws-endpoint.ts +10 -9
- package/src/wss-endpoint.ts +9 -9
- /package/commands/endpoint/add/{[name:string].js → [name].js} +0 -0
- /package/commands/endpoint/add/{[name:string].ts → [name].ts} +0 -0
- /package/commands/endpoint/remove/{[name:string].js → [name].js} +0 -0
- /package/commands/endpoint/remove/{[name:string].ts → [name].ts} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @zhin.js/adapter-napcat
|
|
2
2
|
|
|
3
|
+
## 6.0.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [afc0e66]
|
|
8
|
+
- Updated dependencies [2e41ad5]
|
|
9
|
+
- Updated dependencies [9f57124]
|
|
10
|
+
- @zhin.js/core@1.5.2
|
|
11
|
+
- @zhin.js/adapter@1.1.5
|
|
12
|
+
- @zhin.js/im-contract@1.0.1
|
|
13
|
+
- @zhin.js/plugin-runtime@1.1.3
|
|
14
|
+
- @zhin.js/command@1.0.7
|
|
15
|
+
- @zhin.js/host-http@1.0.6
|
|
16
|
+
- @zhin.js/agent@1.1.3
|
|
17
|
+
- zhin.js@6.0.2
|
|
18
|
+
|
|
19
|
+
## 6.0.2
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- Updated dependencies [696ab1b]
|
|
24
|
+
- @zhin.js/agent@1.1.2
|
|
25
|
+
- zhin.js@6.0.1
|
|
26
|
+
|
|
3
27
|
## 6.0.1
|
|
4
28
|
|
|
5
29
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -24,8 +24,8 @@ pnpm add @zhin.js/adapter-napcat
|
|
|
24
24
|
- `@zhin.js/plugin-runtime` — `plugin.ts`(`definePlugin`)
|
|
25
25
|
- 配置经插件 `schema.json` 落到 `plugins.<instanceKey>`
|
|
26
26
|
|
|
27
|
-
入站:`gateway.receive({
|
|
28
|
-
出站:`send({
|
|
27
|
+
入站:`gateway.receive({ conversation, message: { conversation, id }, content, sender, metadata })`(`conversation` 为 ConversationRef:私聊 `kind: 'private'`、群聊 `kind: 'group'`,临时会话群容器进 `parent`)
|
|
28
|
+
出站:`send({ conversation, payload })` → WS `send_private_msg` / `send_group_msg`
|
|
29
29
|
|
|
30
30
|
## 最小配置
|
|
31
31
|
|
package/lib/http-endpoint.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { EndpointInstance, EndpointManagement } from '@zhin.js/adapter';
|
|
1
|
+
import type { EndpointInstance, EndpointManagement, EndpointSendRequest } from '@zhin.js/adapter';
|
|
2
2
|
import type { MessageGateway } from '@zhin.js/core/runtime';
|
|
3
3
|
import type { HttpHost } from '@zhin.js/host-http';
|
|
4
4
|
import type { CapabilityId } from '@zhin.js/plugin-runtime';
|
|
@@ -18,10 +18,7 @@ export declare class NapCatHttpEndpoint implements EndpointInstance {
|
|
|
18
18
|
open(): void;
|
|
19
19
|
close(): void;
|
|
20
20
|
stop(): Promise<void>;
|
|
21
|
-
send({
|
|
22
|
-
readonly target: string;
|
|
23
|
-
readonly payload: unknown;
|
|
24
|
-
}): Promise<string>;
|
|
21
|
+
send({ conversation, payload }: EndpointSendRequest): Promise<string>;
|
|
25
22
|
recallMessage(messageId: string): Promise<void>;
|
|
26
23
|
callApi(action: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
27
24
|
admit(ev: NapCatEvent): void;
|
package/lib/http-endpoint.js
CHANGED
|
@@ -2,7 +2,7 @@ import { formatCompact, getLogger } from '@zhin.js/logger';
|
|
|
2
2
|
import { createNapCatEndpointManagement } from './endpoint-management.js';
|
|
3
3
|
import { registerNapcatAgentEndpoint } from './napcat-agent-deps.js';
|
|
4
4
|
import { InboundMessageDeduper, isNapCatBotMentioned, isSelfMessage, normalizeMessage, } from './napcat-inbound.js';
|
|
5
|
-
import { buildSendAction, callNapCatHttpAction, formatInboundContent,
|
|
5
|
+
import { buildSendAction, callNapCatHttpAction, formatInboundContent, formatOutboundSegments, isMessageEvent, napcatInboundConversation, napcatOutboundTarget, senderNickname, senderUserId, } from './protocol.js';
|
|
6
6
|
import { readRequestBody } from './webhook.js';
|
|
7
7
|
import { verifyNapCatAccessToken } from './wss-auth.js';
|
|
8
8
|
const logger = getLogger('napcat');
|
|
@@ -48,9 +48,9 @@ export class NapCatHttpEndpoint {
|
|
|
48
48
|
this.#started = false;
|
|
49
49
|
logger.debug(formatCompact({ op: 'disconnect', endpoint: this.#options.config.name }));
|
|
50
50
|
}
|
|
51
|
-
async send({
|
|
51
|
+
async send({ conversation, payload }) {
|
|
52
52
|
const message = formatOutboundSegments(payload);
|
|
53
|
-
const { action, params } = buildSendAction(
|
|
53
|
+
const { action, params } = buildSendAction(napcatOutboundTarget(conversation), message);
|
|
54
54
|
const resp = await this.#callHttpAction({
|
|
55
55
|
http_url: this.#options.config.http_url,
|
|
56
56
|
access_token: this.#options.config.access_token,
|
|
@@ -60,7 +60,7 @@ export class NapCatHttpEndpoint {
|
|
|
60
60
|
logger.debug(formatCompact({
|
|
61
61
|
op: 'napcat_send',
|
|
62
62
|
endpoint: this.#options.config.name,
|
|
63
|
-
target
|
|
63
|
+
target: `${conversation.kind}:${conversation.id}`,
|
|
64
64
|
messageId,
|
|
65
65
|
}));
|
|
66
66
|
return messageId;
|
|
@@ -87,15 +87,14 @@ export class NapCatHttpEndpoint {
|
|
|
87
87
|
if (Array.isArray(ev.message) || typeof ev.message === 'string') {
|
|
88
88
|
ev = { ...ev, message: normalizeMessage(ev.message) };
|
|
89
89
|
}
|
|
90
|
-
const
|
|
90
|
+
const conversation = napcatInboundConversation(String(this.#options.id), ev);
|
|
91
91
|
const nickname = senderNickname(ev);
|
|
92
92
|
const mentioned = isNapCatBotMentioned(ev);
|
|
93
93
|
void this.#options.gateway.receive({
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
conversation,
|
|
95
|
+
message: { conversation, id: msgId },
|
|
96
96
|
content: formatInboundContent(ev),
|
|
97
97
|
sender: senderUserId(ev),
|
|
98
|
-
id: msgId,
|
|
99
98
|
metadata: Object.freeze({
|
|
100
99
|
message_type: ev.message_type,
|
|
101
100
|
user_id: ev.user_id != null ? String(ev.user_id) : undefined,
|
|
@@ -110,7 +109,7 @@ export class NapCatHttpEndpoint {
|
|
|
110
109
|
}).catch((err) => {
|
|
111
110
|
logger.warn(formatCompact({
|
|
112
111
|
op: 'napcat_gateway_receive_failed',
|
|
113
|
-
target
|
|
112
|
+
target: `${conversation.kind}:${conversation.id}`,
|
|
114
113
|
error: err instanceof Error ? err.message : String(err),
|
|
115
114
|
}));
|
|
116
115
|
});
|
package/lib/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { buildSendAction, buildWsConnectOptions, callNapCatHttpAction, formatInboundContent,
|
|
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
3
|
export { getEndpoint, getNapcatAgentDeps, registerNapcatAgentEndpoint, setNapcatAgentDeps, type NapcatAgentDeps, type NapcatAgentEndpoint, } from './napcat-agent-deps.js';
|
|
4
4
|
export { parseOneBotGetMsgResponse } from './onebot-get-msg.js';
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { buildSendAction, buildWsConnectOptions, callNapCatHttpAction, formatInboundContent,
|
|
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
3
|
export { getEndpoint, getNapcatAgentDeps, registerNapcatAgentEndpoint, setNapcatAgentDeps, } from './napcat-agent-deps.js';
|
|
4
4
|
export { parseOneBotGetMsgResponse } from './onebot-get-msg.js';
|
package/lib/protocol.d.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Canonicalization is owned by gateway/core before endpoint.send.
|
|
5
5
|
*/
|
|
6
6
|
import { type MediaRef } from '@zhin.js/core';
|
|
7
|
+
import type { ConversationRef } from '@zhin.js/im-contract';
|
|
7
8
|
/** Transitional legacy endpoint row (`endpoints[]` with `context: napcat`). */
|
|
8
9
|
export interface NapCatLegacyEndpointRow {
|
|
9
10
|
readonly context?: string;
|
|
@@ -116,8 +117,13 @@ export interface ParsedSendTarget {
|
|
|
116
117
|
export declare function resolveNapCatConfig(config?: NapCatAdapterConfig): ResolvedNapCatConfig;
|
|
117
118
|
export declare function isMessageEvent(ev: NapCatEvent): ev is NapCatMessageEvent;
|
|
118
119
|
export declare function getChannelId(ev: NapCatEvent): string;
|
|
119
|
-
|
|
120
|
-
|
|
120
|
+
/**
|
|
121
|
+
* 入站归一化 → ConversationRef:群消息 → kind 'group';私聊临时会话
|
|
122
|
+
* (sub_type 'group')→ kind 'private' + 群容器进 `parent`;其余私聊 → 'private'。
|
|
123
|
+
*/
|
|
124
|
+
export declare function napcatInboundConversation(endpointId: string, ev: NapCatEvent): ConversationRef;
|
|
125
|
+
/** 出站:ConversationRef → OneBot 私聊/群聊目标。 */
|
|
126
|
+
export declare function napcatOutboundTarget(conversation: ConversationRef): ParsedSendTarget;
|
|
121
127
|
export declare function formatInboundContent(ev: NapCatEvent): string;
|
|
122
128
|
/**
|
|
123
129
|
* 入站 sender 语义:必须是用户 ID(Runtime Message contract)。
|
|
@@ -138,7 +144,7 @@ export declare function mediaRefToOneBotFile(media: MediaRef): string;
|
|
|
138
144
|
* 非媒体的 wire 段(at 等)原样透传。
|
|
139
145
|
*/
|
|
140
146
|
export declare function formatOutboundSegments(payload: unknown): MessageSegment[];
|
|
141
|
-
export declare function buildSendAction(target:
|
|
147
|
+
export declare function buildSendAction(target: ParsedSendTarget, message: MessageSegment[]): {
|
|
142
148
|
action: string;
|
|
143
149
|
params: Record<string, unknown>;
|
|
144
150
|
};
|
package/lib/protocol.js
CHANGED
|
@@ -78,24 +78,32 @@ export function getChannelId(ev) {
|
|
|
78
78
|
return String(ev.user_id);
|
|
79
79
|
return '';
|
|
80
80
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
return { message_type: 'private', id: target };
|
|
81
|
+
/**
|
|
82
|
+
* 入站归一化 → ConversationRef:群消息 → kind 'group';私聊临时会话
|
|
83
|
+
* (sub_type 'group')→ kind 'private' + 群容器进 `parent`;其余私聊 → 'private'。
|
|
84
|
+
*/
|
|
85
|
+
export function napcatInboundConversation(endpointId, ev) {
|
|
86
|
+
const endpoint = { id: endpointId, adapter: endpointId.split('\0')[0] ?? endpointId };
|
|
87
|
+
const isGroup = ev.message_type === 'group' || (ev.group_id != null && ev.message_type !== 'private');
|
|
88
|
+
if (isGroup && ev.group_id != null) {
|
|
89
|
+
return { endpoint, kind: 'group', id: String(ev.group_id) };
|
|
91
90
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
91
|
+
if (ev.sub_type === 'group' && ev.group_id != null) {
|
|
92
|
+
return {
|
|
93
|
+
endpoint,
|
|
94
|
+
kind: 'private',
|
|
95
|
+
id: ev.user_id != null ? String(ev.user_id) : '',
|
|
96
|
+
parent: { kind: 'group', id: String(ev.group_id) },
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return { endpoint, kind: 'private', id: ev.user_id != null ? String(ev.user_id) : '' };
|
|
100
|
+
}
|
|
101
|
+
/** 出站:ConversationRef → OneBot 私聊/群聊目标。 */
|
|
102
|
+
export function napcatOutboundTarget(conversation) {
|
|
103
|
+
return {
|
|
104
|
+
message_type: conversation.kind === 'group' ? 'group' : 'private',
|
|
105
|
+
id: conversation.id,
|
|
106
|
+
};
|
|
99
107
|
}
|
|
100
108
|
export function formatInboundContent(ev) {
|
|
101
109
|
if (typeof ev.raw_message === 'string' && ev.raw_message)
|
|
@@ -231,12 +239,11 @@ export function formatOutboundSegments(payload) {
|
|
|
231
239
|
return segs.length ? segs : [{ type: 'text', data: { text: '' } }];
|
|
232
240
|
}
|
|
233
241
|
export function buildSendAction(target, message) {
|
|
234
|
-
|
|
235
|
-
if (parsed.message_type === 'group') {
|
|
242
|
+
if (target.message_type === 'group') {
|
|
236
243
|
return {
|
|
237
244
|
action: 'send_group_msg',
|
|
238
245
|
params: {
|
|
239
|
-
group_id: Number(
|
|
246
|
+
group_id: Number(target.id) || target.id,
|
|
240
247
|
message,
|
|
241
248
|
},
|
|
242
249
|
};
|
|
@@ -244,7 +251,7 @@ export function buildSendAction(target, message) {
|
|
|
244
251
|
return {
|
|
245
252
|
action: 'send_private_msg',
|
|
246
253
|
params: {
|
|
247
|
-
user_id: Number(
|
|
254
|
+
user_id: Number(target.id) || target.id,
|
|
248
255
|
message,
|
|
249
256
|
},
|
|
250
257
|
};
|
package/lib/ws-endpoint.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type EndpointInstance, type EndpointManagement } from '@zhin.js/adapter';
|
|
1
|
+
import { type EndpointInstance, type EndpointManagement, type EndpointSendRequest } from '@zhin.js/adapter';
|
|
2
2
|
import type { MessageGateway } from '@zhin.js/core/runtime';
|
|
3
3
|
import type { CapabilityId } from '@zhin.js/plugin-runtime';
|
|
4
4
|
import { type NapCatEvent, type NapCatWsConfig } from './protocol.js';
|
|
@@ -17,10 +17,7 @@ export declare class NapCatWsEndpoint implements EndpointInstance {
|
|
|
17
17
|
open(): void;
|
|
18
18
|
close(): void;
|
|
19
19
|
stop(): Promise<void>;
|
|
20
|
-
send({
|
|
21
|
-
readonly target: string;
|
|
22
|
-
readonly payload: unknown;
|
|
23
|
-
}): Promise<string>;
|
|
20
|
+
send({ conversation, payload }: EndpointSendRequest): Promise<string>;
|
|
24
21
|
recallMessage(messageId: string): Promise<void>;
|
|
25
22
|
callApi(action: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
26
23
|
setTitle(groupId: number, userId: number, title: string, duration?: number): Promise<boolean>;
|
package/lib/ws-endpoint.js
CHANGED
|
@@ -7,7 +7,7 @@ import { formatCompact, getLogger } from '@zhin.js/logger';
|
|
|
7
7
|
import { createNapCatEndpointManagement } from './endpoint-management.js';
|
|
8
8
|
import { registerNapcatAgentEndpoint } from './napcat-agent-deps.js';
|
|
9
9
|
import { InboundMessageDeduper, isNapCatBotMentioned, isSelfMessage, normalizeMessage, } from './napcat-inbound.js';
|
|
10
|
-
import { buildSendAction, buildWsConnectOptions, formatInboundContent,
|
|
10
|
+
import { buildSendAction, buildWsConnectOptions, formatInboundContent, formatOutboundSegments, isMessageEvent, napcatInboundConversation, napcatOutboundTarget, senderNickname, senderUserId, } from './protocol.js';
|
|
11
11
|
import { callNapCatWsAction, handleNapCatWsMessage, rejectAllPending, } from './ws-transport.js';
|
|
12
12
|
const logger = getLogger('napcat');
|
|
13
13
|
export class NapCatWsEndpoint {
|
|
@@ -70,15 +70,15 @@ export class NapCatWsEndpoint {
|
|
|
70
70
|
this.#ws = undefined;
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
-
async send({
|
|
73
|
+
async send({ conversation, payload }) {
|
|
74
74
|
const message = formatOutboundSegments(payload);
|
|
75
|
-
const { action, params } = buildSendAction(
|
|
75
|
+
const { action, params } = buildSendAction(napcatOutboundTarget(conversation), message);
|
|
76
76
|
const data = await this.callApi(action, params);
|
|
77
77
|
const messageId = data?.message_id != null ? String(data.message_id) : '';
|
|
78
78
|
logger.debug(formatCompact({
|
|
79
79
|
op: 'napcat_send',
|
|
80
80
|
endpoint: this.#options.config.name,
|
|
81
|
-
target
|
|
81
|
+
target: `${conversation.kind}:${conversation.id}`,
|
|
82
82
|
messageId,
|
|
83
83
|
}));
|
|
84
84
|
return messageId;
|
|
@@ -237,16 +237,15 @@ export class NapCatWsEndpoint {
|
|
|
237
237
|
if (Array.isArray(ev.message) || typeof ev.message === 'string') {
|
|
238
238
|
ev = { ...ev, message: normalizeMessage(ev.message) };
|
|
239
239
|
}
|
|
240
|
-
const
|
|
240
|
+
const conversation = napcatInboundConversation(String(this.#options.id), ev);
|
|
241
241
|
const content = formatInboundContent(ev);
|
|
242
242
|
const nickname = senderNickname(ev);
|
|
243
243
|
const mentioned = isNapCatBotMentioned(ev);
|
|
244
244
|
void this.#options.gateway.receive({
|
|
245
|
-
|
|
246
|
-
|
|
245
|
+
conversation,
|
|
246
|
+
message: { conversation, id: msgId },
|
|
247
247
|
content,
|
|
248
248
|
sender: senderUserId(ev),
|
|
249
|
-
id: msgId,
|
|
250
249
|
metadata: Object.freeze({
|
|
251
250
|
message_type: ev.message_type,
|
|
252
251
|
user_id: ev.user_id != null ? String(ev.user_id) : undefined,
|
|
@@ -261,7 +260,7 @@ export class NapCatWsEndpoint {
|
|
|
261
260
|
}).catch((err) => {
|
|
262
261
|
logger.warn(formatCompact({
|
|
263
262
|
op: 'napcat_gateway_receive_failed',
|
|
264
|
-
target
|
|
263
|
+
target: `${conversation.kind}:${conversation.id}`,
|
|
265
264
|
error: err instanceof Error ? err.message : String(err),
|
|
266
265
|
}));
|
|
267
266
|
});
|
package/lib/wss-endpoint.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { EndpointInstance, EndpointManagement } from '@zhin.js/adapter';
|
|
1
|
+
import type { EndpointInstance, EndpointManagement, EndpointSendRequest } from '@zhin.js/adapter';
|
|
2
2
|
import type { MessageGateway } from '@zhin.js/core/runtime';
|
|
3
3
|
import type { HttpHost } from '@zhin.js/host-http';
|
|
4
4
|
import type { CapabilityId } from '@zhin.js/plugin-runtime';
|
|
@@ -17,10 +17,7 @@ export declare class NapCatWssEndpoint implements EndpointInstance {
|
|
|
17
17
|
open(): void;
|
|
18
18
|
close(): void;
|
|
19
19
|
stop(): Promise<void>;
|
|
20
|
-
send({
|
|
21
|
-
readonly target: string;
|
|
22
|
-
readonly payload: unknown;
|
|
23
|
-
}): Promise<string>;
|
|
20
|
+
send({ conversation, payload }: EndpointSendRequest): Promise<string>;
|
|
24
21
|
recallMessage(messageId: string): Promise<void>;
|
|
25
22
|
callApi(action: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
26
23
|
admit(ev: NapCatEvent): void;
|
package/lib/wss-endpoint.js
CHANGED
|
@@ -6,7 +6,7 @@ import { formatCompact, getLogger } from '@zhin.js/logger';
|
|
|
6
6
|
import { createNapCatEndpointManagement } from './endpoint-management.js';
|
|
7
7
|
import { registerNapcatAgentEndpoint } from './napcat-agent-deps.js';
|
|
8
8
|
import { InboundMessageDeduper, isNapCatBotMentioned, isSelfMessage, normalizeMessage, } from './napcat-inbound.js';
|
|
9
|
-
import { buildSendAction, formatInboundContent,
|
|
9
|
+
import { buildSendAction, formatInboundContent, formatOutboundSegments, isMessageEvent, napcatInboundConversation, napcatOutboundTarget, senderNickname, senderUserId, } from './protocol.js';
|
|
10
10
|
import { callNapCatWsAction, handleNapCatWsMessage, rejectAllPending, startNapCatHeartbeat, } from './ws-transport.js';
|
|
11
11
|
import { verifyNapCatAccessToken } from './wss-auth.js';
|
|
12
12
|
const logger = getLogger('napcat');
|
|
@@ -70,9 +70,9 @@ export class NapCatWssEndpoint {
|
|
|
70
70
|
}
|
|
71
71
|
this.#started = false;
|
|
72
72
|
}
|
|
73
|
-
async send({
|
|
73
|
+
async send({ conversation, payload }) {
|
|
74
74
|
const message = formatOutboundSegments(payload);
|
|
75
|
-
const { action, params } = buildSendAction(
|
|
75
|
+
const { action, params } = buildSendAction(napcatOutboundTarget(conversation), message);
|
|
76
76
|
const data = await this.callApi(action, params);
|
|
77
77
|
return data?.message_id != null ? String(data.message_id) : '';
|
|
78
78
|
}
|
|
@@ -95,15 +95,14 @@ export class NapCatWssEndpoint {
|
|
|
95
95
|
if (Array.isArray(ev.message) || typeof ev.message === 'string') {
|
|
96
96
|
ev = { ...ev, message: normalizeMessage(ev.message) };
|
|
97
97
|
}
|
|
98
|
-
const
|
|
98
|
+
const conversation = napcatInboundConversation(String(this.#options.id), ev);
|
|
99
99
|
const nickname = senderNickname(ev);
|
|
100
100
|
const mentioned = isNapCatBotMentioned(ev);
|
|
101
101
|
void this.#options.gateway.receive({
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
conversation,
|
|
103
|
+
message: { conversation, id: msgId },
|
|
104
104
|
content: formatInboundContent(ev),
|
|
105
105
|
sender: senderUserId(ev),
|
|
106
|
-
id: msgId,
|
|
107
106
|
metadata: Object.freeze({
|
|
108
107
|
message_type: ev.message_type,
|
|
109
108
|
user_id: ev.user_id != null ? String(ev.user_id) : undefined,
|
|
@@ -118,7 +117,7 @@ export class NapCatWssEndpoint {
|
|
|
118
117
|
}).catch((err) => {
|
|
119
118
|
logger.warn(formatCompact({
|
|
120
119
|
op: 'napcat_gateway_receive_failed',
|
|
121
|
-
target
|
|
120
|
+
target: `${conversation.kind}:${conversation.id}`,
|
|
122
121
|
error: err instanceof Error ? err.message : String(err),
|
|
123
122
|
}));
|
|
124
123
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-napcat",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.3",
|
|
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.1.
|
|
47
|
-
"@zhin.js/command": "1.0.
|
|
48
|
-
"@zhin.js/core": "1.5.
|
|
49
|
-
"@zhin.js/host-http": "1.0.
|
|
46
|
+
"@zhin.js/adapter": "1.1.5",
|
|
47
|
+
"@zhin.js/command": "1.0.7",
|
|
48
|
+
"@zhin.js/core": "1.5.2",
|
|
49
|
+
"@zhin.js/host-http": "1.0.6",
|
|
50
|
+
"@zhin.js/im-contract": "1.0.1",
|
|
50
51
|
"@zhin.js/logger": "1.0.75",
|
|
51
|
-
"@zhin.js/plugin-runtime": "1.1.
|
|
52
|
+
"@zhin.js/plugin-runtime": "1.1.3"
|
|
52
53
|
},
|
|
53
54
|
"devDependencies": {
|
|
54
55
|
"@types/node": "^26.1.2",
|
|
@@ -56,16 +57,16 @@
|
|
|
56
57
|
"typescript": "^6.0.3",
|
|
57
58
|
"vitest": "^4.1.10",
|
|
58
59
|
"zod": "^4.4.3",
|
|
59
|
-
"@zhin.js/agent": "1.1.
|
|
60
|
-
"@zhin.js/host-http": "1.0.
|
|
60
|
+
"@zhin.js/agent": "1.1.3",
|
|
61
|
+
"@zhin.js/host-http": "1.0.6"
|
|
61
62
|
},
|
|
62
63
|
"peerDependencies": {
|
|
63
64
|
"zod": "^4.0.0",
|
|
64
|
-
"@zhin.js/adapter": "1.1.
|
|
65
|
-
"@zhin.js/agent": "1.1.
|
|
66
|
-
"@zhin.js/core": "1.5.
|
|
67
|
-
"@zhin.js/plugin-runtime": "1.1.
|
|
68
|
-
"zhin.js": "6.0.
|
|
65
|
+
"@zhin.js/adapter": "1.1.5",
|
|
66
|
+
"@zhin.js/agent": "1.1.3",
|
|
67
|
+
"@zhin.js/core": "1.5.2",
|
|
68
|
+
"@zhin.js/plugin-runtime": "1.1.3",
|
|
69
|
+
"zhin.js": "6.0.2"
|
|
69
70
|
},
|
|
70
71
|
"peerDependenciesMeta": {
|
|
71
72
|
"zhin.js": {
|
package/src/http-endpoint.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* NapCat HTTP endpoint — POST inbound events + HTTP API outbound.
|
|
3
3
|
*/
|
|
4
4
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
5
|
-
import type { EndpointInstance, EndpointManagement } from '@zhin.js/adapter';
|
|
5
|
+
import type { EndpointInstance, EndpointManagement, EndpointSendRequest } from '@zhin.js/adapter';
|
|
6
6
|
import type { MessageGateway } from '@zhin.js/core/runtime';
|
|
7
7
|
import type { HttpHost, HttpRouteRegistration } from '@zhin.js/host-http';
|
|
8
8
|
import { formatCompact, getLogger } from '@zhin.js/logger';
|
|
@@ -19,9 +19,10 @@ import {
|
|
|
19
19
|
buildSendAction,
|
|
20
20
|
callNapCatHttpAction,
|
|
21
21
|
formatInboundContent,
|
|
22
|
-
formatInboundTarget,
|
|
23
22
|
formatOutboundSegments,
|
|
24
23
|
isMessageEvent,
|
|
24
|
+
napcatInboundConversation,
|
|
25
|
+
napcatOutboundTarget,
|
|
25
26
|
senderNickname,
|
|
26
27
|
senderUserId,
|
|
27
28
|
type NapCatEvent,
|
|
@@ -90,9 +91,9 @@ export class NapCatHttpEndpoint implements EndpointInstance {
|
|
|
90
91
|
logger.debug(formatCompact({ op: 'disconnect', endpoint: this.#options.config.name }));
|
|
91
92
|
}
|
|
92
93
|
|
|
93
|
-
async send({
|
|
94
|
+
async send({ conversation, payload }: EndpointSendRequest): Promise<string> {
|
|
94
95
|
const message = formatOutboundSegments(payload);
|
|
95
|
-
const { action, params } = buildSendAction(
|
|
96
|
+
const { action, params } = buildSendAction(napcatOutboundTarget(conversation), message);
|
|
96
97
|
const resp = await this.#callHttpAction(
|
|
97
98
|
{
|
|
98
99
|
http_url: this.#options.config.http_url,
|
|
@@ -106,7 +107,7 @@ export class NapCatHttpEndpoint implements EndpointInstance {
|
|
|
106
107
|
logger.debug(formatCompact({
|
|
107
108
|
op: 'napcat_send',
|
|
108
109
|
endpoint: this.#options.config.name,
|
|
109
|
-
target
|
|
110
|
+
target: `${conversation.kind}:${conversation.id}`,
|
|
110
111
|
messageId,
|
|
111
112
|
}));
|
|
112
113
|
return messageId;
|
|
@@ -136,15 +137,14 @@ export class NapCatHttpEndpoint implements EndpointInstance {
|
|
|
136
137
|
if (Array.isArray(ev.message) || typeof ev.message === 'string') {
|
|
137
138
|
ev = { ...ev, message: normalizeMessage(ev.message) };
|
|
138
139
|
}
|
|
139
|
-
const
|
|
140
|
+
const conversation = napcatInboundConversation(String(this.#options.id), ev);
|
|
140
141
|
const nickname = senderNickname(ev);
|
|
141
142
|
const mentioned = isNapCatBotMentioned(ev);
|
|
142
143
|
void this.#options.gateway.receive({
|
|
143
|
-
|
|
144
|
-
|
|
144
|
+
conversation,
|
|
145
|
+
message: { conversation, id: msgId },
|
|
145
146
|
content: formatInboundContent(ev),
|
|
146
147
|
sender: senderUserId(ev),
|
|
147
|
-
id: msgId,
|
|
148
148
|
metadata: Object.freeze({
|
|
149
149
|
message_type: ev.message_type,
|
|
150
150
|
user_id: ev.user_id != null ? String(ev.user_id) : undefined,
|
|
@@ -159,7 +159,7 @@ export class NapCatHttpEndpoint implements EndpointInstance {
|
|
|
159
159
|
}).catch((err) => {
|
|
160
160
|
logger.warn(formatCompact({
|
|
161
161
|
op: 'napcat_gateway_receive_failed',
|
|
162
|
-
target
|
|
162
|
+
target: `${conversation.kind}:${conversation.id}`,
|
|
163
163
|
error: err instanceof Error ? err.message : String(err),
|
|
164
164
|
}));
|
|
165
165
|
});
|
package/src/index.ts
CHANGED
|
@@ -3,12 +3,12 @@ export {
|
|
|
3
3
|
buildWsConnectOptions,
|
|
4
4
|
callNapCatHttpAction,
|
|
5
5
|
formatInboundContent,
|
|
6
|
-
formatInboundTarget,
|
|
7
6
|
formatOutboundSegments,
|
|
8
7
|
getChannelId,
|
|
9
8
|
isMessageEvent,
|
|
10
9
|
mediaRefToOneBotFile,
|
|
11
|
-
|
|
10
|
+
napcatInboundConversation,
|
|
11
|
+
napcatOutboundTarget,
|
|
12
12
|
resolveNapCatConfig,
|
|
13
13
|
senderNickname,
|
|
14
14
|
senderUserId,
|
package/src/protocol.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Canonicalization is owned by gateway/core before endpoint.send.
|
|
5
5
|
*/
|
|
6
6
|
import { isMediaRef, type MediaRef } from '@zhin.js/core';
|
|
7
|
+
import type { ConversationRef } from '@zhin.js/im-contract';
|
|
7
8
|
import { formatCompact, getLogger } from '@zhin.js/logger';
|
|
8
9
|
|
|
9
10
|
const logger = getLogger('napcat');
|
|
@@ -213,23 +214,33 @@ export function getChannelId(ev: NapCatEvent): string {
|
|
|
213
214
|
return '';
|
|
214
215
|
}
|
|
215
216
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
217
|
+
/**
|
|
218
|
+
* 入站归一化 → ConversationRef:群消息 → kind 'group';私聊临时会话
|
|
219
|
+
* (sub_type 'group')→ kind 'private' + 群容器进 `parent`;其余私聊 → 'private'。
|
|
220
|
+
*/
|
|
221
|
+
export function napcatInboundConversation(endpointId: string, ev: NapCatEvent): ConversationRef {
|
|
222
|
+
const endpoint = { id: endpointId, adapter: endpointId.split('\0')[0] ?? endpointId };
|
|
223
|
+
const isGroup = ev.message_type === 'group' || (ev.group_id != null && ev.message_type !== 'private');
|
|
224
|
+
if (isGroup && ev.group_id != null) {
|
|
225
|
+
return { endpoint, kind: 'group', id: String(ev.group_id) };
|
|
226
|
+
}
|
|
227
|
+
if (ev.sub_type === 'group' && ev.group_id != null) {
|
|
228
|
+
return {
|
|
229
|
+
endpoint,
|
|
230
|
+
kind: 'private',
|
|
231
|
+
id: ev.user_id != null ? String(ev.user_id) : '',
|
|
232
|
+
parent: { kind: 'group', id: String(ev.group_id) },
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
return { endpoint, kind: 'private', id: ev.user_id != null ? String(ev.user_id) : '' };
|
|
221
236
|
}
|
|
222
237
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
const rest = target.slice(sep + 1);
|
|
230
|
-
if (head === 'group') return { message_type: 'group', id: rest };
|
|
231
|
-
if (head === 'private') return { message_type: 'private', id: rest };
|
|
232
|
-
return { message_type: 'private', id: target };
|
|
238
|
+
/** 出站:ConversationRef → OneBot 私聊/群聊目标。 */
|
|
239
|
+
export function napcatOutboundTarget(conversation: ConversationRef): ParsedSendTarget {
|
|
240
|
+
return {
|
|
241
|
+
message_type: conversation.kind === 'group' ? 'group' : 'private',
|
|
242
|
+
id: conversation.id,
|
|
243
|
+
};
|
|
233
244
|
}
|
|
234
245
|
|
|
235
246
|
export function formatInboundContent(ev: NapCatEvent): string {
|
|
@@ -373,15 +384,14 @@ export function formatOutboundSegments(payload: unknown): MessageSegment[] {
|
|
|
373
384
|
}
|
|
374
385
|
|
|
375
386
|
export function buildSendAction(
|
|
376
|
-
target:
|
|
387
|
+
target: ParsedSendTarget,
|
|
377
388
|
message: MessageSegment[],
|
|
378
389
|
): { action: string; params: Record<string, unknown> } {
|
|
379
|
-
|
|
380
|
-
if (parsed.message_type === 'group') {
|
|
390
|
+
if (target.message_type === 'group') {
|
|
381
391
|
return {
|
|
382
392
|
action: 'send_group_msg',
|
|
383
393
|
params: {
|
|
384
|
-
group_id: Number(
|
|
394
|
+
group_id: Number(target.id) || target.id,
|
|
385
395
|
message,
|
|
386
396
|
},
|
|
387
397
|
};
|
|
@@ -389,7 +399,7 @@ export function buildSendAction(
|
|
|
389
399
|
return {
|
|
390
400
|
action: 'send_private_msg',
|
|
391
401
|
params: {
|
|
392
|
-
user_id: Number(
|
|
402
|
+
user_id: Number(target.id) || target.id,
|
|
393
403
|
message,
|
|
394
404
|
},
|
|
395
405
|
};
|
package/src/ws-endpoint.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
type EndpointInstance,
|
|
9
9
|
type EndpointLifecycle,
|
|
10
10
|
type EndpointManagement,
|
|
11
|
+
type EndpointSendRequest,
|
|
11
12
|
} from '@zhin.js/adapter';
|
|
12
13
|
import type { MessageGateway } from '@zhin.js/core/runtime';
|
|
13
14
|
import { formatCompact, getLogger } from '@zhin.js/logger';
|
|
@@ -24,9 +25,10 @@ import {
|
|
|
24
25
|
buildSendAction,
|
|
25
26
|
buildWsConnectOptions,
|
|
26
27
|
formatInboundContent,
|
|
27
|
-
formatInboundTarget,
|
|
28
28
|
formatOutboundSegments,
|
|
29
29
|
isMessageEvent,
|
|
30
|
+
napcatInboundConversation,
|
|
31
|
+
napcatOutboundTarget,
|
|
30
32
|
senderNickname,
|
|
31
33
|
senderUserId,
|
|
32
34
|
type NapCatEvent,
|
|
@@ -118,15 +120,15 @@ export class NapCatWsEndpoint implements EndpointInstance {
|
|
|
118
120
|
}
|
|
119
121
|
}
|
|
120
122
|
|
|
121
|
-
async send({
|
|
123
|
+
async send({ conversation, payload }: EndpointSendRequest): Promise<string> {
|
|
122
124
|
const message = formatOutboundSegments(payload);
|
|
123
|
-
const { action, params } = buildSendAction(
|
|
125
|
+
const { action, params } = buildSendAction(napcatOutboundTarget(conversation), message);
|
|
124
126
|
const data = await this.callApi(action, params) as { message_id?: number | string } | undefined;
|
|
125
127
|
const messageId = data?.message_id != null ? String(data.message_id) : '';
|
|
126
128
|
logger.debug(formatCompact({
|
|
127
129
|
op: 'napcat_send',
|
|
128
130
|
endpoint: this.#options.config.name,
|
|
129
|
-
target
|
|
131
|
+
target: `${conversation.kind}:${conversation.id}`,
|
|
130
132
|
messageId,
|
|
131
133
|
}));
|
|
132
134
|
return messageId;
|
|
@@ -326,16 +328,15 @@ export class NapCatWsEndpoint implements EndpointInstance {
|
|
|
326
328
|
if (Array.isArray(ev.message) || typeof ev.message === 'string') {
|
|
327
329
|
ev = { ...ev, message: normalizeMessage(ev.message) };
|
|
328
330
|
}
|
|
329
|
-
const
|
|
331
|
+
const conversation = napcatInboundConversation(String(this.#options.id), ev);
|
|
330
332
|
const content = formatInboundContent(ev);
|
|
331
333
|
const nickname = senderNickname(ev);
|
|
332
334
|
const mentioned = isNapCatBotMentioned(ev);
|
|
333
335
|
void this.#options.gateway.receive({
|
|
334
|
-
|
|
335
|
-
|
|
336
|
+
conversation,
|
|
337
|
+
message: { conversation, id: msgId },
|
|
336
338
|
content,
|
|
337
339
|
sender: senderUserId(ev),
|
|
338
|
-
id: msgId,
|
|
339
340
|
metadata: Object.freeze({
|
|
340
341
|
message_type: ev.message_type,
|
|
341
342
|
user_id: ev.user_id != null ? String(ev.user_id) : undefined,
|
|
@@ -350,7 +351,7 @@ export class NapCatWsEndpoint implements EndpointInstance {
|
|
|
350
351
|
}).catch((err) => {
|
|
351
352
|
logger.warn(formatCompact({
|
|
352
353
|
op: 'napcat_gateway_receive_failed',
|
|
353
|
-
target
|
|
354
|
+
target: `${conversation.kind}:${conversation.id}`,
|
|
354
355
|
error: err instanceof Error ? err.message : String(err),
|
|
355
356
|
}));
|
|
356
357
|
});
|
package/src/wss-endpoint.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* NapCat reverse WSS endpoint — accepts inbound WebSocket from NapCat.
|
|
3
3
|
*/
|
|
4
4
|
import { clearInterval } from 'node:timers';
|
|
5
|
-
import type { EndpointInstance, EndpointManagement } from '@zhin.js/adapter';
|
|
5
|
+
import type { EndpointInstance, EndpointManagement, EndpointSendRequest } from '@zhin.js/adapter';
|
|
6
6
|
import type { MessageGateway } from '@zhin.js/core/runtime';
|
|
7
7
|
import type { HttpHost, WsConnection } from '@zhin.js/host-http';
|
|
8
8
|
import { formatCompact, getLogger } from '@zhin.js/logger';
|
|
@@ -18,9 +18,10 @@ import {
|
|
|
18
18
|
import {
|
|
19
19
|
buildSendAction,
|
|
20
20
|
formatInboundContent,
|
|
21
|
-
formatInboundTarget,
|
|
22
21
|
formatOutboundSegments,
|
|
23
22
|
isMessageEvent,
|
|
23
|
+
napcatInboundConversation,
|
|
24
|
+
napcatOutboundTarget,
|
|
24
25
|
senderNickname,
|
|
25
26
|
senderUserId,
|
|
26
27
|
type NapCatEvent,
|
|
@@ -115,9 +116,9 @@ export class NapCatWssEndpoint implements EndpointInstance {
|
|
|
115
116
|
this.#started = false;
|
|
116
117
|
}
|
|
117
118
|
|
|
118
|
-
async send({
|
|
119
|
+
async send({ conversation, payload }: EndpointSendRequest): Promise<string> {
|
|
119
120
|
const message = formatOutboundSegments(payload);
|
|
120
|
-
const { action, params } = buildSendAction(
|
|
121
|
+
const { action, params } = buildSendAction(napcatOutboundTarget(conversation), message);
|
|
121
122
|
const data = await this.callApi(action, params) as { message_id?: number | string } | undefined;
|
|
122
123
|
return data?.message_id != null ? String(data.message_id) : '';
|
|
123
124
|
}
|
|
@@ -139,15 +140,14 @@ export class NapCatWssEndpoint implements EndpointInstance {
|
|
|
139
140
|
if (Array.isArray(ev.message) || typeof ev.message === 'string') {
|
|
140
141
|
ev = { ...ev, message: normalizeMessage(ev.message) };
|
|
141
142
|
}
|
|
142
|
-
const
|
|
143
|
+
const conversation = napcatInboundConversation(String(this.#options.id), ev);
|
|
143
144
|
const nickname = senderNickname(ev);
|
|
144
145
|
const mentioned = isNapCatBotMentioned(ev);
|
|
145
146
|
void this.#options.gateway.receive({
|
|
146
|
-
|
|
147
|
-
|
|
147
|
+
conversation,
|
|
148
|
+
message: { conversation, id: msgId },
|
|
148
149
|
content: formatInboundContent(ev),
|
|
149
150
|
sender: senderUserId(ev),
|
|
150
|
-
id: msgId,
|
|
151
151
|
metadata: Object.freeze({
|
|
152
152
|
message_type: ev.message_type,
|
|
153
153
|
user_id: ev.user_id != null ? String(ev.user_id) : undefined,
|
|
@@ -162,7 +162,7 @@ export class NapCatWssEndpoint implements EndpointInstance {
|
|
|
162
162
|
}).catch((err) => {
|
|
163
163
|
logger.warn(formatCompact({
|
|
164
164
|
op: 'napcat_gateway_receive_failed',
|
|
165
|
-
target
|
|
165
|
+
target: `${conversation.kind}:${conversation.id}`,
|
|
166
166
|
error: err instanceof Error ? err.message : String(err),
|
|
167
167
|
}));
|
|
168
168
|
});
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|