@zhin.js/adapter-icqq 1.0.16 → 1.0.18

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,158 @@
1
+ # @zhin.js/adapter-icqq
2
+
3
+ ## 1.0.18
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [8f75b7f]
8
+ - @zhin.js/console@1.0.11
9
+
10
+ ## 1.0.17
11
+
12
+ ### Patch Changes
13
+
14
+ - f4a7dd7: fix: force build
15
+
16
+ ## 1.0.16
17
+
18
+ ### Patch Changes
19
+
20
+ - 547028f: fix: 优化包结构,优化客户端支持
21
+ - Updated dependencies [547028f]
22
+ - @zhin.js/console@1.0.10
23
+ - @zhin.js/types@1.0.5
24
+ - @zhin.js/http@1.0.7
25
+ - zhin.js@1.0.14
26
+
27
+ ## 1.0.15
28
+
29
+ ### Patch Changes
30
+
31
+ - Updated dependencies [4034b94]
32
+ - @zhin.js/console@1.0.9
33
+ - zhin.js@1.0.13
34
+
35
+ ## 1.0.14
36
+
37
+ ### Patch Changes
38
+
39
+ - zhin.js@1.0.12
40
+
41
+ ## 1.0.13
42
+
43
+ ### Patch Changes
44
+
45
+ - zhin.js@1.0.11
46
+
47
+ ## 1.0.12
48
+
49
+ ### Patch Changes
50
+
51
+ - Updated dependencies [c1a539e]
52
+ - Updated dependencies [c8c3996]
53
+ - @zhin.js/console@1.0.8
54
+ - @zhin.js/types@1.0.4
55
+ - zhin.js@1.0.10
56
+
57
+ ## 1.0.11
58
+
59
+ ### Patch Changes
60
+
61
+ - c490260: fix: 更新脚手架结构,优化包依赖
62
+ - Updated dependencies [c490260]
63
+ - @zhin.js/console@1.0.7
64
+ - @zhin.js/client@1.0.5
65
+ - @zhin.js/http@1.0.6
66
+ - zhin.js@1.0.9
67
+
68
+ ## 1.0.10
69
+
70
+ ### Patch Changes
71
+
72
+ - 551c4d2: fix: 插件支持配置文件读取,优化 test 用例
73
+ - Updated dependencies [551c4d2]
74
+ - @zhin.js/console@1.0.6
75
+ - @zhin.js/types@1.0.3
76
+ - @zhin.js/client@1.0.4
77
+ - zhin.js@1.0.8
78
+ - @zhin.js/http@1.0.5
79
+
80
+ ## 1.0.9
81
+
82
+ ### Patch Changes
83
+
84
+ - Updated dependencies [47845fb]
85
+ - @zhin.js/console@1.0.5
86
+ - zhin.js@1.0.7
87
+
88
+ ## 1.0.8
89
+
90
+ ### Patch Changes
91
+
92
+ - Updated dependencies [c2d9047]
93
+ - Updated dependencies [c2d9047]
94
+ - Updated dependencies [b213bbc]
95
+ - @zhin.js/console@1.0.4
96
+ - @zhin.js/client@1.0.3
97
+ - @zhin.js/http@1.0.4
98
+ - zhin.js@1.0.6
99
+
100
+ ## 1.0.7
101
+
102
+ ### Patch Changes
103
+
104
+ - Updated dependencies [5e2bddc]
105
+ - @zhin.js/console@1.0.3
106
+
107
+ ## 1.0.6
108
+
109
+ ### Patch Changes
110
+
111
+ - Updated dependencies [f347667]
112
+ - @zhin.js/http@1.0.3
113
+ - zhin.js@1.0.5
114
+
115
+ ## 1.0.5
116
+
117
+ ### Patch Changes
118
+
119
+ - Updated dependencies [d291005]
120
+ - @zhin.js/console@1.0.2
121
+ - @zhin.js/client@1.0.2
122
+ - @zhin.js/http@1.0.2
123
+
124
+ ## 1.0.4
125
+
126
+ ### Patch Changes
127
+
128
+ - zhin.js@1.0.4
129
+
130
+ ## 1.0.3
131
+
132
+ ### Patch Changes
133
+
134
+ - 89bc676: fix: 类型反射优化
135
+ - Updated dependencies [727963c]
136
+ - Updated dependencies [89bc676]
137
+ - @zhin.js/console@1.0.1
138
+ - @zhin.js/client@1.0.1
139
+ - @zhin.js/types@1.0.2
140
+ - zhin.js@1.0.3
141
+
142
+ ## 1.0.2
143
+
144
+ ### Patch Changes
145
+
146
+ - 3ecd487: fix: 函数式组件,更新文档
147
+ - Updated dependencies [15fc934]
148
+ - zhin.js@1.0.2
149
+
150
+ ## 1.0.1
151
+
152
+ ### Patch Changes
153
+
154
+ - efdd58a: fix: init
155
+ - Updated dependencies [efdd58a]
156
+ - @zhin.js/types@1.0.1
157
+ - zhin.js@1.0.1
158
+ - @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.18",
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",
47
+ "@zhin.js/types": "1.0.5",
45
48
  "@zhin.js/http": "1.0.7",
46
- "@zhin.js/console": "1.0.10",
47
- "@zhin.js/types": "1.0.5"
49
+ "@zhin.js/client": "1.0.5",
50
+ "@zhin.js/console": "1.0.11"
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
+ })