@zhin.js/adapter-kook 7.0.14 → 8.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,41 @@
1
1
  # @zhin.js/adapter-kook
2
2
 
3
+ ## 8.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 1fc78bc: Unify native platform Client access behind the literal `adapter` discriminant. Handlers infer both native events and Clients, while command, inbound/outbound middleware, and both Agent tool authoring surfaces expose the exact operation-scoped Client through a lazy `$client` getter. Definitions without `adapter` keep `$client` typed as `unknown`, and runtime dispatch rejects adapter mismatches before resolving the Client. Bundled platform tools now use this single path instead of model-provided endpoint ids and adapter-specific dependency wrappers. Every adapter registers one Client/EventMap contract, and protocol adapters including NapCat, Milky, OneBot and Satori now produce transport-independent Client objects rather than letting Endpoint instances impersonate Clients.
8
+ - Updated dependencies [e9c6a73]
9
+ - Updated dependencies [4e8117c]
10
+ - Updated dependencies [902fa35]
11
+ - Updated dependencies [54bfd6b]
12
+ - Updated dependencies [12025ee]
13
+ - Updated dependencies [09b14d6]
14
+ - Updated dependencies [1fc78bc]
15
+ - @zhin.js/agent@1.1.16
16
+ - @zhin.js/adapter@1.2.1
17
+ - @zhin.js/core@1.5.14
18
+ - @zhin.js/host-http@1.0.13
19
+ - @zhin.js/command@1.0.16
20
+ - @zhin.js/logger@1.0.77
21
+ - zhin.js@6.0.14
22
+ - @zhin.js/feature-kit@1.0.13
23
+ - @zhin.js/permission@1.0.4
24
+
25
+ ## 8.0.0
26
+
27
+ ### Patch Changes
28
+
29
+ - 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.
30
+ - Updated dependencies [b10d058]
31
+ - Updated dependencies [f2c532f]
32
+ - Updated dependencies [3dbf990]
33
+ - @zhin.js/host-http@1.0.12
34
+ - @zhin.js/adapter@1.2.0
35
+ - @zhin.js/core@1.5.13
36
+ - @zhin.js/agent@1.1.15
37
+ - zhin.js@6.0.13
38
+
3
39
  ## 7.0.14
4
40
 
5
41
  ### Patch Changes
package/README.md CHANGED
@@ -20,7 +20,7 @@ pnpm add @zhin.js/adapter-kook
20
20
  ## Plugin Runtime
21
21
 
22
22
  - `@zhin.js/adapter` — 约定式 `adapters/kook.ts`(`defineAdapter`)
23
- - `@zhin.js/core` — `messageGatewayToken` 入站/出站
23
+ - `@zhin.js/core` — `Endpoint.emit(...)` 入站、`outboundMessageToken` 出站
24
24
  - `@zhin.js/host-http` — Webhook 模式 POST 路由(WebSocket 不需要)
25
25
  - `zhin.js` — `plugin.ts`(`definePlugin`)
26
26
  - 配置经插件 `schema.json` 落到 `plugins.<instanceKey>`
@@ -97,7 +97,16 @@ platform permit checker 由 `plugin.ts` 的 generation 生命周期注册;Capa
97
97
 
98
98
  ## 迁移后出站能力变化
99
99
 
100
- 迁移到 Plugin Runtime 后,出站统一经 `messageGatewayToken` 渲染并由 endpoint 编码为 KMarkdown(`sendChannelMsg` / `sendPrivateMsg`)。canonical `markdown` 保留格式;图片、视频、音频和文件仅有远程 URL 时可表示为 KMarkdown 链接。卡片消息与附件上传仍未接入统一出站通道。
100
+ 迁移到 Plugin Runtime 后,出站统一经 `outboundMessageToken` 渲染并由 endpoint 编码为 KMarkdown(`sendChannelMsg` / `sendPrivateMsg`)。canonical `markdown` 保留格式;图片、视频、音频和文件仅有远程 URL 时可表示为 KMarkdown 链接。卡片消息与附件上传仍未接入统一出站通道。
101
+
102
+ ## 故障排查
103
+
104
+ | 现象 | 排查 |
105
+ | --- | --- |
106
+ | WebSocket 无法上线 | 检查 Bot Token、网络与机器人能力开关 |
107
+ | Webhook challenge 失败 | 检查公网路径、`verify_token` 与 HTTP Host |
108
+ | 频道消息未触发 | 检查应用订阅、频道权限与机器人是否已加入服务器 |
109
+ | 附件表现为链接 | 当前统一出站不上传附件;使用远程 URL 或按能力降级 |
101
110
 
102
111
  ## 许可证
103
112
 
package/adapters/kook.js CHANGED
@@ -4,7 +4,6 @@
4
4
  * Implementation lives under `src/` (endpoint / webhook / ws / protocol).
5
5
  */
6
6
  import { defineAdapter } from 'zhin.js/adapter';
7
- import { messageGatewayToken, sideEventGatewayToken } from '@zhin.js/core/runtime';
8
7
  import { httpHostToken } from '@zhin.js/host-http';
9
8
  import { KookWebhookEndpoint, KookWebsocketEndpoint, } from "../lib/endpoint.js";
10
9
  import { resolveKookConfig, } from "../lib/protocol.js";
@@ -12,6 +11,7 @@ import { kookRuntimeStateToken } from "../lib/kook-runtime-state.js";
12
11
  export { KookWebhookEndpoint, KookWebsocketEndpoint, } from "../lib/endpoint.js";
13
12
  export default defineAdapter({
14
13
  capabilities: ['inbound', 'outbound'],
14
+ operations: ['recall'],
15
15
  // KOOK 图片消息消费远程 URL;KMarkdown 由 endpoint codec 原生消费;
16
16
  // 无按钮交互面,交互段降级纯文本。
17
17
  segments: {
@@ -21,8 +21,6 @@ export default defineAdapter({
21
21
  },
22
22
  create(context) {
23
23
  const config = resolveKookConfig(context.config);
24
- const gateway = context.use(messageGatewayToken);
25
- const sideEvents = context.use(sideEventGatewayToken);
26
24
  // 注册到插件运行时状态(kook.endpoint list 的"运行中"数据源)
27
25
  context.use(kookRuntimeStateToken).endpoints.set(config.id, {
28
26
  id: config.id,
@@ -31,16 +29,12 @@ export default defineAdapter({
31
29
  if (config.connection === 'webhook') {
32
30
  return new KookWebhookEndpoint({
33
31
  id: context.id,
34
- gateway,
35
- sideEvents,
36
32
  http: context.use(httpHostToken),
37
33
  config,
38
34
  });
39
35
  }
40
36
  return new KookWebsocketEndpoint({
41
37
  id: context.id,
42
- gateway,
43
- sideEvents,
44
38
  config,
45
39
  });
46
40
  },
package/adapters/kook.ts CHANGED
@@ -3,7 +3,6 @@
3
3
  * Implementation lives under `src/` (endpoint / webhook / ws / protocol).
4
4
  */
5
5
  import { defineAdapter } from 'zhin.js/adapter';
6
- import { messageGatewayToken, sideEventGatewayToken } from '@zhin.js/core/runtime';
7
6
  import { httpHostToken } from '@zhin.js/host-http';
8
7
  import {
9
8
  KookWebhookEndpoint,
@@ -27,6 +26,7 @@ export type { CreateKookClient, KookClientTransport } from '../src/ws.js';
27
26
 
28
27
  export default defineAdapter<KookAdapterConfig>({
29
28
  capabilities: ['inbound', 'outbound'],
29
+ operations: ['recall'],
30
30
  // KOOK 图片消息消费远程 URL;KMarkdown 由 endpoint codec 原生消费;
31
31
  // 无按钮交互面,交互段降级纯文本。
32
32
  segments: {
@@ -36,8 +36,6 @@ export default defineAdapter<KookAdapterConfig>({
36
36
  },
37
37
  create(context) {
38
38
  const config = resolveKookConfig(context.config);
39
- const gateway = context.use(messageGatewayToken);
40
- const sideEvents = context.use(sideEventGatewayToken);
41
39
  // 注册到插件运行时状态(kook.endpoint list 的"运行中"数据源)
42
40
  context.use(kookRuntimeStateToken).endpoints.set(config.id, {
43
41
  id: config.id,
@@ -46,16 +44,12 @@ export default defineAdapter<KookAdapterConfig>({
46
44
  if (config.connection === 'webhook') {
47
45
  return new KookWebhookEndpoint({
48
46
  id: context.id,
49
- gateway,
50
- sideEvents,
51
47
  http: context.use(httpHostToken),
52
48
  config,
53
49
  });
54
50
  }
55
51
  return new KookWebsocketEndpoint({
56
52
  id: context.id,
57
- gateway,
58
- sideEvents,
59
53
  config,
60
54
  });
61
55
  },
@@ -1,29 +1,27 @@
1
1
  import { defineAgentTool } from '@zhin.js/agent/tools';
2
2
  import { z } from 'zod';
3
3
  import { platformPermit } from '../../src/platform-permit.js';
4
- import { getKookAgentDeps } from '../../src/kook-agent-deps.js';
5
4
 
6
- export default defineAgentTool<{ endpoint_id: string; guild_id: string; action: 'add' | 'remove'; user_id: string; remark?: string }>({
5
+ export default defineAgentTool<{ guild_id: string; action: 'add' | 'remove'; user_id: string; remark?: string }>({
7
6
  description: 'KOOK 服务器黑名单管理:添加/移除',
8
7
  inputSchema: z.object({
9
- endpoint_id: z.string().describe('Endpoint 名称'),
10
8
  guild_id: z.string().describe('服务器 ID'),
11
9
  action: z.enum(['add', 'remove']).describe('add|remove'),
12
10
  user_id: z.string().describe('用户 ID'),
13
11
  remark: z.string().optional().describe('备注(add 可选)'),
14
12
  }),
15
- platforms: ['kook'],
13
+ adapter: 'kook',
16
14
  tags: ['kook'],
17
15
  permissions: [platformPermit('guild_admin')],
18
- async execute({ endpoint_id, guild_id, action, user_id, remark }: { endpoint_id: string; guild_id: string; action: 'add' | 'remove'; user_id: string; remark?: string }) {
19
- const endpoint = getKookAgentDeps().getEndpoint(endpoint_id);
16
+ async execute({ guild_id, action, user_id, remark }: { guild_id: string; action: 'add' | 'remove'; user_id: string; remark?: string }, context) {
17
+ const member = context.$client.pickGuildMember(guild_id, user_id);
20
18
  switch (action) {
21
19
  case 'add': {
22
- const success = await endpoint.addToBlacklist(guild_id, user_id, remark);
20
+ const success = await member.addToBlackList(remark);
23
21
  return { success, message: success ? `已将 ${user_id} 加入黑名单` : '操作失败' };
24
22
  }
25
23
  case 'remove': {
26
- const success = await endpoint.removeFromBlacklist(guild_id, user_id);
24
+ const success = await member.removeFromBlackList();
27
25
  return { success, message: success ? `已将 ${user_id} 从黑名单移除` : '操作失败' };
28
26
  }
29
27
  default:
@@ -1,21 +1,19 @@
1
1
  import { defineAgentTool } from '@zhin.js/agent/tools';
2
2
  import { z } from 'zod';
3
3
  import { platformPermit } from '../../src/platform-permit.js';
4
- import { getKookAgentDeps } from '../../src/kook-agent-deps.js';
5
4
 
6
- export default defineAgentTool<{ endpoint_id: string; guild_id: string; name: string }>({
5
+ export default defineAgentTool<{ guild_id: string; name: string }>({
7
6
  description: '在 KOOK 服务器中创建新角色',
8
7
  inputSchema: z.object({
9
- endpoint_id: z.string().describe('Endpoint 名称'),
10
8
  guild_id: z.string().describe('服务器 ID'),
11
9
  name: z.string().describe('角色名称'),
12
10
  }),
13
- platforms: ['kook'],
11
+ adapter: 'kook',
14
12
  tags: ['kook'],
15
13
  permissions: [platformPermit('guild_owner')],
16
- async execute({ endpoint_id, guild_id, name }: { endpoint_id: string; guild_id: string; name: string }) {
17
- const endpoint = getKookAgentDeps().getEndpoint(endpoint_id);
18
- const role = await endpoint.createRole(guild_id, name);
14
+ async execute({ guild_id, name }: { guild_id: string; name: string }, context) {
15
+ const client = context.$client;
16
+ const role = await client.pickGuild(guild_id).createRole(name);
19
17
  return {
20
18
  success: true,
21
19
  message: `已创建角色 "${name}"`,
@@ -1,21 +1,19 @@
1
1
  import { defineAgentTool } from '@zhin.js/agent/tools';
2
2
  import { z } from 'zod';
3
3
  import { platformPermit } from '../../src/platform-permit.js';
4
- import { getKookAgentDeps } from '../../src/kook-agent-deps.js';
5
4
 
6
- export default defineAgentTool<{ endpoint_id: string; guild_id: string; role_id: string }>({
5
+ export default defineAgentTool<{ guild_id: string; role_id: string }>({
7
6
  description: '删除 KOOK 服务器中的角色',
8
7
  inputSchema: z.object({
9
- endpoint_id: z.string().describe('Endpoint 名称'),
10
8
  guild_id: z.string().describe('服务器 ID'),
11
9
  role_id: z.string().describe('角色 ID'),
12
10
  }),
13
- platforms: ['kook'],
11
+ adapter: 'kook',
14
12
  tags: ['kook'],
15
13
  permissions: [platformPermit('guild_owner')],
16
- async execute({ endpoint_id, guild_id, role_id }: { endpoint_id: string; guild_id: string; role_id: string }) {
17
- const endpoint = getKookAgentDeps().getEndpoint(endpoint_id);
18
- const success = await endpoint.deleteRole(guild_id, role_id);
14
+ async execute({ guild_id, role_id }: { guild_id: string; role_id: string }, context) {
15
+ const client = context.$client;
16
+ const success = await client.pickGuild(guild_id).deleteRole(role_id);
19
17
  return { success, message: success ? `已删除角色 ${role_id}` : '删除角色失败' };
20
18
  },
21
19
  });
@@ -1,22 +1,20 @@
1
1
  import { defineAgentTool } from '@zhin.js/agent/tools';
2
2
  import { z } from 'zod';
3
3
  import { platformPermit } from '../../src/platform-permit.js';
4
- import { getKookAgentDeps } from '../../src/kook-agent-deps.js';
5
4
 
6
- export default defineAgentTool<{ endpoint_id: string; guild_id: string; user_id: string; role_id: string }>({
5
+ export default defineAgentTool<{ guild_id: string; user_id: string; role_id: string }>({
7
6
  description: '给用户授予 KOOK 服务器角色',
8
7
  inputSchema: z.object({
9
- endpoint_id: z.string().describe('Endpoint 名称'),
10
8
  guild_id: z.string().describe('服务器 ID'),
11
9
  user_id: z.string().describe('用户 ID'),
12
10
  role_id: z.string().describe('角色 ID'),
13
11
  }),
14
- platforms: ['kook'],
12
+ adapter: 'kook',
15
13
  tags: ['kook'],
16
14
  permissions: [platformPermit('manage_roles')],
17
- async execute({ endpoint_id, guild_id, user_id, role_id }: { endpoint_id: string; guild_id: string; user_id: string; role_id: string }) {
18
- const endpoint = getKookAgentDeps().getEndpoint(endpoint_id);
19
- const success = await endpoint.grantRole(guild_id, user_id, role_id);
15
+ async execute({ guild_id, user_id, role_id }: { guild_id: string; user_id: string; role_id: string }, context) {
16
+ const client = context.$client;
17
+ const success = await client.pickGuildMember(guild_id, user_id).grant(role_id);
20
18
  return { success, message: success ? `已授予用户 ${user_id} 角色 ${role_id}` : '授予角色失败' };
21
19
  },
22
20
  });
@@ -1,18 +1,16 @@
1
1
  import { defineAgentTool } from '@zhin.js/agent/tools';
2
2
  import { z } from 'zod';
3
- import { getKookAgentDeps } from '../../src/kook-agent-deps.js';
4
3
 
5
- export default defineAgentTool<{ endpoint_id: string; guild_id: string }>({
4
+ export default defineAgentTool<{ guild_id: string }>({
6
5
  description: '获取 KOOK 服务器的角色列表',
7
6
  inputSchema: z.object({
8
- endpoint_id: z.string().describe('Endpoint 名称'),
9
7
  guild_id: z.string().describe('服务器 ID'),
10
8
  }),
11
- platforms: ['kook'],
9
+ adapter: 'kook',
12
10
  tags: ['kook'],
13
- async execute({ endpoint_id, guild_id }: { endpoint_id: string; guild_id: string }) {
14
- const endpoint = getKookAgentDeps().getEndpoint(endpoint_id);
15
- const roles = await endpoint.getRoleList(guild_id);
11
+ async execute({ guild_id }: { guild_id: string }, context) {
12
+ const client = context.$client;
13
+ const roles = await client.pickGuild(guild_id).getRoleList();
16
14
  return {
17
15
  roles: roles.map((r) => ({
18
16
  id: String(r.role_id),
@@ -1,22 +1,20 @@
1
1
  import { defineAgentTool } from '@zhin.js/agent/tools';
2
2
  import { z } from 'zod';
3
3
  import { platformPermit } from '../../src/platform-permit.js';
4
- import { getKookAgentDeps } from '../../src/kook-agent-deps.js';
5
4
 
6
- export default defineAgentTool<{ endpoint_id: string; guild_id: string; user_id: string; role_id: string }>({
5
+ export default defineAgentTool<{ guild_id: string; user_id: string; role_id: string }>({
7
6
  description: '撤销用户的 KOOK 服务器角色',
8
7
  inputSchema: z.object({
9
- endpoint_id: z.string().describe('Endpoint 名称'),
10
8
  guild_id: z.string().describe('服务器 ID'),
11
9
  user_id: z.string().describe('用户 ID'),
12
10
  role_id: z.string().describe('角色 ID'),
13
11
  }),
14
- platforms: ['kook'],
12
+ adapter: 'kook',
15
13
  tags: ['kook'],
16
14
  permissions: [platformPermit('manage_roles')],
17
- async execute({ endpoint_id, guild_id, user_id, role_id }: { endpoint_id: string; guild_id: string; user_id: string; role_id: string }) {
18
- const endpoint = getKookAgentDeps().getEndpoint(endpoint_id);
19
- const success = await endpoint.revokeRole(guild_id, user_id, role_id);
15
+ async execute({ guild_id, user_id, role_id }: { guild_id: string; user_id: string; role_id: string }, context) {
16
+ const client = context.$client;
17
+ const success = await client.pickGuildMember(guild_id, user_id).revoke(role_id);
20
18
  return { success, message: success ? `已撤销用户 ${user_id} 的角色 ${role_id}` : '撤销角色失败' };
21
19
  },
22
20
  });
@@ -0,0 +1,11 @@
1
+ import type { KookClientTransport } from './ws.js';
2
+ export type KookClientEventMap = Record<string, unknown>;
3
+ declare module '@zhin.js/feature-kit' {
4
+ interface AdapterClientRegistry {
5
+ readonly kook: {
6
+ readonly client: KookClientTransport;
7
+ readonly events: KookClientEventMap;
8
+ };
9
+ }
10
+ }
11
+ export declare const kookClient: import("@zhin.js/adapter").EndpointClientToken<KookClientTransport, KookClientEventMap>;
package/lib/client.js ADDED
@@ -0,0 +1,2 @@
1
+ import { defineEndpointClient } from 'zhin.js/adapter';
2
+ export const kookClient = defineEndpointClient('kook');
package/lib/endpoint.d.ts CHANGED
@@ -1,57 +1,41 @@
1
- import type { EndpointInstance, EndpointManagement, EndpointSendRequest } from 'zhin.js/adapter';
2
- import type { MessageGateway, SideEventGateway } from '@zhin.js/core/runtime';
1
+ import { Endpoint } from 'zhin.js/adapter';
2
+ import { type EndpointControl, type EndpointManagement, type EndpointSendRequest } from 'zhin.js/adapter';
3
3
  import type { HttpHost } from '@zhin.js/host-http';
4
4
  import type { CapabilityId } from 'zhin.js';
5
- import { type KookInboundMessage, type ResolvedKookWebhookConfig, type ResolvedKookWebsocketConfig } from './protocol.js';
5
+ import { type KookInboundMessage, type KookWebhookEventData, type ResolvedKookWebhookConfig, type ResolvedKookWebsocketConfig } from './protocol.js';
6
6
  import { type CreateKookClient, type KookClientTransport } from './ws.js';
7
7
  export interface KookEndpointOptions {
8
8
  readonly id: CapabilityId;
9
- readonly gateway: MessageGateway;
10
- readonly sideEvents?: SideEventGateway;
11
9
  readonly config: ResolvedKookWebsocketConfig;
12
10
  readonly createClient?: CreateKookClient;
13
11
  }
14
- export declare class KookWebsocketEndpoint implements EndpointInstance {
12
+ export declare class KookWebsocketEndpoint extends Endpoint<KookClientTransport> {
15
13
  #private;
16
14
  readonly management: EndpointManagement;
15
+ readonly control: EndpointControl;
17
16
  constructor(options: KookEndpointOptions);
17
+ get client(): KookClientTransport;
18
18
  start(): Promise<void>;
19
19
  open(): void;
20
20
  close(): void;
21
21
  stop(): Promise<void>;
22
22
  send({ conversation, payload }: EndpointSendRequest): Promise<string>;
23
- /** Test / internal: admit a message when open. */
23
+ /** Test / internal: admit a normalized message when open. */
24
24
  admit(msg: KookInboundMessage): void;
25
25
  recallMessage(messageId: string): Promise<void>;
26
- getRoleList(guildId: string): Promise<{
27
- role_id: string | number;
28
- name: string;
29
- color?: number;
30
- position?: number;
31
- permissions?: unknown;
32
- }[]>;
33
- createRole(guildId: string, name: string): Promise<{
34
- role_id: string | number;
35
- name: string;
36
- }>;
37
- deleteRole(guildId: string, roleId: string): Promise<boolean>;
38
- grantRole(guildId: string, userId: string, roleId: string): Promise<boolean>;
39
- revokeRole(guildId: string, userId: string, roleId: string): Promise<boolean>;
40
- addToBlacklist(guildId: string, userId: string, remark?: string): Promise<boolean>;
41
- removeFromBlacklist(guildId: string, userId: string): Promise<boolean>;
42
26
  }
43
27
  export interface KookWebhookEndpointOptions {
44
28
  readonly id: CapabilityId;
45
- readonly gateway: MessageGateway;
46
- readonly sideEvents?: SideEventGateway;
47
29
  readonly http: HttpHost;
48
30
  readonly config: ResolvedKookWebhookConfig;
49
31
  readonly createClient?: CreateKookClient;
50
32
  }
51
- export declare class KookWebhookEndpoint implements EndpointInstance {
33
+ export declare class KookWebhookEndpoint extends Endpoint<KookClientTransport> {
52
34
  #private;
53
35
  readonly management: EndpointManagement;
36
+ readonly control: EndpointControl;
54
37
  constructor(options: KookWebhookEndpointOptions);
38
+ get client(): KookClientTransport;
55
39
  /** Used by webhook handler. */
56
40
  get isOpen(): boolean;
57
41
  get config(): ResolvedKookWebhookConfig;
@@ -61,26 +45,11 @@ export declare class KookWebhookEndpoint implements EndpointInstance {
61
45
  close(): void;
62
46
  stop(): Promise<void>;
63
47
  send({ conversation, payload }: EndpointSendRequest): Promise<string>;
48
+ admitEvent(event: KookWebhookEventData): void;
64
49
  /** Test / internal: admit a message when open. */
65
50
  admit(msg: KookInboundMessage): void;
66
51
  recallMessage(messageId: string): Promise<void>;
67
52
  checkAndRememberSn(sn: number): boolean;
68
- getRoleList(guildId: string): Promise<{
69
- role_id: string | number;
70
- name: string;
71
- color?: number;
72
- position?: number;
73
- permissions?: unknown;
74
- }[]>;
75
- createRole(guildId: string, name: string): Promise<{
76
- role_id: string | number;
77
- name: string;
78
- }>;
79
- deleteRole(guildId: string, roleId: string): Promise<boolean>;
80
- grantRole(guildId: string, userId: string, roleId: string): Promise<boolean>;
81
- revokeRole(guildId: string, userId: string, roleId: string): Promise<boolean>;
82
- addToBlacklist(guildId: string, userId: string, remark?: string): Promise<boolean>;
83
- removeFromBlacklist(guildId: string, userId: string): Promise<boolean>;
84
53
  }
85
54
  /**
86
55
  * KOOK endpoint 的 EndpointManagement 语义端口(websocket / webhook 共用)。
package/lib/endpoint.js CHANGED
@@ -1,29 +1,33 @@
1
+ import { Endpoint } from 'zhin.js/adapter';
2
+ import { createRecallEndpointControl, } from 'zhin.js/adapter';
1
3
  import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
2
- import { registerKookAgentEndpoint } from './kook-agent-deps.js';
3
- import { formatInboundContent, formatOutboundKmarkdown, isKookBotMentioned, kookInboundConversation, senderDisplayName, } from './protocol.js';
4
+ import { formatInboundContent, formatOutboundKmarkdown, isKookBotMentioned, kookInboundConversation, normalizeKookWebhookEvent, senderDisplayName, } from './protocol.js';
4
5
  import { registerKookWebhookRoutes } from './webhook.js';
5
6
  import { defaultCreateClient, defaultCreateWebhookClient, normalizeKookMessage, } from './ws.js';
6
7
  import { receiveKookSideEvent } from './side-event-dispatch.js';
7
- export class KookWebsocketEndpoint {
8
+ export class KookWebsocketEndpoint extends Endpoint {
8
9
  #logger;
9
10
  #options;
10
11
  #createClient;
11
12
  #client = null;
12
13
  #open = false;
13
14
  #started = false;
14
- #unregisterAgent;
15
15
  management = createKookEndpointManagement(() => this.#requireClient());
16
+ control = createRecallEndpointControl((id) => this.recallMessage(id));
16
17
  constructor(options) {
18
+ super();
17
19
  this.#logger = getAdapterLogger('kook', options.config.id);
18
20
  this.#options = options;
19
21
  this.#createClient = options.createClient ?? defaultCreateClient;
20
22
  }
23
+ get client() {
24
+ return this.#requireClient();
25
+ }
21
26
  async start() {
22
27
  if (this.#started)
23
28
  return;
24
29
  this.#started = true;
25
30
  try {
26
- this.#unregisterAgent = registerKookAgentEndpoint(this.#options.config.id, this);
27
31
  this.#client = this.#createClient(this.#options.config);
28
32
  this.#bindClient(this.#client);
29
33
  await this.#client.connect();
@@ -48,8 +52,6 @@ export class KookWebsocketEndpoint {
48
52
  }
49
53
  async stop() {
50
54
  this.#open = false;
51
- this.#unregisterAgent?.();
52
- this.#unregisterAgent = undefined;
53
55
  if (this.#client) {
54
56
  try {
55
57
  this.#client.removeAllListeners();
@@ -78,7 +80,7 @@ export class KookWebsocketEndpoint {
78
80
  }));
79
81
  return messageId;
80
82
  }
81
- /** Test / internal: admit a message when open. */
83
+ /** Test / internal: admit a normalized message when open. */
82
84
  admit(msg) {
83
85
  if (!this.#open)
84
86
  return;
@@ -86,7 +88,7 @@ export class KookWebsocketEndpoint {
86
88
  return;
87
89
  const conversation = kookInboundConversation(String(this.#options.id), msg);
88
90
  const selfId = this.#client?.self_id != null ? String(this.#client.self_id) : undefined;
89
- void this.#options.gateway.receive({
91
+ void this.emit('message.receive', {
90
92
  conversation,
91
93
  message: { conversation, id: msg.id },
92
94
  content: formatInboundContent(msg),
@@ -116,37 +118,26 @@ export class KookWebsocketEndpoint {
116
118
  return;
117
119
  await this.#requireClient().recallMsg?.(messageId);
118
120
  }
119
- // ── Agent tool surface ──────────────────────────────────────────────
120
- async getRoleList(guildId) {
121
- return this.#requireClient().pickGuild(guildId).getRoleList();
122
- }
123
- async createRole(guildId, name) {
124
- return this.#requireClient().pickGuild(guildId).createRole(name);
125
- }
126
- async deleteRole(guildId, roleId) {
127
- return this.#requireClient().pickGuild(guildId).deleteRole(roleId);
128
- }
129
- async grantRole(guildId, userId, roleId) {
130
- return this.#requireClient().pickGuildMember(guildId, userId).grant(roleId);
131
- }
132
- async revokeRole(guildId, userId, roleId) {
133
- return this.#requireClient().pickGuildMember(guildId, userId).revoke(roleId);
134
- }
135
- async addToBlacklist(guildId, userId, remark) {
136
- return this.#requireClient().pickGuildMember(guildId, userId).addToBlackList(remark);
137
- }
138
- async removeFromBlacklist(guildId, userId) {
139
- return this.#requireClient().pickGuildMember(guildId, userId).removeFromBlackList();
140
- }
141
121
  #bindClient(client) {
142
122
  client.on('message', (raw) => {
123
+ this.#emitPlatformEvent('message', raw);
143
124
  const msg = normalizeKookMessage(raw);
144
125
  if (msg)
145
126
  this.admit(msg);
146
127
  });
147
128
  const receiver = client.receiver;
148
129
  receiver?.on('event', (raw) => {
149
- receiveKookSideEvent(this.#options.sideEvents, this.#options.config.id, raw, this.#logger);
130
+ this.#emitPlatformEvent('event', raw);
131
+ receiveKookSideEvent((name, payload) => this.emit(name, payload), this.#options.config.id, raw, this.#logger);
132
+ });
133
+ }
134
+ #emitPlatformEvent(name, event) {
135
+ void this.emitPlatform(name, event).catch((error) => {
136
+ this.#logger.warn(formatCompact({
137
+ op: 'kook_platform_event_failed',
138
+ event: name,
139
+ error: error instanceof Error ? error.message : String(error),
140
+ }));
150
141
  });
151
142
  }
152
143
  #requireClient() {
@@ -155,7 +146,7 @@ export class KookWebsocketEndpoint {
155
146
  return this.#client;
156
147
  }
157
148
  }
158
- export class KookWebhookEndpoint {
149
+ export class KookWebhookEndpoint extends Endpoint {
159
150
  #logger;
160
151
  #options;
161
152
  #createClient;
@@ -164,13 +155,17 @@ export class KookWebhookEndpoint {
164
155
  #processedSn = new Set();
165
156
  #open = false;
166
157
  #started = false;
167
- #unregisterAgent;
168
158
  management = createKookEndpointManagement(() => this.#requireClient());
159
+ control = createRecallEndpointControl((id) => this.recallMessage(id));
169
160
  constructor(options) {
161
+ super();
170
162
  this.#logger = getAdapterLogger('kook', options.config.id);
171
163
  this.#options = options;
172
164
  this.#createClient = options.createClient ?? defaultCreateWebhookClient;
173
165
  }
166
+ get client() {
167
+ return this.#requireClient();
168
+ }
174
169
  /** Used by webhook handler. */
175
170
  get isOpen() {
176
171
  return this.#open;
@@ -186,7 +181,6 @@ export class KookWebhookEndpoint {
186
181
  return;
187
182
  this.#started = true;
188
183
  try {
189
- this.#unregisterAgent = registerKookAgentEndpoint(this.#options.config.id, this);
190
184
  this.#client = this.#createClient(this.#options.config);
191
185
  await this.#client.init();
192
186
  this.#routeReleases.push(...registerKookWebhookRoutes(this.#options.http, this));
@@ -214,8 +208,6 @@ export class KookWebhookEndpoint {
214
208
  this.#open = false;
215
209
  for (const release of this.#routeReleases.splice(0))
216
210
  release();
217
- this.#unregisterAgent?.();
218
- this.#unregisterAgent = undefined;
219
211
  this.#processedSn.clear();
220
212
  if (this.#client) {
221
213
  try {
@@ -245,6 +237,23 @@ export class KookWebhookEndpoint {
245
237
  }));
246
238
  return messageId;
247
239
  }
240
+ admitEvent(event) {
241
+ void this.emitPlatform(String(event.type ?? 'event'), event).catch((error) => {
242
+ this.#logger.warn(formatCompact({
243
+ op: 'kook_platform_event_failed',
244
+ event: String(event.type ?? 'event'),
245
+ error: error instanceof Error ? error.message : String(error),
246
+ }));
247
+ });
248
+ if (receiveKookSideEvent((name, payload) => this.emit(name, payload), this.#options.config.id, event, this.#logger))
249
+ return;
250
+ const message = normalizeKookWebhookEvent(event, {
251
+ ignore: this.#options.config.ignore,
252
+ selfId: this.selfId,
253
+ });
254
+ if (message)
255
+ this.admit(message);
256
+ }
248
257
  /** Test / internal: admit a message when open. */
249
258
  admit(msg) {
250
259
  if (!this.#open)
@@ -253,7 +262,7 @@ export class KookWebhookEndpoint {
253
262
  return;
254
263
  const conversation = kookInboundConversation(String(this.#options.id), msg);
255
264
  const selfId = this.#client?.self_id != null ? String(this.#client.self_id) : undefined;
256
- void this.#options.gateway.receive({
265
+ void this.emit('message.receive', {
257
266
  conversation,
258
267
  message: { conversation, id: msg.id },
259
268
  content: formatInboundContent(msg),
@@ -294,27 +303,6 @@ export class KookWebhookEndpoint {
294
303
  }
295
304
  return true;
296
305
  }
297
- async getRoleList(guildId) {
298
- return this.#requireClient().pickGuild(guildId).getRoleList();
299
- }
300
- async createRole(guildId, name) {
301
- return this.#requireClient().pickGuild(guildId).createRole(name);
302
- }
303
- async deleteRole(guildId, roleId) {
304
- return this.#requireClient().pickGuild(guildId).deleteRole(roleId);
305
- }
306
- async grantRole(guildId, userId, roleId) {
307
- return this.#requireClient().pickGuildMember(guildId, userId).grant(roleId);
308
- }
309
- async revokeRole(guildId, userId, roleId) {
310
- return this.#requireClient().pickGuildMember(guildId, userId).revoke(roleId);
311
- }
312
- async addToBlacklist(guildId, userId, remark) {
313
- return this.#requireClient().pickGuildMember(guildId, userId).addToBlackList(remark);
314
- }
315
- async removeFromBlacklist(guildId, userId) {
316
- return this.#requireClient().pickGuildMember(guildId, userId).removeFromBlackList();
317
- }
318
306
  #requireClient() {
319
307
  if (!this.#client)
320
308
  throw new Error('KOOK client not initialized');