@onebots/adapter-kook 1.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/lib/types.d.ts ADDED
@@ -0,0 +1,240 @@
1
+ /**
2
+ * KOOK (开黑了) API 类型定义
3
+ * 基于 KOOK 开发者平台官方 API
4
+ */
5
+ export interface KookConfig {
6
+ account_id: string;
7
+ token: string;
8
+ verifyToken?: string;
9
+ encryptKey?: string;
10
+ mode?: 'webhook' | 'websocket';
11
+ maxRetry?: number;
12
+ }
13
+ export interface KookUser {
14
+ id: string;
15
+ username: string;
16
+ nickname?: string;
17
+ identify_num: string;
18
+ online: boolean;
19
+ bot?: boolean;
20
+ status: number;
21
+ avatar: string;
22
+ vip_avatar?: string;
23
+ mobile_verified?: boolean;
24
+ roles?: number[];
25
+ joined_at?: number;
26
+ active_time?: number;
27
+ }
28
+ export interface KookGuild {
29
+ id: string;
30
+ name: string;
31
+ topic: string;
32
+ user_id: string;
33
+ icon: string;
34
+ notify_type: number;
35
+ region: string;
36
+ enable_open: boolean;
37
+ open_id: string;
38
+ default_channel_id: string;
39
+ welcome_channel_id: string;
40
+ roles?: KookRole[];
41
+ channels?: KookChannel[];
42
+ }
43
+ export interface KookChannel {
44
+ id: string;
45
+ name: string;
46
+ user_id: string;
47
+ guild_id: string;
48
+ topic: string;
49
+ is_category: boolean;
50
+ parent_id: string;
51
+ level: number;
52
+ slow_mode: number;
53
+ type: number;
54
+ permission_overwrites?: KookPermissionOverwrite[];
55
+ permission_users?: any[];
56
+ permission_sync: number;
57
+ has_password: boolean;
58
+ }
59
+ export interface KookRole {
60
+ role_id: number;
61
+ name: string;
62
+ color: number;
63
+ position: number;
64
+ hoist: number;
65
+ mentionable: number;
66
+ permissions: number;
67
+ }
68
+ export interface KookPermissionOverwrite {
69
+ role_id: number;
70
+ allow: number;
71
+ deny: number;
72
+ }
73
+ export type KookMessageType = 1 | 2 | 3 | 4 | 8 | 9 | 10 | 255;
74
+ export interface KookChannelMessage {
75
+ id: string;
76
+ type: KookMessageType;
77
+ content: string;
78
+ mention: string[];
79
+ mention_all: boolean;
80
+ mention_roles: number[];
81
+ mention_here: boolean;
82
+ embeds: any[];
83
+ attachments: KookAttachment[];
84
+ create_at: number;
85
+ updated_at: number;
86
+ reactions: KookReaction[];
87
+ author: KookUser;
88
+ image_name?: string;
89
+ read_status?: boolean;
90
+ quote?: KookChannelMessage;
91
+ mention_info?: any;
92
+ }
93
+ export interface KookDirectMessage {
94
+ id: string;
95
+ type: KookMessageType;
96
+ content: string;
97
+ embeds: any[];
98
+ attachments: KookAttachment[];
99
+ create_at: number;
100
+ updated_at: number;
101
+ reactions: KookReaction[];
102
+ author_id: string;
103
+ image_name?: string;
104
+ read_status?: boolean;
105
+ quote?: KookDirectMessage;
106
+ nonce?: string;
107
+ }
108
+ export interface KookAttachment {
109
+ type: string;
110
+ url: string;
111
+ name: string;
112
+ file_type?: string;
113
+ size?: number;
114
+ duration?: number;
115
+ width?: number;
116
+ height?: number;
117
+ }
118
+ export interface KookReaction {
119
+ emoji: KookEmoji;
120
+ count: number;
121
+ me: boolean;
122
+ }
123
+ export interface KookEmoji {
124
+ id: string;
125
+ name: string;
126
+ }
127
+ export interface KookIntimacy {
128
+ img_url: string;
129
+ social_info: string;
130
+ last_read: number;
131
+ score: number;
132
+ img_list: Array<{
133
+ id: string;
134
+ url: string;
135
+ }>;
136
+ }
137
+ export interface KookUserChat {
138
+ code: string;
139
+ last_read_time: number;
140
+ latest_msg_time: number;
141
+ unread_count: number;
142
+ is_friend: boolean;
143
+ is_blocked: boolean;
144
+ is_target_blocked: boolean;
145
+ target_info: KookUser;
146
+ }
147
+ export interface KookGame {
148
+ id: number;
149
+ name: string;
150
+ type: number;
151
+ options: string;
152
+ kmhook_admin: boolean;
153
+ process_name: string[];
154
+ product_name: string[];
155
+ icon: string;
156
+ }
157
+ export interface KookApiResponse<T = any> {
158
+ code: number;
159
+ message: string;
160
+ data: T;
161
+ }
162
+ export interface KookListResponse<T> {
163
+ items: T[];
164
+ meta: {
165
+ page: number;
166
+ page_total: number;
167
+ page_size: number;
168
+ total: number;
169
+ };
170
+ sort?: Record<string, number>;
171
+ }
172
+ export interface KookSignal {
173
+ s: number;
174
+ d: any;
175
+ sn?: number;
176
+ }
177
+ export declare const KookSignalType: {
178
+ readonly EVENT: 0;
179
+ readonly HELLO: 1;
180
+ readonly PING: 2;
181
+ readonly PONG: 3;
182
+ readonly RESUME: 4;
183
+ readonly RECONNECT: 5;
184
+ readonly RESUME_ACK: 6;
185
+ };
186
+ export type KookEventType = 'message' | 'added_reaction' | 'deleted_reaction' | 'updated_message' | 'deleted_message' | 'pinned_message' | 'unpinned_message' | 'added_channel' | 'updated_channel' | 'deleted_channel' | 'joined_guild' | 'exited_guild' | 'updated_guild_member' | 'guild_member_online' | 'guild_member_offline' | 'added_role' | 'deleted_role' | 'updated_role' | 'joined_channel' | 'exited_channel' | 'user_updated' | 'self_joined_guild' | 'self_exited_guild' | 'message_btn_click' | 'added_block_list' | 'deleted_block_list' | 'private_added_reaction' | 'private_deleted_reaction' | 'updated_private_message' | 'deleted_private_message';
187
+ export declare const KookChannelType: {
188
+ readonly TEXT: 1;
189
+ readonly VOICE: 2;
190
+ };
191
+ export interface KookEvent {
192
+ channel_type: 'GROUP' | 'PERSON' | 'BROADCAST';
193
+ type: number;
194
+ target_id: string;
195
+ author_id: string;
196
+ content: string;
197
+ msg_id: string;
198
+ msg_timestamp: number;
199
+ nonce: string;
200
+ extra: KookEventExtra;
201
+ }
202
+ export interface KookEventExtra {
203
+ type?: KookEventType | number;
204
+ guild_id?: string;
205
+ channel_name?: string;
206
+ mention?: string[];
207
+ mention_all?: boolean;
208
+ mention_roles?: number[];
209
+ mention_here?: boolean;
210
+ author?: KookUser;
211
+ body?: any;
212
+ code?: string;
213
+ [key: string]: any;
214
+ }
215
+ export interface KookWebhookChallenge {
216
+ s: 0;
217
+ d: {
218
+ type: 255;
219
+ channel_type: 'WEBHOOK_CHALLENGE';
220
+ challenge: string;
221
+ verify_token: string;
222
+ };
223
+ }
224
+ export interface KookSendMessageParams {
225
+ type?: KookMessageType;
226
+ target_id: string;
227
+ content: string;
228
+ quote?: string;
229
+ nonce?: string;
230
+ temp_target_id?: string;
231
+ }
232
+ export interface KookSendDirectMessageParams {
233
+ type?: KookMessageType;
234
+ target_id?: string;
235
+ chat_code?: string;
236
+ content: string;
237
+ quote?: string;
238
+ nonce?: string;
239
+ }
240
+ //# sourceMappingURL=types.d.ts.map
package/lib/types.js ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * KOOK (开黑了) API 类型定义
3
+ * 基于 KOOK 开发者平台官方 API
4
+ */
5
+ // 信令类型
6
+ export const KookSignalType = {
7
+ EVENT: 0, // 服务端推送消息
8
+ HELLO: 1, // 客户端和服务端的 Hello
9
+ PING: 2, // 客户端发送的 Ping
10
+ PONG: 3, // 服务端回复的 Pong
11
+ RESUME: 4, // 恢复连接
12
+ RECONNECT: 5, // 服务端通知重连
13
+ RESUME_ACK: 6, // 恢复成功
14
+ };
15
+ // 频道类型
16
+ export const KookChannelType = {
17
+ TEXT: 1, // 文字频道
18
+ VOICE: 2, // 语音频道
19
+ };
20
+ //# sourceMappingURL=types.js.map
package/lib/utils.d.ts ADDED
@@ -0,0 +1,93 @@
1
+ /**
2
+ * 验证 Webhook 请求
3
+ */
4
+ export declare function verifyWebhook(body: any, verifyToken: string): boolean;
5
+ /**
6
+ * 解密 Webhook 消息(当配置了 encryptKey 时)
7
+ */
8
+ export declare function decryptWebhookMessage(encryptedData: string, encryptKey: string): string;
9
+ /**
10
+ * 解析 KMarkdown 消息为文本
11
+ */
12
+ export declare function parseKMarkdown(content: string): string;
13
+ /**
14
+ * 将文本转换为 KMarkdown 格式
15
+ */
16
+ export declare function textToKMarkdown(text: string): string;
17
+ /**
18
+ * 构建 @用户 的 KMarkdown
19
+ */
20
+ export declare function mentionUser(userId: string): string;
21
+ /**
22
+ * 构建 @全体成员 的 KMarkdown
23
+ */
24
+ export declare function mentionAll(): string;
25
+ /**
26
+ * 构建 @在线成员 的 KMarkdown
27
+ */
28
+ export declare function mentionHere(): string;
29
+ /**
30
+ * 构建 @角色 的 KMarkdown
31
+ */
32
+ export declare function mentionRole(roleId: number): string;
33
+ /**
34
+ * 构建 #频道 的 KMarkdown
35
+ */
36
+ export declare function mentionChannel(channelId: string): string;
37
+ /**
38
+ * 构建表情的 KMarkdown
39
+ */
40
+ export declare function emojiKMarkdown(emojiName: string, emojiId: string): string;
41
+ /**
42
+ * 构建链接的 KMarkdown
43
+ */
44
+ export declare function linkKMarkdown(text: string, url: string): string;
45
+ /**
46
+ * 构建加粗的 KMarkdown
47
+ */
48
+ export declare function boldKMarkdown(text: string): string;
49
+ /**
50
+ * 构建斜体的 KMarkdown
51
+ */
52
+ export declare function italicKMarkdown(text: string): string;
53
+ /**
54
+ * 构建删除线的 KMarkdown
55
+ */
56
+ export declare function strikethroughKMarkdown(text: string): string;
57
+ /**
58
+ * 构建代码块的 KMarkdown
59
+ */
60
+ export declare function codeBlockKMarkdown(code: string, language?: string): string;
61
+ /**
62
+ * 构建行内代码的 KMarkdown
63
+ */
64
+ export declare function inlineCodeKMarkdown(code: string): string;
65
+ /**
66
+ * 构建引用的 KMarkdown
67
+ */
68
+ export declare function quoteKMarkdown(text: string): string;
69
+ /**
70
+ * 构建分割线的 KMarkdown
71
+ */
72
+ export declare function dividerKMarkdown(): string;
73
+ /**
74
+ * 生成随机 nonce
75
+ */
76
+ export declare function generateNonce(): string;
77
+ /**
78
+ * 解析卡片消息
79
+ */
80
+ export declare function parseCardMessage(content: string): any[];
81
+ /**
82
+ * 构建简单文本卡片
83
+ */
84
+ export declare function buildTextCard(text: string, theme?: 'primary' | 'success' | 'danger' | 'warning' | 'info' | 'secondary' | 'none'): string;
85
+ /**
86
+ * 构建图片卡片
87
+ */
88
+ export declare function buildImageCard(imageUrl: string, title?: string): string;
89
+ /**
90
+ * 计算消息签名(用于验证)
91
+ */
92
+ export declare function calculateSignature(data: string, key: string): string;
93
+ //# sourceMappingURL=utils.d.ts.map
package/lib/utils.js ADDED
@@ -0,0 +1,240 @@
1
+ /**
2
+ * KOOK (开黑了) 工具函数
3
+ */
4
+ import { createDecipheriv, createHash } from 'crypto';
5
+ /**
6
+ * 验证 Webhook 请求
7
+ */
8
+ export function verifyWebhook(body, verifyToken) {
9
+ if (!body || !body.d)
10
+ return false;
11
+ return body.d.verify_token === verifyToken;
12
+ }
13
+ /**
14
+ * 解密 Webhook 消息(当配置了 encryptKey 时)
15
+ */
16
+ export function decryptWebhookMessage(encryptedData, encryptKey) {
17
+ if (!encryptKey) {
18
+ throw new Error('未配置 encryptKey,无法解密消息');
19
+ }
20
+ try {
21
+ // 解码 base64
22
+ const encrypted = Buffer.from(encryptedData, 'base64');
23
+ // 提取 IV(前 16 字节)
24
+ const iv = encrypted.slice(0, 16);
25
+ const ciphertext = encrypted.slice(16);
26
+ // 生成密钥(encryptKey 需要是 32 字节)
27
+ const key = Buffer.alloc(32);
28
+ Buffer.from(encryptKey).copy(key);
29
+ // 解密
30
+ const decipher = createDecipheriv('aes-256-cbc', key, iv);
31
+ let decrypted = decipher.update(ciphertext);
32
+ decrypted = Buffer.concat([decrypted, decipher.final()]);
33
+ return decrypted.toString('utf-8');
34
+ }
35
+ catch (error) {
36
+ throw new Error(`解密消息失败: ${error.message}`);
37
+ }
38
+ }
39
+ /**
40
+ * 解析 KMarkdown 消息为文本
41
+ */
42
+ export function parseKMarkdown(content) {
43
+ if (!content)
44
+ return '';
45
+ // 移除 KMarkdown 格式标记
46
+ let text = content;
47
+ // 移除加粗 **text**
48
+ text = text.replace(/\*\*(.+?)\*\*/g, '$1');
49
+ // 移除斜体 *text*
50
+ text = text.replace(/\*(.+?)\*/g, '$1');
51
+ // 移除删除线 ~~text~~
52
+ text = text.replace(/~~(.+?)~~/g, '$1');
53
+ // 移除下划线 (ins)text(/ins)
54
+ text = text.replace(/\(ins\)(.+?)\(\/ins\)/g, '$1');
55
+ // 移除剧透 (spl)text(/spl)
56
+ text = text.replace(/\(spl\)(.+?)\(\/spl\)/g, '$1');
57
+ // 提取链接文本 [text](url)
58
+ text = text.replace(/\[(.+?)\]\(.+?\)/g, '$1');
59
+ // 提取 @用户 (met)id(/met)
60
+ text = text.replace(/\(met\)(\w+)\(\/met\)/g, '@$1');
61
+ // 提取 @角色 (rol)id(/rol)
62
+ text = text.replace(/\(rol\)(\w+)\(\/rol\)/g, '@角色$1');
63
+ // 提取 #频道 (chn)id(/chn)
64
+ text = text.replace(/\(chn\)(\w+)\(\/chn\)/g, '#$1');
65
+ // 提取表情 (emj)name(/emj)[id]
66
+ text = text.replace(/\(emj\)(.+?)\(\/emj\)\[.+?\]/g, ':$1:');
67
+ // 移除代码块 ```code```
68
+ text = text.replace(/```[\s\S]*?```/g, '[代码块]');
69
+ // 移除行内代码 `code`
70
+ text = text.replace(/`(.+?)`/g, '$1');
71
+ return text.trim();
72
+ }
73
+ /**
74
+ * 将文本转换为 KMarkdown 格式
75
+ */
76
+ export function textToKMarkdown(text) {
77
+ // 转义特殊字符
78
+ return text
79
+ .replace(/\\/g, '\\\\')
80
+ .replace(/\*/g, '\\*')
81
+ .replace(/~/g, '\\~')
82
+ .replace(/`/g, '\\`')
83
+ .replace(/\[/g, '\\[')
84
+ .replace(/\(/g, '\\(');
85
+ }
86
+ /**
87
+ * 构建 @用户 的 KMarkdown
88
+ */
89
+ export function mentionUser(userId) {
90
+ return `(met)${userId}(/met)`;
91
+ }
92
+ /**
93
+ * 构建 @全体成员 的 KMarkdown
94
+ */
95
+ export function mentionAll() {
96
+ return '(met)all(/met)';
97
+ }
98
+ /**
99
+ * 构建 @在线成员 的 KMarkdown
100
+ */
101
+ export function mentionHere() {
102
+ return '(met)here(/met)';
103
+ }
104
+ /**
105
+ * 构建 @角色 的 KMarkdown
106
+ */
107
+ export function mentionRole(roleId) {
108
+ return `(rol)${roleId}(/rol)`;
109
+ }
110
+ /**
111
+ * 构建 #频道 的 KMarkdown
112
+ */
113
+ export function mentionChannel(channelId) {
114
+ return `(chn)${channelId}(/chn)`;
115
+ }
116
+ /**
117
+ * 构建表情的 KMarkdown
118
+ */
119
+ export function emojiKMarkdown(emojiName, emojiId) {
120
+ return `(emj)${emojiName}(emj)[${emojiId}]`;
121
+ }
122
+ /**
123
+ * 构建链接的 KMarkdown
124
+ */
125
+ export function linkKMarkdown(text, url) {
126
+ return `[${text}](${url})`;
127
+ }
128
+ /**
129
+ * 构建加粗的 KMarkdown
130
+ */
131
+ export function boldKMarkdown(text) {
132
+ return `**${text}**`;
133
+ }
134
+ /**
135
+ * 构建斜体的 KMarkdown
136
+ */
137
+ export function italicKMarkdown(text) {
138
+ return `*${text}*`;
139
+ }
140
+ /**
141
+ * 构建删除线的 KMarkdown
142
+ */
143
+ export function strikethroughKMarkdown(text) {
144
+ return `~~${text}~~`;
145
+ }
146
+ /**
147
+ * 构建代码块的 KMarkdown
148
+ */
149
+ export function codeBlockKMarkdown(code, language) {
150
+ return `\`\`\`${language || ''}\n${code}\n\`\`\``;
151
+ }
152
+ /**
153
+ * 构建行内代码的 KMarkdown
154
+ */
155
+ export function inlineCodeKMarkdown(code) {
156
+ return `\`${code}\``;
157
+ }
158
+ /**
159
+ * 构建引用的 KMarkdown
160
+ */
161
+ export function quoteKMarkdown(text) {
162
+ return `> ${text}`;
163
+ }
164
+ /**
165
+ * 构建分割线的 KMarkdown
166
+ */
167
+ export function dividerKMarkdown() {
168
+ return '---';
169
+ }
170
+ /**
171
+ * 生成随机 nonce
172
+ */
173
+ export function generateNonce() {
174
+ return `${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;
175
+ }
176
+ /**
177
+ * 解析卡片消息
178
+ */
179
+ export function parseCardMessage(content) {
180
+ try {
181
+ return JSON.parse(content);
182
+ }
183
+ catch {
184
+ return [];
185
+ }
186
+ }
187
+ /**
188
+ * 构建简单文本卡片
189
+ */
190
+ export function buildTextCard(text, theme = 'primary') {
191
+ const card = [{
192
+ type: 'card',
193
+ theme,
194
+ size: 'lg',
195
+ modules: [{
196
+ type: 'section',
197
+ text: {
198
+ type: 'plain-text',
199
+ content: text,
200
+ },
201
+ }],
202
+ }];
203
+ return JSON.stringify(card);
204
+ }
205
+ /**
206
+ * 构建图片卡片
207
+ */
208
+ export function buildImageCard(imageUrl, title) {
209
+ const modules = [];
210
+ if (title) {
211
+ modules.push({
212
+ type: 'header',
213
+ text: {
214
+ type: 'plain-text',
215
+ content: title,
216
+ },
217
+ });
218
+ }
219
+ modules.push({
220
+ type: 'container',
221
+ elements: [{
222
+ type: 'image',
223
+ src: imageUrl,
224
+ }],
225
+ });
226
+ const card = [{
227
+ type: 'card',
228
+ theme: 'none',
229
+ size: 'lg',
230
+ modules,
231
+ }];
232
+ return JSON.stringify(card);
233
+ }
234
+ /**
235
+ * 计算消息签名(用于验证)
236
+ */
237
+ export function calculateSignature(data, key) {
238
+ return createHash('sha256').update(data + key).digest('hex');
239
+ }
240
+ //# sourceMappingURL=utils.js.map
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@onebots/adapter-kook",
3
+ "version": "1.0.0",
4
+ "description": "onebots KOOK(开黑了)适配器",
5
+ "type": "module",
6
+ "main": "lib/index.js",
7
+ "types": "lib/index.d.ts",
8
+ "keywords": [
9
+ "onebots",
10
+ "kook",
11
+ "kaiheila",
12
+ "adapter"
13
+ ],
14
+ "author": "凉菜",
15
+ "license": "MIT",
16
+ "publishConfig": {
17
+ "access": "public",
18
+ "registry": "https://registry.npmjs.org"
19
+ },
20
+ "files": [
21
+ "/lib/**/*.js",
22
+ "/lib/**/*.d.ts"
23
+ ],
24
+ "devDependencies": {
25
+ "tsc-alias": "latest",
26
+ "typescript": "latest",
27
+ "@types/node": "^22.7.3"
28
+ },
29
+ "peerDependencies": {
30
+ "onebots": "1.0.0"
31
+ },
32
+ "dependencies": {
33
+ "kook-client": "^1.0.4"
34
+ },
35
+ "scripts": {
36
+ "build": "rm -f *.tsbuildinfo && tsc --project tsconfig.json && tsc-alias -p tsconfig.json",
37
+ "clean": "rm -rf lib *.tsbuildinfo"
38
+ }
39
+ }