@zhin.js/adapter-kook 7.0.13 → 8.0.0
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 +53 -0
- package/README.md +2 -1
- package/adapters/kook.js +8 -2
- package/adapters/kook.ts +8 -2
- package/lib/endpoint.d.ts +6 -2
- package/lib/endpoint.js +8 -0
- package/lib/protocol.js +2 -0
- package/lib/side-event-dispatch.d.ts +3 -0
- package/lib/side-event-dispatch.js +51 -0
- package/lib/webhook.d.ts +2 -0
- package/lib/webhook.js +4 -0
- package/package.json +14 -14
- package/src/endpoint.ts +18 -7
- package/src/protocol.ts +2 -0
- package/src/side-event-dispatch.ts +55 -0
- package/src/webhook.ts +6 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,58 @@
|
|
|
1
1
|
# @zhin.js/adapter-kook
|
|
2
2
|
|
|
3
|
+
## 8.0.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- f2c532f: Expose exact per-Endpoint message operations through one validated Adapter capability model, route Core control calls through declared active capabilities, and connect existing recall, edit, reaction, and typing implementations across platform adapters.
|
|
8
|
+
- Updated dependencies [b10d058]
|
|
9
|
+
- Updated dependencies [f2c532f]
|
|
10
|
+
- Updated dependencies [3dbf990]
|
|
11
|
+
- @zhin.js/host-http@1.0.12
|
|
12
|
+
- @zhin.js/adapter@1.2.0
|
|
13
|
+
- @zhin.js/core@1.5.13
|
|
14
|
+
- @zhin.js/agent@1.1.15
|
|
15
|
+
- zhin.js@6.0.13
|
|
16
|
+
|
|
17
|
+
## 7.0.14
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- 974772e: Replace the user-facing `Prompt` vocabulary with the `UserInteraction` authoring surface for input, confirmation, and selection. Commands and handlers now expose `interaction`; IM Runtime exposes `createInteraction`; schema-driven endpoint collection is named `SchemaInteraction`. The old prompt-named interaction types and properties are removed rather than aliased. User interactions render through one canonical Markdown and keyboard/list presentation module shared by commands and Agent `ask_user` turns.
|
|
22
|
+
|
|
23
|
+
Extract the transport-neutral interaction contract into `@zhin.js/interaction`. A discriminated `ask()` API supports text, number, confirmation, single-select, multi-select, and typed lists with structured `title`, `description`, and `tip` content. Typed `sequence()` interactions return one result object keyed by step id, render progress, and retry invalid replies without leaking invalid values to callers.
|
|
24
|
+
|
|
25
|
+
Preserve AI Markdown and card command actions through outbound publishing. QQ delivers Markdown with native command buttons; KOOK, Discord, Telegram, DingTalk, and Lark/Feishu now declare and encode their native Markdown dialects while retaining each adapter's interaction policy. Correct QQ callback button action encoding and button style mapping.
|
|
26
|
+
|
|
27
|
+
- 5969c5b: Add SideEventGateway so adapters forward notice/request/system into HandlerIndex. HandlerContext now exposes only generation-safe capabilities and prompt ports; live Endpoint escape hatches are removed.
|
|
28
|
+
- Updated dependencies [5969c5b]
|
|
29
|
+
- Updated dependencies [d336a3f]
|
|
30
|
+
- Updated dependencies [0c82a7e]
|
|
31
|
+
- Updated dependencies [b9217e4]
|
|
32
|
+
- Updated dependencies [5969c5b]
|
|
33
|
+
- Updated dependencies [5969c5b]
|
|
34
|
+
- Updated dependencies [974772e]
|
|
35
|
+
- Updated dependencies [5969c5b]
|
|
36
|
+
- Updated dependencies [5969c5b]
|
|
37
|
+
- Updated dependencies [2f786bd]
|
|
38
|
+
- Updated dependencies [63d89f9]
|
|
39
|
+
- Updated dependencies [71c7cdd]
|
|
40
|
+
- Updated dependencies [3cca0ea]
|
|
41
|
+
- Updated dependencies [1312ca0]
|
|
42
|
+
- Updated dependencies [985fa22]
|
|
43
|
+
- Updated dependencies [04b861d]
|
|
44
|
+
- Updated dependencies [a23d544]
|
|
45
|
+
- Updated dependencies [8cddabf]
|
|
46
|
+
- Updated dependencies [dbe5081]
|
|
47
|
+
- @zhin.js/im-contract@1.0.4
|
|
48
|
+
- @zhin.js/core@1.5.12
|
|
49
|
+
- @zhin.js/adapter@1.1.11
|
|
50
|
+
- @zhin.js/agent@1.1.14
|
|
51
|
+
- @zhin.js/host-http@1.0.11
|
|
52
|
+
- @zhin.js/command@1.0.15
|
|
53
|
+
- zhin.js@6.0.12
|
|
54
|
+
- @zhin.js/permission@1.0.3
|
|
55
|
+
|
|
3
56
|
## 7.0.13
|
|
4
57
|
|
|
5
58
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -8,6 +8,7 @@ Zhin.js KOOK(开黑啦)适配器(Plugin Runtime),默认通过 **WebSoc
|
|
|
8
8
|
- Webhook 入站(`connection: webhook` + `httpHostToken` + `verify_token`)
|
|
9
9
|
- 解析频道与私聊文本消息
|
|
10
10
|
- 出站 `send({ conversation, payload })` → KOOK KMarkdown(`kind: 'channel' | 'private'`)
|
|
11
|
+
- canonical `markdown` 段原生保留为 [KMarkdown](https://developer.kookapp.cn/doc/kmarkdown-desc)
|
|
11
12
|
- 约定式 `defineAdapter` / `definePlugin`(无需 `usePlugin`)
|
|
12
13
|
|
|
13
14
|
## 安装
|
|
@@ -96,7 +97,7 @@ platform permit checker 由 `plugin.ts` 的 generation 生命周期注册;Capa
|
|
|
96
97
|
|
|
97
98
|
## 迁移后出站能力变化
|
|
98
99
|
|
|
99
|
-
迁移到 Plugin Runtime 后,出站统一经 `messageGatewayToken`
|
|
100
|
+
迁移到 Plugin Runtime 后,出站统一经 `messageGatewayToken` 渲染并由 endpoint 编码为 KMarkdown(`sendChannelMsg` / `sendPrivateMsg`)。canonical `markdown` 保留格式;图片、视频、音频和文件仅有远程 URL 时可表示为 KMarkdown 链接。卡片消息与附件上传仍未接入统一出站通道。
|
|
100
101
|
|
|
101
102
|
## 许可证
|
|
102
103
|
|
package/adapters/kook.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Implementation lives under `src/` (endpoint / webhook / ws / protocol).
|
|
5
5
|
*/
|
|
6
6
|
import { defineAdapter } from 'zhin.js/adapter';
|
|
7
|
-
import { messageGatewayToken } from '@zhin.js/core/runtime';
|
|
7
|
+
import { messageGatewayToken, sideEventGatewayToken } from '@zhin.js/core/runtime';
|
|
8
8
|
import { httpHostToken } from '@zhin.js/host-http';
|
|
9
9
|
import { KookWebhookEndpoint, KookWebsocketEndpoint, } from "../lib/endpoint.js";
|
|
10
10
|
import { resolveKookConfig, } from "../lib/protocol.js";
|
|
@@ -12,14 +12,18 @@ import { kookRuntimeStateToken } from "../lib/kook-runtime-state.js";
|
|
|
12
12
|
export { KookWebhookEndpoint, KookWebsocketEndpoint, } from "../lib/endpoint.js";
|
|
13
13
|
export default defineAdapter({
|
|
14
14
|
capabilities: ['inbound', 'outbound'],
|
|
15
|
-
|
|
15
|
+
operations: ['recall'],
|
|
16
|
+
// KOOK 图片消息消费远程 URL;KMarkdown 由 endpoint codec 原生消费;
|
|
17
|
+
// 无按钮交互面,交互段降级纯文本。
|
|
16
18
|
segments: {
|
|
17
19
|
outboundMedia: ['url'],
|
|
18
20
|
interactive: 'text',
|
|
21
|
+
markdown: 'native',
|
|
19
22
|
},
|
|
20
23
|
create(context) {
|
|
21
24
|
const config = resolveKookConfig(context.config);
|
|
22
25
|
const gateway = context.use(messageGatewayToken);
|
|
26
|
+
const sideEvents = context.use(sideEventGatewayToken);
|
|
23
27
|
// 注册到插件运行时状态(kook.endpoint list 的"运行中"数据源)
|
|
24
28
|
context.use(kookRuntimeStateToken).endpoints.set(config.id, {
|
|
25
29
|
id: config.id,
|
|
@@ -29,6 +33,7 @@ export default defineAdapter({
|
|
|
29
33
|
return new KookWebhookEndpoint({
|
|
30
34
|
id: context.id,
|
|
31
35
|
gateway,
|
|
36
|
+
sideEvents,
|
|
32
37
|
http: context.use(httpHostToken),
|
|
33
38
|
config,
|
|
34
39
|
});
|
|
@@ -36,6 +41,7 @@ export default defineAdapter({
|
|
|
36
41
|
return new KookWebsocketEndpoint({
|
|
37
42
|
id: context.id,
|
|
38
43
|
gateway,
|
|
44
|
+
sideEvents,
|
|
39
45
|
config,
|
|
40
46
|
});
|
|
41
47
|
},
|
package/adapters/kook.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Implementation lives under `src/` (endpoint / webhook / ws / protocol).
|
|
4
4
|
*/
|
|
5
5
|
import { defineAdapter } from 'zhin.js/adapter';
|
|
6
|
-
import { messageGatewayToken } from '@zhin.js/core/runtime';
|
|
6
|
+
import { messageGatewayToken, sideEventGatewayToken } from '@zhin.js/core/runtime';
|
|
7
7
|
import { httpHostToken } from '@zhin.js/host-http';
|
|
8
8
|
import {
|
|
9
9
|
KookWebhookEndpoint,
|
|
@@ -27,14 +27,18 @@ export type { CreateKookClient, KookClientTransport } from '../src/ws.js';
|
|
|
27
27
|
|
|
28
28
|
export default defineAdapter<KookAdapterConfig>({
|
|
29
29
|
capabilities: ['inbound', 'outbound'],
|
|
30
|
-
|
|
30
|
+
operations: ['recall'],
|
|
31
|
+
// KOOK 图片消息消费远程 URL;KMarkdown 由 endpoint codec 原生消费;
|
|
32
|
+
// 无按钮交互面,交互段降级纯文本。
|
|
31
33
|
segments: {
|
|
32
34
|
outboundMedia: ['url'],
|
|
33
35
|
interactive: 'text',
|
|
36
|
+
markdown: 'native',
|
|
34
37
|
},
|
|
35
38
|
create(context) {
|
|
36
39
|
const config = resolveKookConfig(context.config);
|
|
37
40
|
const gateway = context.use(messageGatewayToken);
|
|
41
|
+
const sideEvents = context.use(sideEventGatewayToken);
|
|
38
42
|
// 注册到插件运行时状态(kook.endpoint list 的"运行中"数据源)
|
|
39
43
|
context.use(kookRuntimeStateToken).endpoints.set(config.id, {
|
|
40
44
|
id: config.id,
|
|
@@ -44,6 +48,7 @@ export default defineAdapter<KookAdapterConfig>({
|
|
|
44
48
|
return new KookWebhookEndpoint({
|
|
45
49
|
id: context.id,
|
|
46
50
|
gateway,
|
|
51
|
+
sideEvents,
|
|
47
52
|
http: context.use(httpHostToken),
|
|
48
53
|
config,
|
|
49
54
|
});
|
|
@@ -51,6 +56,7 @@ export default defineAdapter<KookAdapterConfig>({
|
|
|
51
56
|
return new KookWebsocketEndpoint({
|
|
52
57
|
id: context.id,
|
|
53
58
|
gateway,
|
|
59
|
+
sideEvents,
|
|
54
60
|
config,
|
|
55
61
|
});
|
|
56
62
|
},
|
package/lib/endpoint.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import type { MessageGateway } from '@zhin.js/core/runtime';
|
|
1
|
+
import { type EndpointControl, type EndpointInstance, type EndpointManagement, type EndpointSendRequest } from 'zhin.js/adapter';
|
|
2
|
+
import type { MessageGateway, SideEventGateway } from '@zhin.js/core/runtime';
|
|
3
3
|
import type { HttpHost } from '@zhin.js/host-http';
|
|
4
4
|
import type { CapabilityId } from 'zhin.js';
|
|
5
5
|
import { type KookInboundMessage, type ResolvedKookWebhookConfig, type ResolvedKookWebsocketConfig } from './protocol.js';
|
|
@@ -7,12 +7,14 @@ import { type CreateKookClient, type KookClientTransport } from './ws.js';
|
|
|
7
7
|
export interface KookEndpointOptions {
|
|
8
8
|
readonly id: CapabilityId;
|
|
9
9
|
readonly gateway: MessageGateway;
|
|
10
|
+
readonly sideEvents?: SideEventGateway;
|
|
10
11
|
readonly config: ResolvedKookWebsocketConfig;
|
|
11
12
|
readonly createClient?: CreateKookClient;
|
|
12
13
|
}
|
|
13
14
|
export declare class KookWebsocketEndpoint implements EndpointInstance {
|
|
14
15
|
#private;
|
|
15
16
|
readonly management: EndpointManagement;
|
|
17
|
+
readonly control: EndpointControl;
|
|
16
18
|
constructor(options: KookEndpointOptions);
|
|
17
19
|
start(): Promise<void>;
|
|
18
20
|
open(): void;
|
|
@@ -42,6 +44,7 @@ export declare class KookWebsocketEndpoint implements EndpointInstance {
|
|
|
42
44
|
export interface KookWebhookEndpointOptions {
|
|
43
45
|
readonly id: CapabilityId;
|
|
44
46
|
readonly gateway: MessageGateway;
|
|
47
|
+
readonly sideEvents?: SideEventGateway;
|
|
45
48
|
readonly http: HttpHost;
|
|
46
49
|
readonly config: ResolvedKookWebhookConfig;
|
|
47
50
|
readonly createClient?: CreateKookClient;
|
|
@@ -49,6 +52,7 @@ export interface KookWebhookEndpointOptions {
|
|
|
49
52
|
export declare class KookWebhookEndpoint implements EndpointInstance {
|
|
50
53
|
#private;
|
|
51
54
|
readonly management: EndpointManagement;
|
|
55
|
+
readonly control: EndpointControl;
|
|
52
56
|
constructor(options: KookWebhookEndpointOptions);
|
|
53
57
|
/** Used by webhook handler. */
|
|
54
58
|
get isOpen(): boolean;
|
package/lib/endpoint.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { createRecallEndpointControl, } from 'zhin.js/adapter';
|
|
1
2
|
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
2
3
|
import { registerKookAgentEndpoint } from './kook-agent-deps.js';
|
|
3
4
|
import { formatInboundContent, formatOutboundKmarkdown, isKookBotMentioned, kookInboundConversation, senderDisplayName, } from './protocol.js';
|
|
4
5
|
import { registerKookWebhookRoutes } from './webhook.js';
|
|
5
6
|
import { defaultCreateClient, defaultCreateWebhookClient, normalizeKookMessage, } from './ws.js';
|
|
7
|
+
import { receiveKookSideEvent } from './side-event-dispatch.js';
|
|
6
8
|
export class KookWebsocketEndpoint {
|
|
7
9
|
#logger;
|
|
8
10
|
#options;
|
|
@@ -12,6 +14,7 @@ export class KookWebsocketEndpoint {
|
|
|
12
14
|
#started = false;
|
|
13
15
|
#unregisterAgent;
|
|
14
16
|
management = createKookEndpointManagement(() => this.#requireClient());
|
|
17
|
+
control = createRecallEndpointControl((id) => this.recallMessage(id));
|
|
15
18
|
constructor(options) {
|
|
16
19
|
this.#logger = getAdapterLogger('kook', options.config.id);
|
|
17
20
|
this.#options = options;
|
|
@@ -143,6 +146,10 @@ export class KookWebsocketEndpoint {
|
|
|
143
146
|
if (msg)
|
|
144
147
|
this.admit(msg);
|
|
145
148
|
});
|
|
149
|
+
const receiver = client.receiver;
|
|
150
|
+
receiver?.on('event', (raw) => {
|
|
151
|
+
receiveKookSideEvent(this.#options.sideEvents, this.#options.config.id, raw, this.#logger);
|
|
152
|
+
});
|
|
146
153
|
}
|
|
147
154
|
#requireClient() {
|
|
148
155
|
if (!this.#client)
|
|
@@ -161,6 +168,7 @@ export class KookWebhookEndpoint {
|
|
|
161
168
|
#started = false;
|
|
162
169
|
#unregisterAgent;
|
|
163
170
|
management = createKookEndpointManagement(() => this.#requireClient());
|
|
171
|
+
control = createRecallEndpointControl((id) => this.recallMessage(id));
|
|
164
172
|
constructor(options) {
|
|
165
173
|
this.#logger = getAdapterLogger('kook', options.config.id);
|
|
166
174
|
this.#options = options;
|
package/lib/protocol.js
CHANGED
|
@@ -146,6 +146,8 @@ export function formatOutboundKmarkdown(payload) {
|
|
|
146
146
|
switch (item.type) {
|
|
147
147
|
case 'text':
|
|
148
148
|
return String(data.text ?? data.content ?? '');
|
|
149
|
+
case 'markdown':
|
|
150
|
+
return String(data.content ?? data.text ?? '');
|
|
149
151
|
case 'at': {
|
|
150
152
|
const id = String(data.user_id ?? data.qq ?? data.id ?? '');
|
|
151
153
|
return id === 'all' ? '(met)all(met)' : `(met)${id}(met)`;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { SideEventGateway } from '@zhin.js/core/runtime';
|
|
2
|
+
import { type getAdapterLogger } from '@zhin.js/logger';
|
|
3
|
+
export declare function receiveKookSideEvent(sideEvents: SideEventGateway | undefined, configId: string, raw: unknown, logger: ReturnType<typeof getAdapterLogger>): boolean;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { buildNotice, mapNoticeParts, senderFromId, KOOK_NOTICE_PARTS_MAP } from '@zhin.js/core';
|
|
2
|
+
import { formatCompact } from '@zhin.js/logger';
|
|
3
|
+
function extractKookNoticeType(raw) {
|
|
4
|
+
if (!raw || typeof raw !== 'object')
|
|
5
|
+
return null;
|
|
6
|
+
const event = raw;
|
|
7
|
+
const extraType = event.extra?.type;
|
|
8
|
+
if (typeof extraType === 'string' && extraType)
|
|
9
|
+
return extraType;
|
|
10
|
+
if (event.channel_type === 'NOTICE' && event.type != null) {
|
|
11
|
+
return String(event.type);
|
|
12
|
+
}
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
export function receiveKookSideEvent(sideEvents, configId, raw, logger) {
|
|
16
|
+
if (!sideEvents)
|
|
17
|
+
return false;
|
|
18
|
+
const noticeType = extractKookNoticeType(raw);
|
|
19
|
+
if (!noticeType)
|
|
20
|
+
return false;
|
|
21
|
+
if (!Object.prototype.hasOwnProperty.call(KOOK_NOTICE_PARTS_MAP, noticeType))
|
|
22
|
+
return false;
|
|
23
|
+
const event = raw;
|
|
24
|
+
const parts = mapNoticeParts('kook', noticeType);
|
|
25
|
+
const guildId = event.extra?.guild_id;
|
|
26
|
+
const userId = event.author_id ?? event.extra?.author?.id;
|
|
27
|
+
const sceneId = guildId != null
|
|
28
|
+
? String(guildId)
|
|
29
|
+
: userId != null
|
|
30
|
+
? String(userId)
|
|
31
|
+
: configId;
|
|
32
|
+
void sideEvents.receiveNotice(buildNotice(event, {
|
|
33
|
+
$id: `kook:${noticeType}:${event.msg_timestamp ?? Date.now()}:${sceneId}:${String(userId ?? '')}`,
|
|
34
|
+
$adapter: 'kook',
|
|
35
|
+
$endpoint: configId,
|
|
36
|
+
$type: 'notice',
|
|
37
|
+
$scene_id: sceneId,
|
|
38
|
+
$scene_type: parts.scene_type,
|
|
39
|
+
$sub_type: parts.sub_type,
|
|
40
|
+
$actor: senderFromId(userId, event.extra?.author?.username),
|
|
41
|
+
$timestamp: event.msg_timestamp ?? Date.now(),
|
|
42
|
+
})).catch((err) => {
|
|
43
|
+
logger.warn(formatCompact({
|
|
44
|
+
op: 'kook_side_event_failed',
|
|
45
|
+
endpoint: configId,
|
|
46
|
+
event: noticeType,
|
|
47
|
+
error: err instanceof Error ? err.message : String(err),
|
|
48
|
+
}));
|
|
49
|
+
});
|
|
50
|
+
return true;
|
|
51
|
+
}
|
package/lib/webhook.d.ts
CHANGED
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
5
5
|
import type { HttpHost, HttpRouteRegistration } from '@zhin.js/host-http';
|
|
6
|
+
import type { SideEventGateway } from '@zhin.js/core/runtime';
|
|
6
7
|
import { type KookInboundMessage, type ResolvedKookWebhookConfig } from './protocol.js';
|
|
7
8
|
export interface KookWebhookHandler {
|
|
8
9
|
readonly config: ResolvedKookWebhookConfig;
|
|
9
10
|
readonly isOpen: boolean;
|
|
10
11
|
readonly selfId?: string;
|
|
12
|
+
readonly sideEvents?: SideEventGateway;
|
|
11
13
|
admit(msg: KookInboundMessage): void;
|
|
12
14
|
checkAndRememberSn(sn: number): boolean;
|
|
13
15
|
}
|
package/lib/webhook.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { formatCompact, getLogger } from '@zhin.js/logger';
|
|
2
2
|
import { isKookWebhookChallenge, normalizeKookWebhookEvent, parseKookWebhookBody, readRequestBody, verifyKookWebhookToken, } from './protocol.js';
|
|
3
|
+
import { receiveKookSideEvent } from './side-event-dispatch.js';
|
|
3
4
|
const logger = getLogger('kook');
|
|
4
5
|
export function registerKookWebhookRoutes(http, handler) {
|
|
5
6
|
const path = handler.config.webhookPath;
|
|
@@ -67,6 +68,9 @@ export async function handleKookWebhookRequest(request, response, handler) {
|
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
70
|
function handleKookWebhookEvent(event, handler) {
|
|
71
|
+
if (receiveKookSideEvent(handler.sideEvents, handler.config.id, event, logger)) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
70
74
|
const msg = normalizeKookWebhookEvent(event, {
|
|
71
75
|
ignore: handler.config.ignore,
|
|
72
76
|
selfId: handler.selfId,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-kook",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.0",
|
|
4
4
|
"description": "Zhin.js KOOK adapter for Plugin Runtime (WebSocket gateway or Webhook)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -34,20 +34,20 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"kook-client": "^1.0.4",
|
|
37
|
-
"@zhin.js/adapter": "1.
|
|
38
|
-
"@zhin.js/core": "1.5.
|
|
39
|
-
"@zhin.js/host-http": "1.0.
|
|
40
|
-
"@zhin.js/im-contract": "1.0.
|
|
37
|
+
"@zhin.js/adapter": "1.2.0",
|
|
38
|
+
"@zhin.js/core": "1.5.13",
|
|
39
|
+
"@zhin.js/host-http": "1.0.12",
|
|
40
|
+
"@zhin.js/im-contract": "1.0.4",
|
|
41
41
|
"@zhin.js/logger": "1.0.76",
|
|
42
|
-
"@zhin.js/permission": "1.0.
|
|
42
|
+
"@zhin.js/permission": "1.0.3"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"zod": "^4.0.0",
|
|
46
|
-
"@zhin.js/adapter": "1.
|
|
47
|
-
"@zhin.js/agent": "1.1.
|
|
48
|
-
"@zhin.js/command": "1.0.
|
|
49
|
-
"@zhin.js/core": "1.5.
|
|
50
|
-
"zhin.js": "6.0.
|
|
46
|
+
"@zhin.js/adapter": "1.2.0",
|
|
47
|
+
"@zhin.js/agent": "1.1.15",
|
|
48
|
+
"@zhin.js/command": "1.0.15",
|
|
49
|
+
"@zhin.js/core": "1.5.13",
|
|
50
|
+
"zhin.js": "6.0.13"
|
|
51
51
|
},
|
|
52
52
|
"peerDependenciesMeta": {
|
|
53
53
|
"@zhin.js/agent": {
|
|
@@ -68,9 +68,9 @@
|
|
|
68
68
|
"typescript": "^6.0.3",
|
|
69
69
|
"vitest": "^4.1.10",
|
|
70
70
|
"zod": "^4.4.3",
|
|
71
|
-
"@zhin.js/agent": "1.1.
|
|
72
|
-
"@zhin.js/host-http": "1.0.
|
|
73
|
-
"zhin.js": "6.0.
|
|
71
|
+
"@zhin.js/agent": "1.1.15",
|
|
72
|
+
"@zhin.js/host-http": "1.0.12",
|
|
73
|
+
"zhin.js": "6.0.13"
|
|
74
74
|
},
|
|
75
75
|
"files": [
|
|
76
76
|
"adapters",
|
package/src/endpoint.ts
CHANGED
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
* KookEndpoint — lifecycle, outbound, admit, OpenAPI helpers for agent tools.
|
|
3
3
|
*/
|
|
4
4
|
import { Client } from 'kook-client';
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
import {
|
|
6
|
+
createRecallEndpointControl,
|
|
7
|
+
type EndpointControl,
|
|
8
|
+
type EndpointChannel,
|
|
9
|
+
type EndpointGroup,
|
|
10
|
+
type EndpointInstance,
|
|
11
|
+
type EndpointManagement,
|
|
12
|
+
type EndpointSendRequest,
|
|
11
13
|
} from 'zhin.js/adapter';
|
|
12
|
-
import type { MessageGateway } from '@zhin.js/core/runtime';
|
|
14
|
+
import type { MessageGateway, SideEventGateway } from '@zhin.js/core/runtime';
|
|
13
15
|
import type { HttpHost, HttpRouteRegistration } from '@zhin.js/host-http';
|
|
14
16
|
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
15
17
|
import type { CapabilityId } from 'zhin.js';
|
|
@@ -32,10 +34,12 @@ import {
|
|
|
32
34
|
type CreateKookClient,
|
|
33
35
|
type KookClientTransport,
|
|
34
36
|
} from './ws.js';
|
|
37
|
+
import { receiveKookSideEvent } from './side-event-dispatch.js';
|
|
35
38
|
|
|
36
39
|
export interface KookEndpointOptions {
|
|
37
40
|
readonly id: CapabilityId;
|
|
38
41
|
readonly gateway: MessageGateway;
|
|
42
|
+
readonly sideEvents?: SideEventGateway;
|
|
39
43
|
readonly config: ResolvedKookWebsocketConfig;
|
|
40
44
|
readonly createClient?: CreateKookClient;
|
|
41
45
|
}
|
|
@@ -50,6 +54,7 @@ export class KookWebsocketEndpoint implements EndpointInstance {
|
|
|
50
54
|
#started = false;
|
|
51
55
|
#unregisterAgent?: () => void;
|
|
52
56
|
readonly management: EndpointManagement = createKookEndpointManagement(() => this.#requireClient());
|
|
57
|
+
readonly control: EndpointControl = createRecallEndpointControl((id) => this.recallMessage(id));
|
|
53
58
|
|
|
54
59
|
constructor(options: KookEndpointOptions) {
|
|
55
60
|
this.#logger = getAdapterLogger('kook', options.config.id);
|
|
@@ -191,6 +196,10 @@ export class KookWebsocketEndpoint implements EndpointInstance {
|
|
|
191
196
|
const msg = normalizeKookMessage(raw);
|
|
192
197
|
if (msg) this.admit(msg);
|
|
193
198
|
});
|
|
199
|
+
const receiver = (client as { receiver?: { on(event: string, listener: (...args: unknown[]) => void): void } }).receiver;
|
|
200
|
+
receiver?.on('event', (raw) => {
|
|
201
|
+
receiveKookSideEvent(this.#options.sideEvents, this.#options.config.id, raw, this.#logger);
|
|
202
|
+
});
|
|
194
203
|
}
|
|
195
204
|
|
|
196
205
|
#requireClient(): KookClientTransport {
|
|
@@ -202,6 +211,7 @@ export class KookWebsocketEndpoint implements EndpointInstance {
|
|
|
202
211
|
export interface KookWebhookEndpointOptions {
|
|
203
212
|
readonly id: CapabilityId;
|
|
204
213
|
readonly gateway: MessageGateway;
|
|
214
|
+
readonly sideEvents?: SideEventGateway;
|
|
205
215
|
readonly http: HttpHost;
|
|
206
216
|
readonly config: ResolvedKookWebhookConfig;
|
|
207
217
|
readonly createClient?: CreateKookClient;
|
|
@@ -219,6 +229,7 @@ export class KookWebhookEndpoint implements EndpointInstance {
|
|
|
219
229
|
#started = false;
|
|
220
230
|
#unregisterAgent?: () => void;
|
|
221
231
|
readonly management: EndpointManagement = createKookEndpointManagement(() => this.#requireClient());
|
|
232
|
+
readonly control: EndpointControl = createRecallEndpointControl((id) => this.recallMessage(id));
|
|
222
233
|
|
|
223
234
|
constructor(options: KookWebhookEndpointOptions) {
|
|
224
235
|
this.#logger = getAdapterLogger('kook', options.config.id);
|
package/src/protocol.ts
CHANGED
|
@@ -279,6 +279,8 @@ export function formatOutboundKmarkdown(payload: unknown): string {
|
|
|
279
279
|
switch (item.type) {
|
|
280
280
|
case 'text':
|
|
281
281
|
return String(data.text ?? data.content ?? '');
|
|
282
|
+
case 'markdown':
|
|
283
|
+
return String(data.content ?? data.text ?? '');
|
|
282
284
|
case 'at': {
|
|
283
285
|
const id = String(data.user_id ?? data.qq ?? data.id ?? '');
|
|
284
286
|
return id === 'all' ? '(met)all(met)' : `(met)${id}(met)`;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { buildNotice, mapNoticeParts, senderFromId, KOOK_NOTICE_PARTS_MAP } from '@zhin.js/core';
|
|
2
|
+
import type { SideEventGateway } from '@zhin.js/core/runtime';
|
|
3
|
+
import { formatCompact, type getAdapterLogger } from '@zhin.js/logger';
|
|
4
|
+
import type { KookWebhookEventData } from './protocol.js';
|
|
5
|
+
|
|
6
|
+
function extractKookNoticeType(raw: unknown): string | null {
|
|
7
|
+
if (!raw || typeof raw !== 'object') return null;
|
|
8
|
+
const event = raw as KookWebhookEventData & { extra?: { type?: string } };
|
|
9
|
+
const extraType = event.extra?.type;
|
|
10
|
+
if (typeof extraType === 'string' && extraType) return extraType;
|
|
11
|
+
if (event.channel_type === 'NOTICE' && event.type != null) {
|
|
12
|
+
return String(event.type);
|
|
13
|
+
}
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function receiveKookSideEvent(
|
|
18
|
+
sideEvents: SideEventGateway | undefined,
|
|
19
|
+
configId: string,
|
|
20
|
+
raw: unknown,
|
|
21
|
+
logger: ReturnType<typeof getAdapterLogger>,
|
|
22
|
+
): boolean {
|
|
23
|
+
if (!sideEvents) return false;
|
|
24
|
+
const noticeType = extractKookNoticeType(raw);
|
|
25
|
+
if (!noticeType) return false;
|
|
26
|
+
if (!Object.prototype.hasOwnProperty.call(KOOK_NOTICE_PARTS_MAP, noticeType)) return false;
|
|
27
|
+
const event = raw as KookWebhookEventData;
|
|
28
|
+
const parts = mapNoticeParts('kook', noticeType);
|
|
29
|
+
const guildId = event.extra?.guild_id;
|
|
30
|
+
const userId = event.author_id ?? event.extra?.author?.id;
|
|
31
|
+
const sceneId = guildId != null
|
|
32
|
+
? String(guildId)
|
|
33
|
+
: userId != null
|
|
34
|
+
? String(userId)
|
|
35
|
+
: configId;
|
|
36
|
+
void sideEvents.receiveNotice(buildNotice(event, {
|
|
37
|
+
$id: `kook:${noticeType}:${event.msg_timestamp ?? Date.now()}:${sceneId}:${String(userId ?? '')}`,
|
|
38
|
+
$adapter: 'kook' as never,
|
|
39
|
+
$endpoint: configId,
|
|
40
|
+
$type: 'notice',
|
|
41
|
+
$scene_id: sceneId,
|
|
42
|
+
$scene_type: parts.scene_type,
|
|
43
|
+
$sub_type: parts.sub_type,
|
|
44
|
+
$actor: senderFromId(userId, event.extra?.author?.username),
|
|
45
|
+
$timestamp: event.msg_timestamp ?? Date.now(),
|
|
46
|
+
})).catch((err) => {
|
|
47
|
+
logger.warn(formatCompact({
|
|
48
|
+
op: 'kook_side_event_failed',
|
|
49
|
+
endpoint: configId,
|
|
50
|
+
event: noticeType,
|
|
51
|
+
error: err instanceof Error ? err.message : String(err),
|
|
52
|
+
}));
|
|
53
|
+
});
|
|
54
|
+
return true;
|
|
55
|
+
}
|
package/src/webhook.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
5
5
|
import type { HttpHost, HttpRouteRegistration } from '@zhin.js/host-http';
|
|
6
|
+
import type { SideEventGateway } from '@zhin.js/core/runtime';
|
|
6
7
|
import { formatCompact, getLogger } from '@zhin.js/logger';
|
|
7
8
|
import {
|
|
8
9
|
isKookWebhookChallenge,
|
|
@@ -15,6 +16,7 @@ import {
|
|
|
15
16
|
type KookWebhookFrame,
|
|
16
17
|
type ResolvedKookWebhookConfig,
|
|
17
18
|
} from './protocol.js';
|
|
19
|
+
import { receiveKookSideEvent } from './side-event-dispatch.js';
|
|
18
20
|
|
|
19
21
|
const logger = getLogger('kook');
|
|
20
22
|
|
|
@@ -22,6 +24,7 @@ export interface KookWebhookHandler {
|
|
|
22
24
|
readonly config: ResolvedKookWebhookConfig;
|
|
23
25
|
readonly isOpen: boolean;
|
|
24
26
|
readonly selfId?: string;
|
|
27
|
+
readonly sideEvents?: SideEventGateway;
|
|
25
28
|
admit(msg: KookInboundMessage): void;
|
|
26
29
|
checkAndRememberSn(sn: number): boolean;
|
|
27
30
|
}
|
|
@@ -108,6 +111,9 @@ function handleKookWebhookEvent(
|
|
|
108
111
|
event: KookWebhookEventData,
|
|
109
112
|
handler: KookWebhookHandler,
|
|
110
113
|
): void {
|
|
114
|
+
if (receiveKookSideEvent(handler.sideEvents, handler.config.id, event, logger)) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
111
117
|
const msg = normalizeKookWebhookEvent(event, {
|
|
112
118
|
ignore: handler.config.ignore,
|
|
113
119
|
selfId: handler.selfId,
|