@zhin.js/adapter-icqq 1.0.16 → 1.0.17

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 ADDED
@@ -0,0 +1,151 @@
1
+ # @zhin.js/adapter-icqq
2
+
3
+ ## 1.0.17
4
+
5
+ ### Patch Changes
6
+
7
+ - f4a7dd7: fix: force build
8
+
9
+ ## 1.0.16
10
+
11
+ ### Patch Changes
12
+
13
+ - 547028f: fix: 优化包结构,优化客户端支持
14
+ - Updated dependencies [547028f]
15
+ - @zhin.js/console@1.0.10
16
+ - @zhin.js/types@1.0.5
17
+ - @zhin.js/http@1.0.7
18
+ - zhin.js@1.0.14
19
+
20
+ ## 1.0.15
21
+
22
+ ### Patch Changes
23
+
24
+ - Updated dependencies [4034b94]
25
+ - @zhin.js/console@1.0.9
26
+ - zhin.js@1.0.13
27
+
28
+ ## 1.0.14
29
+
30
+ ### Patch Changes
31
+
32
+ - zhin.js@1.0.12
33
+
34
+ ## 1.0.13
35
+
36
+ ### Patch Changes
37
+
38
+ - zhin.js@1.0.11
39
+
40
+ ## 1.0.12
41
+
42
+ ### Patch Changes
43
+
44
+ - Updated dependencies [c1a539e]
45
+ - Updated dependencies [c8c3996]
46
+ - @zhin.js/console@1.0.8
47
+ - @zhin.js/types@1.0.4
48
+ - zhin.js@1.0.10
49
+
50
+ ## 1.0.11
51
+
52
+ ### Patch Changes
53
+
54
+ - c490260: fix: 更新脚手架结构,优化包依赖
55
+ - Updated dependencies [c490260]
56
+ - @zhin.js/console@1.0.7
57
+ - @zhin.js/client@1.0.5
58
+ - @zhin.js/http@1.0.6
59
+ - zhin.js@1.0.9
60
+
61
+ ## 1.0.10
62
+
63
+ ### Patch Changes
64
+
65
+ - 551c4d2: fix: 插件支持配置文件读取,优化 test 用例
66
+ - Updated dependencies [551c4d2]
67
+ - @zhin.js/console@1.0.6
68
+ - @zhin.js/types@1.0.3
69
+ - @zhin.js/client@1.0.4
70
+ - zhin.js@1.0.8
71
+ - @zhin.js/http@1.0.5
72
+
73
+ ## 1.0.9
74
+
75
+ ### Patch Changes
76
+
77
+ - Updated dependencies [47845fb]
78
+ - @zhin.js/console@1.0.5
79
+ - zhin.js@1.0.7
80
+
81
+ ## 1.0.8
82
+
83
+ ### Patch Changes
84
+
85
+ - Updated dependencies [c2d9047]
86
+ - Updated dependencies [c2d9047]
87
+ - Updated dependencies [b213bbc]
88
+ - @zhin.js/console@1.0.4
89
+ - @zhin.js/client@1.0.3
90
+ - @zhin.js/http@1.0.4
91
+ - zhin.js@1.0.6
92
+
93
+ ## 1.0.7
94
+
95
+ ### Patch Changes
96
+
97
+ - Updated dependencies [5e2bddc]
98
+ - @zhin.js/console@1.0.3
99
+
100
+ ## 1.0.6
101
+
102
+ ### Patch Changes
103
+
104
+ - Updated dependencies [f347667]
105
+ - @zhin.js/http@1.0.3
106
+ - zhin.js@1.0.5
107
+
108
+ ## 1.0.5
109
+
110
+ ### Patch Changes
111
+
112
+ - Updated dependencies [d291005]
113
+ - @zhin.js/console@1.0.2
114
+ - @zhin.js/client@1.0.2
115
+ - @zhin.js/http@1.0.2
116
+
117
+ ## 1.0.4
118
+
119
+ ### Patch Changes
120
+
121
+ - zhin.js@1.0.4
122
+
123
+ ## 1.0.3
124
+
125
+ ### Patch Changes
126
+
127
+ - 89bc676: fix: 类型反射优化
128
+ - Updated dependencies [727963c]
129
+ - Updated dependencies [89bc676]
130
+ - @zhin.js/console@1.0.1
131
+ - @zhin.js/client@1.0.1
132
+ - @zhin.js/types@1.0.2
133
+ - zhin.js@1.0.3
134
+
135
+ ## 1.0.2
136
+
137
+ ### Patch Changes
138
+
139
+ - 3ecd487: fix: 函数式组件,更新文档
140
+ - Updated dependencies [15fc934]
141
+ - zhin.js@1.0.2
142
+
143
+ ## 1.0.1
144
+
145
+ ### Patch Changes
146
+
147
+ - efdd58a: fix: init
148
+ - Updated dependencies [efdd58a]
149
+ - @zhin.js/types@1.0.1
150
+ - zhin.js@1.0.1
151
+ - @zhin.js/http@1.0.1
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ import{jsx as e}from"react/jsx-runtime";import{addPage as t}from"@zhin.js/client";import{Bot as m}from"lucide-react";function n(){return e("div",{children:"ICQQManagement"})}t({key:"icqq-management",path:"/icqq",title:"ICQQ管理",icon:e(m,{className:"w-5 h-5"}),element:e(n,{})});
package/package.json CHANGED
@@ -1,15 +1,10 @@
1
1
  {
2
2
  "name": "@zhin.js/adapter-icqq",
3
- "version": "1.0.16",
3
+ "version": "1.0.17",
4
4
  "description": "zhin adapter for icqq",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
7
7
  "types": "./lib/index.d.ts",
8
- "files": [
9
- "lib",
10
- "client",
11
- "README.md"
12
- ],
13
8
  "exports": {
14
9
  ".": {
15
10
  "types": "./lib/index.d.ts",
@@ -28,6 +23,14 @@
28
23
  "type": "git",
29
24
  "directory": "plugins/adapters/icqq"
30
25
  },
26
+ "files": [
27
+ "lib",
28
+ "README.md",
29
+ "CHANGELOG.md",
30
+ "client",
31
+ "src",
32
+ "dist"
33
+ ],
31
34
  "dependencies": {
32
35
  "@icqqjs/icqq": "latest"
33
36
  },
@@ -41,10 +44,10 @@
41
44
  },
42
45
  "peerDependencies": {
43
46
  "zhin.js": "1.0.14",
44
- "@zhin.js/client": "1.0.5",
45
47
  "@zhin.js/http": "1.0.7",
48
+ "@zhin.js/types": "1.0.5",
46
49
  "@zhin.js/console": "1.0.10",
47
- "@zhin.js/types": "1.0.5"
50
+ "@zhin.js/client": "1.0.5"
48
51
  },
49
52
  "peerDependenciesMeta": {
50
53
  "@zhin.js/client": {
@@ -61,7 +64,7 @@
61
64
  }
62
65
  },
63
66
  "scripts": {
64
- "build": "tsc && (zhin-console build || echo 'Skipping client build: zhin-console not found')",
67
+ "build": "tsc && (test -f ../../services/console/lib/bin.js && node ../../services/console/lib/bin.js build || echo 'Skipping client build: console not built yet')",
65
68
  "clean": "rm -rf lib"
66
69
  }
67
70
  }
package/src/index.ts ADDED
@@ -0,0 +1,247 @@
1
+ import { Config, Client, PrivateMessageEvent, GroupMessageEvent, Sendable, MessageElem} from "@icqqjs/icqq";
2
+ import path from "path";
3
+ import {
4
+ Bot,
5
+ usePlugin,
6
+ useContext,
7
+ Adapter,
8
+ Plugin,
9
+ registerAdapter,
10
+ Message,
11
+ SendOptions,
12
+ MessageSegment,
13
+ SendContent,
14
+ segment
15
+ } from "zhin.js";
16
+ declare module '@zhin.js/types'{
17
+ interface RegisteredAdapters{
18
+ icqq:Adapter<IcqqBot>
19
+ }
20
+ }
21
+ const plugin =usePlugin()
22
+ export interface IcqqBotConfig extends Bot.Config,Config{
23
+ context:'icqq'
24
+ name:`${number}`
25
+ password?:string
26
+ scope?:string
27
+ }
28
+ export interface IcqqBot{
29
+ $config:IcqqBotConfig
30
+ }
31
+ export class IcqqBot extends Client implements Bot<PrivateMessageEvent|GroupMessageEvent,IcqqBotConfig>{
32
+ $connected?:boolean
33
+ constructor(config:IcqqBotConfig) {
34
+ if(!config.scope) config.scope='icqqjs'
35
+ if(!config.data_dir) config.data_dir=path.join(process.cwd(),'data')
36
+ if(config.scope.startsWith('@')) config.scope=config.scope.slice(1)
37
+ super(config);
38
+ this.$config=config
39
+ }
40
+ private handleIcqqMessage(msg: PrivateMessageEvent|GroupMessageEvent): void {
41
+ const message =this.$formatMessage(msg) ;
42
+ plugin.dispatch('message.receive',message)
43
+ plugin.logger.info(`${this.$config.name} recv ${message.$channel.type}(${message.$channel.id}):${segment.raw(message.$content)}`)
44
+ plugin.dispatch(`message.${message.$channel.type}.receive`,message)
45
+ }
46
+ async $connect(): Promise<void> {
47
+ this.on('message',this.handleIcqqMessage.bind(this))
48
+ this.on('system.login.device',async (e:unknown)=>{
49
+ await this.sendSmsCode()
50
+ plugin.logger.info('请输入短信验证码:')
51
+ process.stdin.once('data',(data)=>{
52
+ this.submitSmsCode(data.toString().trim())
53
+ })
54
+ })
55
+ this.on('system.login.qrcode',(e)=>{
56
+ plugin.logger.info(`取码地址:${e.image}\n请扫码完成后回车继续:`)
57
+ process.stdin.once('data',()=>{
58
+ this.login()
59
+ })
60
+ })
61
+ this.on('system.login.slider',(e)=>{
62
+ plugin.logger.info(`取码地址:${e.url}\n请输入滑块验证ticket:`)
63
+ process.stdin.once('data',(e)=>{
64
+ this.submitSlider(e.toString().trim())
65
+ })
66
+ })
67
+ return new Promise((resolve)=>{
68
+ this.once('system.online',()=>{
69
+ this.$connected=true;
70
+ resolve()
71
+ })
72
+ this.login(Number(this.$config.name),this.$config.password)
73
+ })
74
+ }
75
+
76
+ async $disconnect(): Promise<void> {
77
+ await this.logout()
78
+ this.$connected=false;
79
+ }
80
+ $formatMessage(msg:PrivateMessageEvent|GroupMessageEvent){
81
+ const result= Message.from(msg,{
82
+ $id: msg.message_id.toString(),
83
+ $adapter:'icqq',
84
+ $bot:`${this.$config.name}`,
85
+ $sender:{
86
+ id:msg.sender.user_id.toString(),
87
+ name:msg.sender.nickname.toString(),
88
+ },
89
+ $channel:{
90
+ id:msg.message_type==='group'?msg.group_id.toString():msg.from_id.toString(),
91
+ type:msg.message_type
92
+ },
93
+ $content: IcqqBot.toSegments(msg.message),
94
+ $raw: msg.raw_message,
95
+ $timestamp: msg.time,
96
+ $reply:async (content: SendContent, quote?: boolean|string):Promise<string>=> {
97
+ if(!Array.isArray(content)) content=[content];
98
+ if(quote) content.unshift({type:'reply',data:{id:typeof quote==="boolean"?result.$id:quote}})
99
+ return await this.$sendMessage({
100
+ ...result.$channel,
101
+ context:'icqq',
102
+ bot:`${this.uin}`,
103
+ content
104
+ })
105
+ }
106
+ })
107
+ return result
108
+ }
109
+ async $recallMessage(id:string):Promise<void> {
110
+ await this.deleteMsg(id)
111
+ }
112
+ async $sendMessage(options: SendOptions): Promise<string> {
113
+ options=await plugin.app.handleBeforeSend(options)
114
+ switch (options.type){
115
+ case 'private':{
116
+ const result= await this.sendPrivateMsg(Number(options.id),IcqqBot.toSendable(options.content))
117
+ plugin.logger.info(`${this.$config.name} send ${options.type}(${options.id}):${segment.raw(options.content)}`)
118
+ return result.message_id.toString()
119
+ break;
120
+ }
121
+ case "group":{
122
+ const result=await this.sendGroupMsg(Number(options.id),IcqqBot.toSendable(options.content))
123
+ plugin.logger.info(`${this.$config.name} send ${options.type}(${options.id}):${segment.raw(options.content)}`)
124
+ return result.message_id.toString()
125
+ break;
126
+ }
127
+ default:
128
+ throw new Error(`unsupported channel type ${options.type}`)
129
+ }
130
+ }
131
+
132
+ }
133
+ export namespace IcqqBot{
134
+ const allowTypes=[
135
+ 'text',
136
+ 'face',
137
+ 'image',
138
+ 'record',
139
+ 'audio',
140
+ 'dice',
141
+ 'rps',
142
+ 'video',
143
+ 'file',
144
+ 'location',
145
+ 'share',
146
+ 'json',
147
+ 'at',
148
+ 'reply',
149
+ 'long_msg',
150
+ 'button',
151
+ 'markdown',
152
+ 'xml',
153
+ ]
154
+ export function toSegments(message:Sendable):MessageSegment[]{
155
+ if(!Array.isArray(message)) message=[message]
156
+ return message.filter((item,index)=>{
157
+ return typeof item==="string"||(item.type!=='long_msg'||index!==0)
158
+ }).map((item):MessageSegment=>{
159
+ if(typeof item==="string") return {type:'text',data:{text:item}}
160
+ const {type,...data}=item
161
+ return {type,data}
162
+ })
163
+ }
164
+ export function toSendable(content:SendContent):Sendable{
165
+ if(!Array.isArray(content)) content=[content]
166
+ return content.map((seg):MessageElem=>{
167
+ if(typeof seg==="string") return {type:'text',text:seg}
168
+ let {type,data}=seg
169
+ if(typeof type==='function') type=type.name
170
+ if(!allowTypes.includes(type)) return {type:'text',text:segment.toString(seg)}
171
+ return {type,...data} as MessageElem
172
+ })
173
+ }
174
+ }
175
+ registerAdapter(new Adapter('icqq',IcqqBot))
176
+
177
+ useContext('web', (web) => {
178
+ // 注册ICQQ适配器的客户端入口文件
179
+ const dispose = web.addEntry({
180
+ production: path.resolve(import.meta.dirname, '../dist/index.js'),
181
+ development: path.resolve(import.meta.dirname, '../client/index.tsx')
182
+ })
183
+ return dispose
184
+ });
185
+ useContext('router','icqq', (router,icqq) => {
186
+ router.get('/api/icqq/bots', async (ctx) => {
187
+ try {
188
+ const bots = Array.from(icqq.bots.values())
189
+
190
+ if (bots.length === 0) {
191
+ ctx.body = {
192
+ success: true,
193
+ data: [],
194
+ message: '暂无ICQQ机器人实例'
195
+ }
196
+ return
197
+ }
198
+
199
+ const result = bots.map(bot => {
200
+ try {
201
+ return {
202
+ name: bot.$config.name,
203
+ connected: bot.$connected || false,
204
+ groupCount: bot.gl?.size || 0,
205
+ friendCount: bot.fl?.size || 0,
206
+ receiveCount: bot.stat?.recv_msg_cnt || 0,
207
+ sendCount: bot.stat?.sent_msg_cnt || 0,
208
+ loginMode: bot.$config.password ? 'password' : 'qrcode',
209
+ status: bot.$connected ? 'online' : 'offline',
210
+ lastActivity: new Date().toISOString()
211
+ }
212
+ } catch (botError) {
213
+ // 单个机器人数据获取失败时的处理
214
+ // 获取机器人数据失败,返回错误状态
215
+ return {
216
+ name: bot.$config.name,
217
+ connected: false,
218
+ groupCount: 0,
219
+ friendCount: 0,
220
+ receiveCount: 0,
221
+ sendCount: 0,
222
+ loginMode: 'unknown',
223
+ status: 'error',
224
+ error: '数据获取失败'
225
+ }
226
+ }
227
+ })
228
+
229
+ ctx.body = {
230
+ success: true,
231
+ data: result,
232
+ timestamp: new Date().toISOString()
233
+ }
234
+ } catch (error) {
235
+ // ICQQ API调用失败
236
+
237
+ ctx.status = 500
238
+ ctx.body = {
239
+ success: false,
240
+ error: 'ICQQ_API_ERROR',
241
+ message: '获取机器人数据失败',
242
+ details: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,
243
+ timestamp: new Date().toISOString()
244
+ }
245
+ }
246
+ })
247
+ })