@zhin.js/adapter-kook 1.1.18 → 1.1.20
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 +46 -0
- package/README.md +11 -4
- package/adapters/kook/index.js +3 -23
- package/adapters/kook/index.ts +3 -27
- package/commands/kook/endpoint/definition.js +0 -2
- package/commands/kook/endpoint/definition.ts +0 -2
- package/lib/adapter.d.ts +14 -0
- package/lib/adapter.js +44 -0
- package/lib/client.d.ts +7 -8
- package/lib/client.js +1 -2
- package/lib/console-spec.js +10 -0
- package/lib/console.d.ts +1 -7
- package/lib/console.js +2 -5
- package/lib/endpoint.d.ts +10 -24
- package/lib/endpoint.js +160 -159
- package/lib/index.d.ts +3 -2
- package/lib/index.js +2 -2
- package/lib/outbound.d.ts +3 -4
- package/lib/outbound.js +15 -11
- package/lib/protocol.d.ts +4 -0
- package/lib/protocol.js +3 -1
- package/lib/webhook.d.ts +3 -2
- package/lib/webhook.js +24 -21
- package/lib/ws.d.ts +4 -66
- package/lib/ws.js +17 -8
- package/package.json +18 -18
- package/plugin.js +1 -4
- package/src/adapter.ts +35 -0
- package/src/client.ts +4 -11
- package/src/console-spec.ts +10 -0
- package/src/console.ts +2 -6
- package/src/endpoint.ts +162 -163
- package/src/index.ts +4 -4
- package/src/outbound.ts +18 -14
- package/src/protocol.ts +6 -2
- package/src/webhook.ts +25 -22
- package/src/ws.ts +13 -64
- package/lib/kook-runtime-state.d.ts +0 -1
- package/lib/kook-runtime-state.js +0 -6
- package/src/kook-runtime-state.ts +0 -7
package/lib/protocol.js
CHANGED
|
@@ -297,6 +297,8 @@ export function normalizeKookWebhookEvent(event, options = {}) {
|
|
|
297
297
|
return null;
|
|
298
298
|
return {
|
|
299
299
|
id: String(event.msg_id),
|
|
300
|
+
event,
|
|
301
|
+
...(typeof event.msg_timestamp === 'number' ? { platformSentAt: event.msg_timestamp } : {}),
|
|
300
302
|
content: event.content ?? '',
|
|
301
303
|
channelKind,
|
|
302
304
|
channelId,
|
|
@@ -328,5 +330,5 @@ export function normalizeKookButtonEvent(raw) {
|
|
|
328
330
|
if (!channelId)
|
|
329
331
|
return null;
|
|
330
332
|
const timestamp = event.msg_timestamp ?? Date.now();
|
|
331
|
-
return { id: String(event.msg_id || `button:${body.msg_id}:${timestamp}`), sourceMessageId: String(body.msg_id), payload: body.value, userId: String(body.user_id), channelKind, channelId, timestamp };
|
|
333
|
+
return { event: raw, ...(typeof event.msg_timestamp === 'number' ? { platformSentAt: event.msg_timestamp } : {}), id: String(event.msg_id || `button:${body.msg_id}:${timestamp}`), sourceMessageId: String(body.msg_id), payload: body.value, userId: String(body.user_id), channelKind, channelId, timestamp };
|
|
332
334
|
}
|
package/lib/webhook.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
+
import { type Endpoint } from 'zhin.js/adapter';
|
|
1
2
|
/**
|
|
2
3
|
* KOOK webhook HTTP: verify → parse → admit.
|
|
3
4
|
*/
|
|
4
5
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
5
6
|
import type { HttpHost, HttpRouteRegistration } from '@zhin.js/host-http';
|
|
6
7
|
import { type KookInboundMessage, type KookWebhookEventData, type ResolvedKookWebhookConfig } from './protocol.js';
|
|
7
|
-
export interface KookWebhookHandler {
|
|
8
|
-
readonly
|
|
8
|
+
export interface KookWebhookHandler extends Endpoint {
|
|
9
|
+
readonly endpointConfig: ResolvedKookWebhookConfig;
|
|
9
10
|
readonly isOpen: boolean;
|
|
10
11
|
readonly selfId?: string;
|
|
11
12
|
admit(msg: KookInboundMessage): void;
|
package/lib/webhook.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { endpointSpec } from 'zhin.js/adapter';
|
|
1
2
|
import { formatCompact, getLogger } from '@zhin.js/logger';
|
|
2
3
|
import { isKookWebhookChallenge, parseKookWebhookBody, readRequestBody, verifyKookWebhookToken, } from './protocol.js';
|
|
3
4
|
const logger = getLogger('kook');
|
|
4
5
|
export function registerKookWebhookRoutes(http, handler) {
|
|
5
|
-
const path = handler.
|
|
6
|
+
const path = handler.endpointConfig.webhookPath;
|
|
6
7
|
return [
|
|
7
8
|
http.route('POST', path, async (request, response) => {
|
|
8
9
|
await handleKookWebhookRequest(request, response, handler);
|
|
@@ -14,7 +15,7 @@ export async function handleKookWebhookRequest(request, response, handler) {
|
|
|
14
15
|
const rawBody = await readRequestBody(request);
|
|
15
16
|
let frame;
|
|
16
17
|
try {
|
|
17
|
-
frame = parseKookWebhookBody(rawBody, handler.
|
|
18
|
+
frame = parseKookWebhookBody(rawBody, handler.endpointConfig.encryptKey);
|
|
18
19
|
}
|
|
19
20
|
catch (error) {
|
|
20
21
|
logger.warn(formatCompact({
|
|
@@ -33,7 +34,7 @@ export async function handleKookWebhookRequest(request, response, handler) {
|
|
|
33
34
|
return;
|
|
34
35
|
}
|
|
35
36
|
if (isKookWebhookChallenge(event)) {
|
|
36
|
-
if (!verifyKookWebhookToken(handler.
|
|
37
|
+
if (!verifyKookWebhookToken(handler.endpointConfig.verifyToken, event.verify_token)) {
|
|
37
38
|
response.writeHead(403, { 'Content-Type': 'application/json' });
|
|
38
39
|
response.end(JSON.stringify({ message: 'Invalid verify_token' }));
|
|
39
40
|
return;
|
|
@@ -42,7 +43,7 @@ export async function handleKookWebhookRequest(request, response, handler) {
|
|
|
42
43
|
response.end(JSON.stringify({ challenge: event.challenge ?? '' }));
|
|
43
44
|
return;
|
|
44
45
|
}
|
|
45
|
-
if (!verifyKookWebhookToken(handler.
|
|
46
|
+
if (!verifyKookWebhookToken(handler.endpointConfig.verifyToken, event.verify_token)) {
|
|
46
47
|
response.writeHead(403, { 'Content-Type': 'application/json' });
|
|
47
48
|
response.end(JSON.stringify({ message: 'Invalid verify_token' }));
|
|
48
49
|
return;
|
|
@@ -52,25 +53,27 @@ export async function handleKookWebhookRequest(request, response, handler) {
|
|
|
52
53
|
response.end(JSON.stringify({ message: 'Endpoint unavailable' }));
|
|
53
54
|
return;
|
|
54
55
|
}
|
|
55
|
-
|
|
56
|
-
if (
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
await handler[endpointSpec].events.run(async () => {
|
|
57
|
+
if (frame.sn != null) {
|
|
58
|
+
if (!handler.checkAndRememberSn(frame.sn)) {
|
|
59
|
+
response.writeHead(200, { 'Content-Type': 'application/json' });
|
|
60
|
+
response.end(JSON.stringify({ message: 'OK' }));
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
await handler.admitEvent(event);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
if (frame.sn != null)
|
|
69
|
+
handler.forgetSn?.(frame.sn);
|
|
70
|
+
response.writeHead(503, { 'Content-Type': 'application/json' });
|
|
71
|
+
response.end(JSON.stringify({ message: 'Admission unavailable' }));
|
|
59
72
|
return;
|
|
60
73
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
catch {
|
|
66
|
-
if (frame.sn != null)
|
|
67
|
-
handler.forgetSn?.(frame.sn);
|
|
68
|
-
response.writeHead(503, { 'Content-Type': 'application/json' });
|
|
69
|
-
response.end(JSON.stringify({ message: 'Admission unavailable' }));
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
response.writeHead(200, { 'Content-Type': 'application/json' });
|
|
73
|
-
response.end(JSON.stringify({ message: 'OK' }));
|
|
74
|
+
response.writeHead(200, { 'Content-Type': 'application/json' });
|
|
75
|
+
response.end(JSON.stringify({ message: 'OK' }));
|
|
76
|
+
});
|
|
74
77
|
}
|
|
75
78
|
catch (error) {
|
|
76
79
|
logger.error('KOOK webhook error:', error);
|
package/lib/ws.d.ts
CHANGED
|
@@ -1,70 +1,8 @@
|
|
|
1
1
|
import { type KookApiProxy } from './api-proxy.js';
|
|
2
2
|
import { Client } from 'kook-client';
|
|
3
3
|
import { createEndpointLifecycle, type EndpointTransportState } from 'zhin.js/adapter';
|
|
4
|
-
import { type KookInboundMessage, type
|
|
5
|
-
|
|
6
|
-
export interface KookClientTransport {
|
|
7
|
-
getTransportState?(): EndpointTransportState | undefined;
|
|
8
|
-
connect(): Promise<void>;
|
|
9
|
-
disconnect(): Promise<void>;
|
|
10
|
-
on(event: string, listener: (...args: unknown[]) => void): void;
|
|
11
|
-
removeAllListeners(): void;
|
|
12
|
-
sendChannelMsg(channelId: string, message: unknown, quote?: {
|
|
13
|
-
message_id: string;
|
|
14
|
-
}): Promise<{
|
|
15
|
-
msg_id?: string | number;
|
|
16
|
-
}>;
|
|
17
|
-
sendPrivateMsg(userId: string, message: unknown, quote?: {
|
|
18
|
-
message_id: string;
|
|
19
|
-
}): Promise<{
|
|
20
|
-
msg_id?: string | number;
|
|
21
|
-
}>;
|
|
22
|
-
uploadMedia?(data: Buffer): Promise<string>;
|
|
23
|
-
recallChannelMsg?(channelId: string, messageId: string): Promise<boolean>;
|
|
24
|
-
recallPrivateMsg?(userId: string, messageId: string): Promise<boolean>;
|
|
25
|
-
/** GET /api/v3/guild/view(群主 id)。 */
|
|
26
|
-
getGuildInfo?(guildId: string): Promise<{
|
|
27
|
-
user_id?: string | number;
|
|
28
|
-
}>;
|
|
29
|
-
pickGuild(guildId: string): {
|
|
30
|
-
kick(userId: string): Promise<boolean>;
|
|
31
|
-
getRoleList(): Promise<Array<{
|
|
32
|
-
role_id: string | number;
|
|
33
|
-
name: string;
|
|
34
|
-
color?: number;
|
|
35
|
-
position?: number;
|
|
36
|
-
permissions?: unknown;
|
|
37
|
-
}>>;
|
|
38
|
-
createRole(name: string): Promise<{
|
|
39
|
-
role_id: string | number;
|
|
40
|
-
name: string;
|
|
41
|
-
}>;
|
|
42
|
-
deleteRole(roleId: string): Promise<boolean>;
|
|
43
|
-
};
|
|
44
|
-
pickGuildMember(guildId: string, userId: string): {
|
|
45
|
-
addToBlackList(remark?: string, delMsgDays?: number): Promise<boolean>;
|
|
46
|
-
removeFromBlackList(): Promise<boolean>;
|
|
47
|
-
grant(roleId: string): Promise<boolean>;
|
|
48
|
-
revoke(roleId: string): Promise<boolean>;
|
|
49
|
-
setNickname(nickname: string): Promise<boolean>;
|
|
50
|
-
};
|
|
51
|
-
/** GET /api/v3/guild/list(kook-client 内部分页聚合)。 */
|
|
52
|
-
getGuildList(): Promise<Array<{
|
|
53
|
-
id: string | number;
|
|
54
|
-
name?: string;
|
|
55
|
-
}>>;
|
|
56
|
-
/** GET /api/v3/channel/list(type: 1=文字 2=语音;is_category 为分组)。 */
|
|
57
|
-
getChannelList(guildId: string): Promise<Array<{
|
|
58
|
-
id: string | number;
|
|
59
|
-
name?: string;
|
|
60
|
-
type?: string | number;
|
|
61
|
-
is_category?: boolean;
|
|
62
|
-
}>>;
|
|
63
|
-
/** GET /api/v3/guild/user-list。 */
|
|
64
|
-
getGuildUserList(guildId: string, channelId?: string): Promise<unknown[]>;
|
|
65
|
-
self_id?: string | number;
|
|
66
|
-
}
|
|
67
|
-
export type CreateKookClient = (config: ResolvedKookConfig) => KookClientTransport;
|
|
4
|
+
import { type KookInboundMessage, type ResolvedKookWebhookConfig, type ResolvedKookWebsocketConfig } from './protocol.js';
|
|
5
|
+
export type KookClientTransport = RuntimeKookClient;
|
|
68
6
|
export declare function normalizeKookMessage(raw: unknown): KookInboundMessage | null;
|
|
69
7
|
export declare class RuntimeKookClient extends Client {
|
|
70
8
|
#private;
|
|
@@ -77,5 +15,5 @@ export declare class RuntimeKookClient extends Client {
|
|
|
77
15
|
init(): Promise<void>;
|
|
78
16
|
getBlacklist(guildId: string): Promise<import("kook-client").Guild.BlackInfo[]>;
|
|
79
17
|
}
|
|
80
|
-
export declare function
|
|
81
|
-
export declare function
|
|
18
|
+
export declare function kookWebsocketClientOptions(config: ResolvedKookWebsocketConfig): ConstructorParameters<typeof Client>[0];
|
|
19
|
+
export declare function kookWebhookClientOptions(config: ResolvedKookWebhookConfig): ConstructorParameters<typeof Client>[0];
|
package/lib/ws.js
CHANGED
|
@@ -42,6 +42,8 @@ export function normalizeKookMessage(raw) {
|
|
|
42
42
|
catch { /* optional cache enrichment unavailable */ }
|
|
43
43
|
return {
|
|
44
44
|
id: String(msg.message_id),
|
|
45
|
+
event: raw,
|
|
46
|
+
...(typeof msg.timestamp === 'number' ? { platformSentAt: msg.timestamp } : {}),
|
|
45
47
|
content,
|
|
46
48
|
channelKind,
|
|
47
49
|
channelId,
|
|
@@ -57,6 +59,7 @@ export function normalizeKookMessage(raw) {
|
|
|
57
59
|
};
|
|
58
60
|
}
|
|
59
61
|
export class RuntimeKookClient extends Client {
|
|
62
|
+
#apiAgent;
|
|
60
63
|
#lifecycle;
|
|
61
64
|
#initialized = false;
|
|
62
65
|
#connectionAttempt = 0;
|
|
@@ -64,7 +67,8 @@ export class RuntimeKookClient extends Client {
|
|
|
64
67
|
super({ ...config, autoReconnect: false, handleProcessErrors: false });
|
|
65
68
|
this.#lifecycle = createEndpointLifecycle(lifecycleOptions);
|
|
66
69
|
if (apiProxy) {
|
|
67
|
-
this
|
|
70
|
+
this.#apiAgent = createKookApiAgent(apiProxy);
|
|
71
|
+
this.request.defaults.httpsAgent = this.#apiAgent;
|
|
68
72
|
this.request.defaults.proxy = false;
|
|
69
73
|
this.request.defaults.maxRedirects = 0;
|
|
70
74
|
this.request.interceptors.request.use(request => {
|
|
@@ -125,7 +129,12 @@ export class RuntimeKookClient extends Client {
|
|
|
125
129
|
}
|
|
126
130
|
});
|
|
127
131
|
}
|
|
128
|
-
async disconnect() {
|
|
132
|
+
async disconnect() { try {
|
|
133
|
+
await this.#lifecycle.stop();
|
|
134
|
+
}
|
|
135
|
+
finally {
|
|
136
|
+
this.#apiAgent?.destroy();
|
|
137
|
+
} }
|
|
129
138
|
/** Native FormData avoids kook-client's Buffer-to-text multipart conversion. */
|
|
130
139
|
async uploadMedia(data) {
|
|
131
140
|
let bytes;
|
|
@@ -190,8 +199,8 @@ export class RuntimeKookClient extends Client {
|
|
|
190
199
|
}
|
|
191
200
|
}
|
|
192
201
|
}
|
|
193
|
-
export function
|
|
194
|
-
return
|
|
202
|
+
export function kookWebsocketClientOptions(config) {
|
|
203
|
+
return {
|
|
195
204
|
token: config.token,
|
|
196
205
|
mode: 'websocket',
|
|
197
206
|
socketFactory: (url) => createKookStreamSocket(url, config.streamProxy),
|
|
@@ -200,10 +209,10 @@ export function defaultCreateClient(config) {
|
|
|
200
209
|
max_retry: config.max_retry,
|
|
201
210
|
ignore: config.ignore,
|
|
202
211
|
logLevel: config.logLevel,
|
|
203
|
-
}
|
|
212
|
+
};
|
|
204
213
|
}
|
|
205
|
-
export function
|
|
206
|
-
return
|
|
214
|
+
export function kookWebhookClientOptions(config) {
|
|
215
|
+
return {
|
|
207
216
|
token: config.token,
|
|
208
217
|
mode: 'webhook',
|
|
209
218
|
data_dir: path.join(process.cwd(), 'data', 'kook'),
|
|
@@ -211,5 +220,5 @@ export function defaultCreateWebhookClient(config) {
|
|
|
211
220
|
max_retry: 3,
|
|
212
221
|
ignore: config.ignore,
|
|
213
222
|
logLevel: config.logLevel,
|
|
214
|
-
}
|
|
223
|
+
};
|
|
215
224
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-kook",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.20",
|
|
4
4
|
"description": "Zhin.js KOOK adapter for Plugin Runtime (WebSocket gateway or Webhook)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -33,26 +33,26 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"kook-client": "^1.0.5",
|
|
36
|
-
"@zhin.js/adapter": "1.1.
|
|
37
|
-
"@zhin.js/agent-feature": "1.1.
|
|
38
|
-
"@zhin.js/client": "1.1.
|
|
36
|
+
"@zhin.js/adapter": "1.1.26",
|
|
37
|
+
"@zhin.js/agent-feature": "1.1.11",
|
|
38
|
+
"@zhin.js/client": "1.1.22",
|
|
39
39
|
"@zhin.js/console-contract": "1.1.3",
|
|
40
|
-
"@zhin.js/core": "1.1.
|
|
41
|
-
"@zhin.js/feature-kit": "1.1.
|
|
42
|
-
"@zhin.js/host-http": "1.1.
|
|
40
|
+
"@zhin.js/core": "1.1.54",
|
|
41
|
+
"@zhin.js/feature-kit": "1.1.10",
|
|
42
|
+
"@zhin.js/host-http": "1.1.12",
|
|
43
43
|
"@zhin.js/im-contract": "1.1.9",
|
|
44
44
|
"@zhin.js/logger": "1.1.2",
|
|
45
|
-
"@zhin.js/page": "1.1.
|
|
46
|
-
"@zhin.js/permission": "1.1.
|
|
47
|
-
"@zhin.js/skill": "1.1.
|
|
48
|
-
"@zhin.js/tool": "1.1.
|
|
45
|
+
"@zhin.js/page": "1.1.12",
|
|
46
|
+
"@zhin.js/permission": "1.1.10",
|
|
47
|
+
"@zhin.js/skill": "1.1.11",
|
|
48
|
+
"@zhin.js/tool": "1.1.13"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
51
|
"zod": "^4.0.0",
|
|
52
|
-
"@zhin.js/adapter": "^1.1.
|
|
53
|
-
"@zhin.js/command": "^1.1.
|
|
54
|
-
"@zhin.js/core": "^1.1.
|
|
55
|
-
"zhin.js": "^1.1.
|
|
52
|
+
"@zhin.js/adapter": "^1.1.26",
|
|
53
|
+
"@zhin.js/command": "^1.1.12",
|
|
54
|
+
"@zhin.js/core": "^1.1.54",
|
|
55
|
+
"zhin.js": "^1.1.19"
|
|
56
56
|
},
|
|
57
57
|
"peerDependenciesMeta": {
|
|
58
58
|
"@zhin.js/command": {
|
|
@@ -70,8 +70,8 @@
|
|
|
70
70
|
"typescript": "^6.0.3",
|
|
71
71
|
"vitest": "^4.1.10",
|
|
72
72
|
"zod": "^4.4.3",
|
|
73
|
-
"@zhin.js/host-http": "1.1.
|
|
74
|
-
"zhin.js": "1.1.
|
|
73
|
+
"@zhin.js/host-http": "1.1.12",
|
|
74
|
+
"zhin.js": "1.1.19"
|
|
75
75
|
},
|
|
76
76
|
"files": [
|
|
77
77
|
"adapters",
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
"features": [
|
|
104
104
|
{
|
|
105
105
|
"package": "@zhin.js/adapter",
|
|
106
|
-
"api": "^
|
|
106
|
+
"api": "^2.0.0"
|
|
107
107
|
},
|
|
108
108
|
{
|
|
109
109
|
"package": "@zhin.js/command",
|
package/plugin.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
-
import { createEndpointRuntimeState } from 'zhin.js/adapter';
|
|
3
2
|
import { definePlugin, pluginConsoleRpcToken } from 'zhin.js';
|
|
4
3
|
import { permissionHostToken } from '@zhin.js/permission';
|
|
5
4
|
import { checkKookPlatformPermit } from "./lib/platform-permit.js";
|
|
6
|
-
import { kookRuntimeStateToken } from "./lib/kook-runtime-state.js";
|
|
7
5
|
import { createKookConsoleRpc } from "./lib/console.js";
|
|
8
6
|
export default definePlugin({
|
|
9
7
|
name: 'kook',
|
|
@@ -11,8 +9,7 @@ export default definePlugin({
|
|
|
11
9
|
displayName: 'KOOK WebSocket Adapter',
|
|
12
10
|
},
|
|
13
11
|
setup(context) {
|
|
14
|
-
context.resources.provide(
|
|
15
|
-
context.resources.provide(pluginConsoleRpcToken, createKookConsoleRpc(context.resources, () => context.config.get()));
|
|
12
|
+
context.resources.provide(pluginConsoleRpcToken, createKookConsoleRpc(() => context.config.get()));
|
|
16
13
|
if (context.resources.has(permissionHostToken)) {
|
|
17
14
|
const host = context.resources.use(permissionHostToken);
|
|
18
15
|
return host.registerPlatform('kook', checkKookPlatformPermit);
|
package/src/adapter.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Adapter, type AdapterContext, type EndpointCreationContext } from 'zhin.js/adapter';
|
|
2
|
+
import { httpHostToken } from '@zhin.js/host-http';
|
|
3
|
+
import { KookWebhookEndpoint, KookWebsocketEndpoint } from './endpoint.js';
|
|
4
|
+
import { RuntimeKookClient, kookWebhookClientOptions, kookWebsocketClientOptions } from './ws.js';
|
|
5
|
+
import { resolveKookConfig, type KookEndpointConfig } from './protocol.js';
|
|
6
|
+
import type { KookClientEventMap } from './client.js';
|
|
7
|
+
|
|
8
|
+
export class KookAdapter extends Adapter<KookWebhookEndpoint | KookWebsocketEndpoint, KookEndpointConfig, KookClientEventMap> {
|
|
9
|
+
constructor(private readonly context: AdapterContext<KookEndpointConfig>) { super(); }
|
|
10
|
+
override get configurationIdentityFields(): readonly string[] { return ['id']; }
|
|
11
|
+
override get configurationIdentityProbeFields(): readonly string[] { return ['token', 'verify_token', 'encrypt_key']; }
|
|
12
|
+
override get configurationUpdateFields(): readonly string[] { return ['token', 'verify_token', 'encrypt_key', 'connection',
|
|
13
|
+
'webhookPath', 'data_dir', 'timeout', 'max_retry', 'ignore', 'logLevel', 'apiProxy', 'apiProxy.port',
|
|
14
|
+
'streamProxy', 'streamProxy.port', 'streamProxy.serverName']; }
|
|
15
|
+
protected override validateConfiguration(input: KookEndpointConfig): void { resolveKookConfig(input); }
|
|
16
|
+
protected override async identifyConfiguration(input: KookEndpointConfig, signal: AbortSignal, changedFields: readonly string[]): Promise<string | undefined> {
|
|
17
|
+
if (changedFields.some(field => field !== 'token')) return undefined;
|
|
18
|
+
const config = resolveKookConfig(input);
|
|
19
|
+
const options = config.connection === 'websocket' ? kookWebsocketClientOptions(config) : kookWebhookClientOptions(config);
|
|
20
|
+
// Webhook receiver construction has no gateway socket or login; only GET /v3/user/me is issued.
|
|
21
|
+
const client = new RuntimeKookClient({ ...options, mode: 'webhook' }, undefined, config.apiProxy);
|
|
22
|
+
client.request.interceptors.request.use(request => { request.signal = signal; return request; });
|
|
23
|
+
try {
|
|
24
|
+
const me = await client.getSelfInfo();
|
|
25
|
+
if (typeof me?.id !== 'string' || !me.id.trim()) throw new Error('KOOK identity response is incomplete');
|
|
26
|
+
return JSON.stringify(['kook', me.id]);
|
|
27
|
+
} finally { await client.disconnect(); }
|
|
28
|
+
}
|
|
29
|
+
protected createEndpoint(input: KookEndpointConfig, execution: EndpointCreationContext): KookWebhookEndpoint | KookWebsocketEndpoint {
|
|
30
|
+
const config = resolveKookConfig(input);
|
|
31
|
+
return config.connection === 'webhook'
|
|
32
|
+
? new KookWebhookEndpoint({ id: execution.canonicalId, config, http: this.context.use(httpHostToken) })
|
|
33
|
+
: new KookWebsocketEndpoint({ id: execution.canonicalId, config });
|
|
34
|
+
}
|
|
35
|
+
}
|
package/src/client.ts
CHANGED
|
@@ -1,15 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type {
|
|
1
|
+
import type { EventMap } from 'kook-client';
|
|
2
|
+
import type { KookAdapter } from './adapter.js';
|
|
3
3
|
|
|
4
|
-
export type KookClientEventMap =
|
|
4
|
+
export type KookClientEventMap = { readonly [K in keyof EventMap]: EventMap[K] extends (event: infer E, ...args: never[]) => unknown ? E : never };
|
|
5
5
|
|
|
6
6
|
declare module '@zhin.js/feature-kit' {
|
|
7
|
-
interface
|
|
8
|
-
readonly kook: {
|
|
9
|
-
readonly client: KookClientTransport;
|
|
10
|
-
readonly events: KookClientEventMap;
|
|
11
|
-
};
|
|
12
|
-
}
|
|
7
|
+
interface AdapterRegistry { readonly kook: KookAdapter; }
|
|
13
8
|
}
|
|
14
|
-
|
|
15
|
-
export const kookClient = defineEndpointClient<KookClientTransport, KookClientEventMap>('kook');
|
package/src/console-spec.ts
CHANGED
|
@@ -10,6 +10,16 @@ export const kookConsoleSpec = {
|
|
|
10
10
|
{ key: 'token', required: true, env: true, description: 'KOOK bot token' },
|
|
11
11
|
{ key: 'encrypt_key', env: true, description: 'webhook 加密密钥(connection: webhook)', descriptionI18n: { en: 'Webhook encryption secret' } },
|
|
12
12
|
{ key: 'verify_token', env: true, description: 'webhook 验证 token(connection: webhook)', descriptionI18n: { en: 'Webhook verification token' } },
|
|
13
|
+
{ key: 'connection', description: 'websocket or webhook' },
|
|
14
|
+
{ key: 'webhookPath', description: 'Local webhook route' },
|
|
15
|
+
{ key: 'data_dir', description: 'SDK data directory' },
|
|
16
|
+
{ key: 'timeout', type: 'number', description: 'SDK request timeout' },
|
|
17
|
+
{ key: 'max_retry', type: 'number', description: 'SDK configured retry count' },
|
|
18
|
+
{ key: 'ignore', description: 'SDK inbound ignore setting: bot or self' },
|
|
19
|
+
{ key: 'logLevel', description: 'SDK log level' },
|
|
20
|
+
{ key: 'apiProxy.port', type: 'number', description: 'Configured API loopback proxy port' },
|
|
21
|
+
{ key: 'streamProxy.port', type: 'number', description: 'Configured Gateway loopback proxy port' },
|
|
22
|
+
{ key: 'streamProxy.serverName', description: 'Expected Gateway TLS hostname' },
|
|
13
23
|
] as readonly AdapterConsoleField[],
|
|
14
24
|
docsUrl: 'https://zhin.js.org/adapters/kook',
|
|
15
25
|
readPermission: 'kook:read',
|
package/src/console.ts
CHANGED
|
@@ -3,19 +3,15 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 页面绑定 `pages/index`,读取 / 写入分别要求 `<adapter>:read` / `<adapter>:write`。
|
|
5
5
|
*/
|
|
6
|
-
import { createAdapterConsoleRpc
|
|
6
|
+
import { createAdapterConsoleRpc } from 'zhin.js/adapter';
|
|
7
7
|
import type { PluginConsoleRpc } from 'zhin.js';
|
|
8
|
-
import { kookRuntimeStateToken } from './kook-runtime-state.js';
|
|
9
8
|
import { kookConsoleSpec } from './console-spec.js';
|
|
10
9
|
|
|
11
10
|
export function createKookConsoleRpc(
|
|
12
|
-
resources: AdapterConsoleResources,
|
|
13
11
|
getConfig: () => unknown,
|
|
14
12
|
): PluginConsoleRpc {
|
|
15
|
-
const state = resources.use(kookRuntimeStateToken);
|
|
16
13
|
return createAdapterConsoleRpc({
|
|
17
14
|
...kookConsoleSpec,
|
|
18
|
-
running: () => state.endpoints.values(),
|
|
19
15
|
getConfig,
|
|
20
|
-
}
|
|
16
|
+
});
|
|
21
17
|
}
|