karin-plugin-mys-core 1.0.4 → 1.0.5

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.
Files changed (70) hide show
  1. package/README.md +1031 -76
  2. package/lib/apps/MiHoYoLogin.js +13 -12
  3. package/lib/apps/MysDevice.js +12 -13
  4. package/lib/apps/UIDManage.js +13 -12
  5. package/lib/{array-DuqoS2wx.d.ts → array-CCexQ14j.d.ts} +1 -1
  6. package/lib/chunk-AY34PPJT.js +72 -0
  7. package/lib/{chunk-3BIQN6QA.js → chunk-BWFWWHCT.js} +20 -1
  8. package/lib/{chunk-JKZ5NRPX.js → chunk-BXA3VAQC.js} +3 -2
  9. package/lib/{chunk-WQK5RDUV.js → chunk-DJTJKSNN.js} +157 -164
  10. package/lib/chunk-UC6INRYV.js +0 -0
  11. package/lib/chunk-UX2BDLJF.js +6 -0
  12. package/lib/{chunk-NC54IKOY.js → chunk-ZZ5BYFNK.js} +83 -6
  13. package/lib/exports/config/array.d.ts +1 -1
  14. package/lib/exports/config/config.d.ts +1 -1
  15. package/lib/exports/config/config.js +1 -1
  16. package/lib/exports/config/index.d.ts +1 -1
  17. package/lib/exports/config/index.js +1 -1
  18. package/lib/exports/database/database.js +1 -1
  19. package/lib/exports/database/dbs/base.js +1 -1
  20. package/lib/exports/database/dbs/index.js +1 -1
  21. package/lib/exports/database/dbs/sqlite3.js +1 -1
  22. package/lib/exports/database/dbs/table.js +1 -1
  23. package/lib/exports/database/index.js +8 -9
  24. package/lib/exports/database/tables/index.js +6 -7
  25. package/lib/exports/database/tables/mysAccountInfo.js +1 -1
  26. package/lib/exports/database/tables/mysDeviceInfo.js +2 -3
  27. package/lib/exports/database/tables/mysUserInfo.js +1 -1
  28. package/lib/exports/database/types/index.js +3 -3
  29. package/lib/exports/database/types/tables/index.js +3 -3
  30. package/lib/exports/mys/api/apis.d.ts +2 -2
  31. package/lib/exports/mys/api/apis.js +10 -11
  32. package/lib/exports/mys/api/app.js +3 -4
  33. package/lib/exports/mys/api/define.js +10 -11
  34. package/lib/exports/mys/api/index.js +13 -14
  35. package/lib/exports/mys/index.d.ts +3 -3
  36. package/lib/exports/mys/index.js +15 -17
  37. package/lib/exports/mys/types/index.d.ts +2 -2
  38. package/lib/exports/mys/types/index.js +1 -7
  39. package/lib/exports/mys/types/user/game.d.ts +2 -13
  40. package/lib/exports/mys/types/user/game.js +1 -7
  41. package/lib/exports/mys/types/user/index.d.ts +2 -2
  42. package/lib/exports/mys/types/user/index.js +1 -7
  43. package/lib/exports/mys/types/user/userInfo.d.ts +2 -2
  44. package/lib/exports/mys/user/deviceInfo.js +3 -4
  45. package/lib/exports/mys/user/game.d.ts +15 -4
  46. package/lib/exports/mys/user/game.js +5 -3
  47. package/lib/exports/mys/user/index.d.ts +1 -1
  48. package/lib/exports/mys/user/index.js +16 -15
  49. package/lib/exports/mys/user/userInfo.js +10 -11
  50. package/lib/exports/render/index.d.ts +3 -0
  51. package/lib/exports/render/index.js +13 -0
  52. package/lib/exports/render/render.d.ts +38 -0
  53. package/lib/exports/render/render.js +9 -0
  54. package/lib/exports/utils/common.d.ts +33 -1
  55. package/lib/exports/utils/index.d.ts +1 -3
  56. package/lib/exports/utils/index.js +1 -5
  57. package/package.json +11 -2
  58. package/resources/styles/karin-plugin-mys-core.css +1059 -0
  59. package/lib/chunk-CDBMB57U.js +0 -52
  60. package/lib/chunk-T6MFN2MO.js +0 -23
  61. package/lib/common-Dw5l6Uud.d.ts +0 -33
  62. package/lib/exports/utils/render.d.ts +0 -27
  63. package/lib/exports/utils/render.js +0 -7
  64. package/resources/template/ShowBindAccount/index.css +0 -1
  65. package/resources/template/ShowBindAccount/index.html +0 -65
  66. package/resources/template/ShowBindDevice/index.html +0 -20
  67. package/resources/template/ShowBindDevice/inex.css +0 -1
  68. package/resources/template/layout/default.css +0 -1
  69. package/resources/template/layout/default.html +0 -27
  70. /package/lib/{chunk-ARLTXJFJ.js → chunk-FOAQZIZ2.js} +0 -0
package/README.md CHANGED
@@ -1,123 +1,1078 @@
1
- # Karin TypeScript 插件开发模板
1
+ <h1 align="center"><font color="#3f7dd1">karin-plugin-mys-core</font></h1>
2
2
 
3
3
  ## 📖 目录
4
4
 
5
5
  - [前言](#前言)
6
- - [快速开始](#快速开始)
7
- - [详细开发流程](#详细开发流程)
8
- - [常见问题与建议](#常见问题与建议)
6
+ - [快速安装](#快速安装)
7
+ - [游戏模块](#游戏模块)
8
+ - [API 文档](#api-文档)
9
+ - [配置模块 (config)](#配置模块-config)
10
+ - [数据库模块 (database)](#数据库模块-database)
11
+ - [米游社模块 (mys)](#米游社模块-mys)
12
+ - [渲染模块 (render)](#渲染模块-render)
13
+ - [工具模块 (utils)](#工具模块-utils)
9
14
  - [贡献与反馈](#贡献与反馈)
10
15
 
11
16
  ---
12
17
 
13
- ## 前言
18
+ ## 快速安装
14
19
 
15
- TypeScript 插件开发流程现在更加简单,无需手动克隆模板仓库,只需一条命令即可快速开始!
20
+ - 本插件已加入插件商店,可在插件商店中一键下载安装。
16
21
 
17
- > TypeScript 编写 → 编译为 JS → 发布 NPM 包 → 用户安装
22
+ ---
23
+
24
+ ## 游戏模块
25
+ > [!TIP]
26
+ > 本插件并不直接提供完整的游戏功能
27
+
28
+ - 自行编写请查看[karin-plugin-mys-template](https://github.com/Karin-Mys-Plugins/karin-plugin-mys-template)
29
+
30
+ ---
31
+
32
+ ## API 文档
33
+
34
+ ### 配置模块 (config)
35
+
36
+ 配置模块提供了强大的配置文件管理功能,包括配置类和增强数组类。
37
+
38
+ #### 导入方式
39
+
40
+ ```typescript
41
+ import { Config } from 'karin-plugin-mys-core/config'
42
+ ```
43
+
44
+ #### Config 类
45
+
46
+ 用于管理 JSON 配置文件,支持自动补全、类型安全和实时监听。
47
+
48
+ **构造函数**
49
+
50
+ ```typescript
51
+ const config = new Config<ConfigType>(
52
+ 'plugin-name:config-name', // 配置名称
53
+ '/path/to/config.json', // 配置文件路径
54
+ defaultConfig, // 默认配置对象
55
+ defineConfig // 配置定义对象
56
+ )
57
+ ```
58
+
59
+ **主要方法**
60
+
61
+ ```typescript
62
+ // 获取配置值
63
+ const value = config.get<T>('key.path')
64
+
65
+ // 设置配置值
66
+ config.set<T>('key.path', value, save?: boolean)
67
+
68
+ // 获取数组配置(返回 EnhancedArray)
69
+ const arr = config.getArray<T>('key.path')
70
+
71
+ // 监听配置变化(文件修改时触发)
72
+ config.watch((self, oldData, newData) => {
73
+ console.log('配置已更新')
74
+ console.log('旧配置:', oldData)
75
+ console.log('新配置:', newData)
76
+
77
+ // 可以在这里处理配置变化后的逻辑
78
+ if (oldData.enable !== newData.enable) {
79
+ console.log('功能启用状态已改变')
80
+ }
81
+ })
82
+
83
+ // 手动保存配置
84
+ config.save()
85
+
86
+ // 重新加载配置
87
+ config.loadConfig()
88
+ ```
89
+
90
+ **示例**
91
+
92
+ ```typescript
93
+ interface MyConfig {
94
+ enable: boolean
95
+ users: string[]
96
+ settings: {
97
+ timeout: number
98
+ }
99
+ }
100
+
101
+ const config = new Config<MyConfig>(
102
+ 'my-plugin:config',
103
+ './config/config.json',
104
+ {
105
+ enable: true,
106
+ users: [],
107
+ settings: { timeout: 5000 }
108
+ },
109
+ {}
110
+ )
111
+
112
+ // 获取配置
113
+ const isEnabled = config.get<boolean>('enable')
114
+
115
+ // 设置配置
116
+ config.set('settings.timeout', 10000, true)
117
+
118
+ // 获取数组
119
+ const users = config.getArray<string>('users')
120
+ users.add('user1', true, true)
121
+
122
+ // 监听配置文件变化
123
+ config.watch((self, oldData, newData) => {
124
+ console.log('配置文件已被外部修改')
125
+
126
+ // 检查特定字段的变化
127
+ if (oldData.enable !== newData.enable) {
128
+ console.log(`功能状态变更: ${oldData.enable} -> ${newData.enable}`)
129
+ }
130
+
131
+ if (oldData.settings.timeout !== newData.settings.timeout) {
132
+ console.log(`超时时间变更: ${oldData.settings.timeout}ms -> ${newData.settings.timeout}ms`)
133
+ }
134
+ })
135
+ ```
136
+
137
+ #### EnhancedArray 类
138
+
139
+ 扩展的数组类,提供了更多便捷的操作方法。
140
+
141
+ **主要方法**
142
+
143
+ ```typescript
144
+ // 检查元素是否存在
145
+ arr.has(element)
146
+
147
+ // 添加单个元素
148
+ arr.add(element, isEqual: boolean, save: boolean)
149
+
150
+ // 批量添加元素
151
+ arr.addSome(elements, isEqual: boolean, save: boolean)
152
+
153
+ // 删除元素
154
+ arr.remove(predicate, save: boolean)
155
+ arr.remove(index, save: boolean, true) // 按索引删除
156
+
157
+ // 批量删除元素
158
+ arr.removeSome(elements, save: boolean)
159
+ ```
160
+
161
+ **示例**
162
+
163
+ ```typescript
164
+ const users = config.getArray<string>('users')
165
+
166
+ // 添加元素(去重)
167
+ users.add('user1', true, true)
168
+
169
+ // 批量添加
170
+ users.addSome(['user2', 'user3'], true, true)
171
+
172
+ // 删除元素
173
+ users.remove('user1', true)
174
+
175
+ // 按条件删除
176
+ users.remove(user => user.startsWith('test'), true)
177
+
178
+ // 按索引删除
179
+ users.remove(0, true, true)
180
+ ```
181
+
182
+ ---
183
+
184
+ ### 数据库模块 (database)
185
+
186
+ 数据库模块提供了统一的数据库访问接口,支持 SQLite 等多种数据库。
187
+
188
+ #### 导入方式
189
+
190
+ ```typescript
191
+ import { Database } from 'karin-plugin-mys-core/database'
192
+ ```
193
+
194
+ #### Database 对象
195
+
196
+ **主要方法**
197
+
198
+ ```typescript
199
+ // 获取数据库实例
200
+ const db = Database.get<TableType, DatabaseType>()
201
+
202
+ // 设置默认数据库(不要在你的插件中随意使用)
203
+ Database.default(Dialect.Sqlite)
204
+
205
+ // 添加新的数据库支持
206
+ await Database.Add(DatabaseFn, StaticClass)
207
+
208
+ // 获取数据库列表
209
+ const dbList = Database.details
210
+ ```
211
+
212
+ **列定义方法**
213
+
214
+ ```typescript
215
+ // 1. 普通列 - Column(type, defaultValue, options?)
216
+ Database.Column(
217
+ 'STRING', // 数据类型:STRING, INTEGER, BOOLEAN, TEXT 等
218
+ 'default', // 默认值
219
+ { // 可选配置
220
+ allowNull: false, // 是否允许为空
221
+ unique: true // 是否唯一
222
+ }
223
+ )
224
+
225
+ // 2. 主键列 - PkColumn(type, options?)
226
+ Database.PkColumn(
227
+ 'STRING', // 数据类型
228
+ { // 可选配置(已包含 primaryKey: true, allowNull: false)
229
+ autoIncrement: true // 自动递增(仅数字类型)
230
+ }
231
+ )
232
+
233
+ // 3. 数组列 - ArrayColumn(key, transformFn?)
234
+ Database.ArrayColumn(
235
+ 'tags', // 列名(必须与 schema 中的 key 一致)
236
+ (data) => data // 可选:数据转换函数
237
+ )
238
+ // 存储格式:逗号分隔的字符串 "tag1,tag2,tag3"
239
+ // 读取返回:DatabaseArray<T> 类型
240
+
241
+ // 4. JSON 列 - JsonColumn(key, defaultValue)
242
+ Database.JsonColumn(
243
+ 'metadata', // 列名(必须与 schema 中的 key 一致)
244
+ {} // 默认值(JSON 对象)
245
+ )
246
+ // 存储格式:JSON 字符串
247
+ // 读取返回:自动解析为对象
248
+ ```
249
+
250
+ **完整列定义示例**
251
+
252
+ ```typescript
253
+ import { Database } from 'karin-plugin-mys-core/database'
254
+
255
+ const userSchema = {
256
+ // 主键列:只需指定类型
257
+ userId: Database.PkColumn('STRING'),
258
+
259
+ // 普通列:类型 + 默认值 + 可选配置
260
+ nickname: Database.Column('STRING', 'Guest', { allowNull: false }),
261
+ email: Database.Column('STRING', '', { unique: true }),
262
+ age: Database.Column('INTEGER', 0),
263
+ active: Database.Column('BOOLEAN', true),
264
+ bio: Database.Column('TEXT', ''),
265
+
266
+ // 数组列:列名必须与 key 一致
267
+ tags: Database.ArrayColumn('tags'),
268
+ // 或带转换函数
269
+ roles: Database.ArrayColumn('roles', (data) => {
270
+ return data.filter(role => role !== 'banned')
271
+ }),
272
+
273
+ // JSON 列:列名 + 默认值对象
274
+ profile: Database.JsonColumn('profile', { level: 1, exp: 0 }),
275
+ settings: Database.JsonColumn('settings', { theme: 'light' }),
276
+ metadata: Database.JsonColumn('metadata', {})
277
+ }
278
+ ```
279
+
280
+ **数据库类型**
281
+
282
+ 本模块支持三种数据库存储类型:
283
+
284
+ | 类型 | 说明 | 存储方式 | 适用场景 |
285
+ |------|------|---------|---------|
286
+ | `DatabaseType.Db` | SQL 数据库 | SQLite/MySQL 等数据库表 | 大量结构化数据、需要复杂查询 |
287
+ | `DatabaseType.File` | 单文件存储 | 每个记录一个 JSON 文件 | 小量数据、独立配置文件 |
288
+ | `DatabaseType.Dir` | 目录存储 | 每个记录一个目录,目录内多个 JSON 文件 | 复杂数据结构、需要分文件存储 |
289
+
290
+ > [!IMPORTANT]
291
+ > **大型数据库说明**:当使用 PostgreSQL、MySQL、MariaDB 等大型数据库时,**三种类型的存储方式都会统一使用 SQL 数据库表**。只有在使用 SQLite 时,才会根据不同的 `DatabaseType` 采用不同的存储策略(文件、目录或数据库)。
292
+ > 不论在使用什么数据库,编写代码时统一只考虑数据库为 SQLite 时使用何DatabaseType类型
293
+ > ```typescript
294
+ > // 使用 PostgreSQL 时(不要在你的插件中随意使用)
295
+ > Database.default(Dialect.PostgreSQL)
296
+ >
297
+ > // 这三种初始化方式最终都会使用 PostgreSQL 数据库表
298
+ > await db.init('./data', 'users', schema, DatabaseType.Db) // ✅ 数据库表
299
+ > await db.init('./data', 'users', schema, DatabaseType.File) // ✅ 数据库表(非文件)
300
+ > await db.init('./data', 'users', schema, DatabaseType.Dir) // ✅ 数据库表(非目录)
301
+ > ```
302
+
303
+ **初始化表**
304
+
305
+ 根据不同的数据库类型初始化表:
306
+
307
+ ```typescript
308
+ // 1. SQL 数据库模式(推荐用于大量数据)
309
+ const dbInstance = Database.get<UserType, DatabaseType.Db>()
310
+ await dbInstance.init(
311
+ './data', // 数据目录
312
+ 'users', // 表名
313
+ schema, // 表结构
314
+ DatabaseType.Db // 数据库类型:SQL 数据库
315
+ )
316
+ // 存储位置:./data/database/sqlite3.db(表名:users)
317
+
318
+ // 2. 单文件存储模式(适合独立配置)
319
+ const fileInstance = Database.get<ConfigType, DatabaseType.File>()
320
+ await fileInstance.init(
321
+ './data', // 数据目录
322
+ 'configs', // 目录名
323
+ schema, // 数据结构
324
+ DatabaseType.File // 数据库类型:单文件
325
+ )
326
+ // 存储位置:./data/configs/{userId}.json
327
+
328
+ // 3. 目录存储模式(适合复杂数据)
329
+ const dirInstance = Database.get<ComplexType, DatabaseType.Dir>()
330
+ await dirInstance.init(
331
+ './data', // 数据目录
332
+ 'userdata', // 目录名
333
+ schema, // 数据结构
334
+ DatabaseType.Dir // 数据库类型:目录
335
+ )
336
+ // 存储位置:./data/userdata/{userId}/*.json
337
+ ```
338
+
339
+ **数据库操作**
340
+
341
+ 所有类型的数据库都支持统一的操作接口:
342
+
343
+ ```typescript
344
+ // 查找记录(主键)
345
+ const record = await db.findByPk(pk, create?: boolean)
346
+
347
+ // 查找多个记录(批量查询)
348
+ const records = await db.findAllByPks(pks)
349
+
350
+ // 查找所有记录(可排除指定主键)
351
+ const allRecords = await db.findAll(excludePks?: string[])
352
+
353
+ // 保存记录
354
+ await record.save({ key: value })
355
+
356
+ // 删除记录
357
+ await record.destroy()
358
+ ```
359
+
360
+ **示例**
361
+
362
+ **示例 1:SQL 数据库模式 - 用户信息表**
363
+
364
+ ```typescript
365
+ import { Database, DatabaseType } from 'karin-plugin-mys-core/database'
366
+
367
+ // 定义用户表结构(注意参数顺序)
368
+ const userSchema = {
369
+ userId: Database.PkColumn('STRING'), // 主键
370
+ nickname: Database.Column('STRING', '', { allowNull: false }), // 默认值 '', 不允许为空
371
+ level: Database.Column('INTEGER', 1), // 默认值 1
372
+ coins: Database.Column('INTEGER', 0), // 默认值 0
373
+ vip: Database.Column('BOOLEAN', false), // 默认值 false
374
+ tags: Database.ArrayColumn('tags'), // 数组列
375
+ data: Database.JsonColumn('data', {}) // JSON 列,默认值 {}
376
+ }
377
+
378
+ // 初始化 SQL 数据库
379
+ const userDB = Database.get<UserType, DatabaseType.Db>()
380
+ await userDB.init('./data', 'users', userSchema, DatabaseType.Db)
381
+
382
+ // 操作数据
383
+ const user = await userDB.findByPk('123456', true) // 不存在则创建
384
+ await user.save({
385
+ level: 10,
386
+ coins: 1000,
387
+ data: { lastLogin: Date.now() }
388
+ })
389
+
390
+ // 批量查询
391
+ const users = await userDB.findAllByPks(['123456', '789012'])
392
+
393
+ // 查询所有用户
394
+ const allUsers = await userDB.findAll()
395
+ ```
396
+
397
+ **示例 2:单文件存储 - 配置文件**
398
+
399
+ ```typescript
400
+ import { Database, DatabaseType } from 'karin-plugin-mys-core/database'
401
+
402
+ // 定义配置结构(注意参数顺序)
403
+ const configSchema = {
404
+ key: Database.PkColumn('STRING'), // 主键
405
+ value: Database.Column('TEXT', ''), // 默认值 ''
406
+ type: Database.Column('STRING', 'string'), // 默认值 'string'
407
+ updatedAt: Database.Column('INTEGER', 0) // 默认值 0
408
+ }
409
+
410
+ // 初始化文件存储
411
+ const configDB = Database.get<ConfigType, DatabaseType.File>()
412
+ await configDB.init('./config', 'settings', configSchema, DatabaseType.File)
413
+
414
+ // 操作配置
415
+ const config = await configDB.findByPk('app_name', true)
416
+ await config.save({
417
+ key: 'app_name',
418
+ value: 'My App',
419
+ type: 'string',
420
+ updatedAt: Date.now()
421
+ })
422
+ // 将保存到:./config/settings/app_name.json
423
+ ```
424
+
425
+ **示例 3:目录存储 - 复杂用户数据**
426
+
427
+ ```typescript
428
+ import { Database, DatabaseType } from 'karin-plugin-mys-core/database'
429
+
430
+ // 定义复杂数据结构(注意参数顺序)
431
+ const complexSchema = {
432
+ userId: Database.PkColumn('STRING'), // 主键
433
+ profile: Database.JsonColumn('profile', {}), // JSON 列,默认值 {}
434
+ inventory: Database.JsonColumn('inventory', { items: [] }), // JSON 列,默认值 { items: [] }
435
+ achievements: Database.ArrayColumn('achievements'), // 数组列
436
+ settings: Database.JsonColumn('settings', {}) // JSON 列,默认值 {}
437
+ }
438
+
439
+ // 初始化目录存储
440
+ const complexDB = Database.get<ComplexType, DatabaseType.Dir>()
441
+ await complexDB.init('./data', 'userdata', complexSchema, DatabaseType.Dir)
442
+
443
+ // 操作数据
444
+ const userData = await complexDB.findByPk('123456', true)
445
+ await userData.save({
446
+ userId: '123456',
447
+ profile: { name: '玩家', avatar: 'url' },
448
+ inventory: { items: [], weapons: [] },
449
+ achievements: ['first_login', 'level_10'],
450
+ settings: { theme: 'dark', language: 'zh-cn' }
451
+ })
452
+ // 将保存到:./data/userdata/123456/ 目录下的多个 JSON 文件
453
+
454
+ // 删除数据
455
+ await userData.destroy() // 删除整个目录
456
+ ```
457
+
458
+ **数据库方言对比**
459
+
460
+ ```typescript
461
+ import { Dialect } from 'karin-plugin-mys-core/database'
462
+
463
+ // SQLite(默认)- 支持三种存储模式
464
+ Database.default(Dialect.Sqlite)
465
+ // ✅ DatabaseType.Db → SQLite 数据库表
466
+ // ✅ DatabaseType.File → JSON 文件存储
467
+ // ✅ DatabaseType.Dir → 目录 + JSON 文件
468
+
469
+ // PostgreSQL/MySQL/MariaDB 等 - 所有数据都使用 Db 模式
470
+ Database.default(Dialect.PostgreSQL) // 或 MySQL, MariaDB
471
+ // ✅ DatabaseType.Db → PostgreSQL 数据库表
472
+ // ✅ DatabaseType.File → PostgreSQL 数据库表
473
+ // ✅ DatabaseType.Dir → PostgreSQL 数据库表
474
+
475
+ ```
476
+
477
+ **内置表**
478
+
479
+ ```typescript
480
+ import {
481
+ MysUserInfoDB, // 用户信息表
482
+ MysAccountInfoDB, // 账号信息表
483
+ MysDeviceInfoDB // 设备信息表
484
+ } from 'karin-plugin-mys-core/database'
485
+
486
+ // 使用内置表
487
+ const userDB = await MysUserInfoDB()
488
+ const user = await userDB.findByPk(userId, true)
489
+ ```
18
490
 
19
491
  ---
20
492
 
21
- ## 🚀 快速开始
493
+ ### 米游社模块 (mys)
494
+
495
+ 米游社模块提供了完整的米游社 API 调用和用户管理功能。
496
+
497
+ #### 导入方式
498
+
499
+ ```typescript
500
+ import {
501
+ UserInfo, // 用户信息类
502
+ MysGame, // 游戏注册管理
503
+ DefineApi, // API 定义类
504
+ MysApp, // 米游社应用配置
505
+ MysHosts // 米游社主机地址
506
+ } from 'karin-plugin-mys-core/mys'
507
+ ```
508
+
509
+ #### UserInfo 类
510
+
511
+ 管理用户的米游社账号信息。
512
+
513
+ **创建用户信息**
514
+
515
+ ```typescript
516
+ // 创建用户信息实例
517
+ const userInfo = await UserInfo.create(userId, initAll?: boolean)
518
+
519
+ // 刷新 UID
520
+ const result = await UserInfo.refreshUid({
521
+ userId: 'xxx',
522
+ cookie: 'xxx',
523
+ ltuid: 'xxx',
524
+ type: MysAccountType.cn
525
+ }, UidPermission.Allow)
526
+ ```
527
+
528
+ **属性和方法**
529
+
530
+ ```typescript
531
+ // 获取 ltuid 列表
532
+ const ltuids = userInfo.ltuids
533
+
534
+ // 获取 stuid 列表
535
+ const stuids = userInfo.stuids
536
+
537
+ // 获取账号信息列表
538
+ const accounts = userInfo.LtuidInfoList
539
+
540
+ // 获取特定账号信息
541
+ const account = userInfo.getLtuidInfo(ltuid)
542
+
543
+ // 获取设备信息列表
544
+ const devices = await userInfo.getDeviceInfoList()
545
+
546
+ // 保存用户信息
547
+ await userInfo.saveUserInfo({ key: value })
548
+
549
+ // 保存米游社账号信息
550
+ await userInfo.saveMysAccountInfo(ltuid, { cookie: 'xxx' })
551
+
552
+ // 刷新用户信息
553
+ await userInfo.refresh()
554
+ ```
555
+
556
+ #### MysGame 游戏管理
557
+
558
+ 注册和管理游戏模块。
559
+
560
+ **注册游戏**
561
+
562
+ 使用 `RegisterGameBase` 类注册新游戏:
563
+
564
+ ```typescript
565
+ import { MysGame, RegisterGameBase } from 'karin-plugin-mys-core/mys'
566
+ import { GameUserInfo } from './GameUserInfo' // 你的游戏用户信息类
567
+
568
+ // 创建游戏注册对象
569
+ const MyGame = new RegisterGameBase(
570
+ 'game_key', // 游戏标识(如:gs, sr, zzz)
571
+ '原神', // 游戏名称
572
+ /^#?(原神|gs)/i, // 指令前缀匹配正则
573
+ GameUserInfo, // 游戏用户信息类
574
+ (info) => { // UID 刷新函数
575
+ return info.map(item => item.game_uid)
576
+ }
577
+ )
578
+
579
+ // 注册到 MysGame
580
+ MysGame.RegisterGame(MyGame)
581
+ ```
582
+
583
+ **游戏匹配**
584
+
585
+ ```typescript
586
+ // 通过指令前缀匹配游戏
587
+ const game = MysGame.match('#原神角色')
588
+ if (game) {
589
+ console.log('匹配到游戏:', game.name)
590
+ console.log('游戏标识:', game.game)
591
+ console.log('列键名:', game.columnKey) // 'gs-uids'
592
+ }
593
+ ```
594
+
595
+ **遍历游戏**
596
+
597
+ ```typescript
598
+ // 遍历所有已注册的游戏
599
+ await MysGame.forEachGame(async (game) => {
600
+ console.log(`游戏: ${game.name}`)
601
+ console.log(`标识: ${game.game}`)
602
+
603
+ // 如果需要中断遍历,返回 'break'
604
+ if (someCondition) {
605
+ return 'break'
606
+ }
607
+ })
608
+
609
+ // 获取已注册游戏数量
610
+ console.log(`已注册 ${MysGame.num} 个游戏`)
611
+ ```
612
+
613
+ **完整示例**
614
+
615
+ ```typescript
616
+ import {
617
+ MysGame,
618
+ RegisterGameBase,
619
+ GameUserInfoBase
620
+ } from 'karin-plugin-mys-core/mys'
621
+
622
+ // 1. 定义游戏用户信息类(继承自 GameUserInfoBase)
623
+ class GenshinUserInfo extends GameUserInfoBase<GenshinUserInfoTableType> {
624
+ static async create(userId: string) {
625
+ // 实现创建逻辑
626
+ const userInfo = new GenshinUserInfo(userId)
627
+ await userInfo.refresh()
628
+ return userInfo
629
+ }
630
+
631
+ async refresh() {
632
+ // 实现刷新逻辑
633
+ return this
634
+ }
635
+ }
636
+
637
+ // 2. 创建并注册游戏
638
+ const Genshin = new RegisterGameBase(
639
+ 'gs', // 游戏标识
640
+ '原神', // 游戏名称
641
+ /^#?(原神|gs|ys)/i, // 匹配 #原神 #gs #ys
642
+ GenshinUserInfo, // 用户信息类
643
+ (roleList) => { // UID 提取函数
644
+ return roleList
645
+ .filter(role => role.game_biz === 'hk4e_cn')
646
+ .map(role => role.game_uid)
647
+ }
648
+ )
649
+
650
+ MysGame.RegisterGame(Genshin)
651
+
652
+ // 3. 使用游戏
653
+ const game = MysGame.match('#原神角色')
654
+ if (game) {
655
+ // 创建用户信息
656
+ const userInfo = await game.UserInfo.create(userId)
657
+
658
+ // 获取主 UID
659
+ console.log('主 UID:', userInfo.main_uid)
660
+
661
+ // 获取所有绑定的 UID
662
+ console.log('绑定 UID:', userInfo.bind_uids)
663
+
664
+ // 获取 UID 信息
665
+ const uidInfo = userInfo.getUIDInfo(uid)
666
+ }
667
+ ```
668
+
669
+
670
+ #### DefineApi API 定义
671
+
672
+ 定义和调用米游社 API。
22
673
 
23
- ```bash
24
- pnpm create karin
674
+ ```typescript
675
+ // 定义 API
676
+ const myApi = new DefineApi<ResponseType, RequestType>(
677
+ (self, data) => ({
678
+ Method: 'POST',
679
+ Url: new URL('https://api.example.com/endpoint'),
680
+ Body: data,
681
+ HeaderFn: self.DefaultHeaders
682
+ })
683
+ )
684
+
685
+ // 调用 API
686
+ const response = await myApi.request({
687
+ ltuid: 'xxx',
688
+ cookie: 'xxx',
689
+ type: MysAccountType.cn,
690
+ // 其他请求参数...
691
+ })
692
+ ```
693
+
694
+ **内置 API**
695
+
696
+ ```typescript
697
+ import {
698
+ fetchQRcode, // 获取二维码
699
+ queryQRcode, // 查询二维码状态
700
+ getTokenByGameToken, // 通过游戏 Token 获取 Token
701
+ getCookieTokenBySToken, // 通过 SToken 获取 CookieToken
702
+ getUserGameRolesByCookie // 获取用户游戏角色
703
+ } from 'karin-plugin-mys-core/mys'
25
704
  ```
26
705
 
27
- - 按提示选择“ts插件开发模板”即可自动初始化项目。
28
- - 进入新建的项目目录,继续开发。
706
+ #### 配置常量
707
+
708
+ ```typescript
709
+ // 米游社应用配置
710
+ MysApp.version // { cn: '2.70.1', os: '1.5.0' }
711
+ MysApp.appId // 游戏 ID
712
+ MysApp.salt // 签名盐值
713
+
714
+ // 米游社主机地址
715
+ MysHosts.bbs // 社区 API
716
+ MysHosts.web // Web API
717
+ MysHosts.record // 记录 API
718
+ MysHosts.hk4e // 原神 API
719
+ // 更多主机地址...
720
+ ```
29
721
 
30
722
  ---
31
723
 
32
- ## 详细开发流程
724
+ ### 渲染模块 (render)
725
+
726
+ 渲染模块提供了基于 React 的模板渲染功能,可以将 React 组件渲染为图片。
727
+
728
+ #### 导入方式
729
+
730
+ ```typescript
731
+ import { ReactRender, React } from 'karin-plugin-mys-core/render'
732
+ // 或者单独导入
733
+ import React from 'karin-plugin-mys-core/render'
734
+ ```
735
+
736
+ #### ReactRender 类
737
+
738
+ 用于将 React 组件渲染为图片的核心类。
739
+
740
+ **类型定义**
741
+
742
+ ```typescript
743
+ interface RenderCfg {
744
+ /** 插件名称 package.json 的 name */
745
+ name: string
746
+ /** 插件版本 package.json 的 version */
747
+ version: string
748
+ /** 根目录绝对路径 */
749
+ pluginDir: string
750
+ /** 插件资源目录 @karinjs/karin-plugin-xxx/resources */
751
+ ResourcesDir: string
752
+ }
753
+
754
+ class ReactRender<P extends Record<string, any>, K extends string>
755
+ ```
756
+
757
+ **构造函数**
758
+
759
+ ```typescript
760
+ const render = new ReactRender<PluginOptions, TemplateName>(
761
+ {
762
+ name: 'karin-plugin-example',
763
+ version: '1.0.0',
764
+ pluginDir: '/path/to/plugin',
765
+ ResourcesDir: '/path/to/@karinjs/karin-plugin-example/resources'
766
+ },
767
+ {
768
+ // 自定义插件参数(可选)
769
+ customOption: 'value'
770
+ }
771
+ )
772
+ ```
773
+
774
+ **主要属性**
775
+
776
+ ```typescript
777
+ // 获取插件信息
778
+ render.plugin
779
+ // 返回:
780
+ // {
781
+ // name: string // 插件名称
782
+ // version: string // 插件版本
783
+ // resources: {
784
+ // default: string // 插件内部资源路径
785
+ // download: string // 插件外部资源路径
786
+ // }
787
+ // ...customOptions // 自定义选项
788
+ // }
789
+
790
+ // 获取 Karin 版本信息
791
+ render.karin
792
+ // 返回: { version: string }
793
+ ```
794
+
795
+ **template 方法**
796
+
797
+ 将 React 组件渲染为图片。
798
+
799
+ ```typescript
800
+ async template<C extends React.ComponentType<any>>(
801
+ template: K, // 模板名称
802
+ component: C, // React 组件
803
+ props: React.ComponentProps<C>, // 组件 props
804
+ options?: {
805
+ type?: 'png' | 'jpeg' | 'webp' // 图片格式,默认 'jpeg'
806
+ plugin?: Record<string, any> // 额外插件参数
807
+ render?: { // 渲染选项
808
+ name?: string // 文件名(不含后缀)
809
+ setViewport?: {
810
+ deviceScaleFactor?: number // 设备缩放比例,默认 2
811
+ }
812
+ // 更多 karin.render 选项...
813
+ }
814
+ }
815
+ ): Promise<string | null>
816
+ ```
817
+
818
+ **返回值**
819
+
820
+ - 成功:返回 `'base64://...'` 格式的 base64 图片字符串
821
+ - 失败:返回 `null`
822
+
823
+ **渲染流程**
824
+
825
+ 1. 将 React 组件渲染为 HTML 字符串
826
+ 2. 生成完整的 HTML 文档,自动引入 CSS 文件
827
+ 3. 保存 HTML 到临时目录
828
+ 4. 使用 Puppeteer 将 HTML 渲染为图片
829
+ 5. 返回 base64 格式的图片数据
830
+
831
+ **CSS 文件要求**
832
+
833
+ CSS 文件应放置在 `resources/styles/{插件名}.css` 路径下,会自动被引入到渲染的 HTML 中。
834
+
835
+ **完整示例**
836
+
837
+ ```typescript
838
+ import { ReactRender, React } from 'karin-plugin-mys-core/render'
839
+ import path from 'path'
840
+
841
+ // 定义模板名称类型
842
+ type Templates = 'userCard' | 'stats'
843
+
844
+ // 定义自定义插件选项(可选)
845
+ interface PluginOptions {
846
+ theme: string
847
+ }
848
+
849
+ // 创建渲染器实例
850
+ const render = new ReactRender<PluginOptions, Templates>(
851
+ {
852
+ name: 'karin-plugin-example',
853
+ version: '1.0.0',
854
+ pluginDir: path.resolve(__dirname, '..'),
855
+ ResourcesDir: path.resolve(__dirname, '../resources')
856
+ },
857
+ {
858
+ theme: 'light' // 自定义选项
859
+ }
860
+ )
861
+
862
+ // 定义组件的 Props 类型
863
+ interface UserCardProps {
864
+ username: string
865
+ level: number
866
+ avatar: string
867
+ }
868
+
869
+ // 创建 React 组件
870
+ const UserCard: React.FC<UserCardProps> = ({ username, level, avatar }) => {
871
+ // 访问插件信息
872
+ const plugin = render.plugin
873
+
874
+ return (
875
+ <div className="user-card">
876
+ <img src={avatar} alt="avatar" />
877
+ <h2>{username}</h2>
878
+ <p>等级: {level}</p>
879
+ <p>主题: {plugin.theme}</p>
880
+ {/* 使用插件资源 */}
881
+ <img src={`${plugin.resources.default}/image/icon.png`} />
882
+ </div>
883
+ )
884
+ }
885
+
886
+ // 渲染组件为图片
887
+ async function renderUserCard(userId: string) {
888
+ const image = await render.template(
889
+ 'userCard', // 模板名称
890
+ UserCard, // 组件
891
+ { // Props
892
+ username: '玩家',
893
+ level: 60,
894
+ avatar: 'https://...'
895
+ },
896
+ { // 选项
897
+ type: 'png', // PNG 格式
898
+ render: {
899
+ name: `user-${userId}`, // 自定义文件名
900
+ setViewport: {
901
+ deviceScaleFactor: 2 // 2倍缩放(高清)
902
+ }
903
+ }
904
+ }
905
+ )
906
+
907
+ if (image) {
908
+ console.log('渲染成功:', image)
909
+ // 返回 'base64://...'
910
+ return image
911
+ } else {
912
+ console.error('渲染失败')
913
+ return null
914
+ }
915
+ }
916
+ ```
33
917
 
34
- 1. **一键创建项目**
918
+ **在消息事件中使用**
35
919
 
36
- ```bash
37
- pnpm create karin
38
- ```
920
+ ```typescript
921
+ import { plugin } from 'node-karin'
922
+ import { ReactRender, React } from 'karin-plugin-mys-core/render'
39
923
 
40
- - 选择“ts插件开发模板”
41
- - 填写你的插件名称(会自动作为 package.json name)
42
- - 其余信息按提示填写
924
+ // 创建渲染器
925
+ const render = new ReactRender<{}, 'profile'>(
926
+ {
927
+ name: 'my-plugin',
928
+ version: '1.0.0',
929
+ pluginDir: __dirname,
930
+ ResourcesDir: path.join(__dirname, 'resources')
931
+ }
932
+ )
43
933
 
44
- 2. **安装依赖**
934
+ // 定义组件
935
+ interface ProfileProps {
936
+ nickname: string
937
+ uid: string
938
+ level: number
939
+ }
45
940
 
46
- ```bash
47
- pnpm install
48
- ```
941
+ const ProfileCard: React.FC<ProfileProps> = ({ nickname, uid, level }) => (
942
+ <div className="profile-card">
943
+ <h1>{nickname}</h1>
944
+ <p>UID: {uid}</p>
945
+ <p>等级: {level}</p>
946
+ </div>
947
+ )
49
948
 
50
- 3. **开发与调试**
949
+ // 在插件中使用
950
+ export const showProfile = plugin({
951
+ name: '查看信息',
952
+ rule: [{ reg: /^#查看信息$/i }]
953
+ }, async (e) => {
954
+ // 渲染图片
955
+ const image = await render.template(
956
+ 'profile',
957
+ ProfileCard,
958
+ {
959
+ nickname: e.sender.card || e.sender.nickname,
960
+ uid: e.userId,
961
+ level: 60
962
+ },
963
+ { type: 'jpeg' }
964
+ )
965
+
966
+ if (image) {
967
+ // 直接发送 base64 图片
968
+ await e.reply(image)
969
+ } else {
970
+ await e.reply('渲染失败')
971
+ }
972
+
973
+ return true
974
+ })
975
+ ```
51
976
 
52
- - 启动开发命令:
53
- ```bash
54
- pnpm dev
55
- ```
56
- - 编写你的插件代码于 `src/` 目录。
57
- - 编译输出:
58
- ```bash
59
- pnpm build
60
- ```
61
- - 调试编译之后的代码:
62
- ```bash
63
- pnpm app
64
- ```
65
- - 本地调试建议:
66
- - 可用 `pnpm link --global` 进行全局软链测试。
67
- - 或在 karin 根目录用 `pnpm add ../your-plugin-repo -w` 进行本地依赖测试。
977
+ **使用 Tailwind CSS**
68
978
 
69
- 4. **配置 NPM 秘钥**
979
+ 插件支持 Tailwind CSS,可以在组件中直接使用 Tailwind 类名:
70
980
 
71
- > 用于自动化发布,建议开启 2FA。
981
+ ```typescript
982
+ const Card: React.FC<{ title: string }> = ({ title }) => (
983
+ <div className="bg-white rounded-lg shadow-md p-4">
984
+ <h2 className="text-xl font-bold text-gray-800">{title}</h2>
985
+ <div className="mt-2 space-y-2">
986
+ <p className="text-sm text-gray-600">这是一段文字</p>
987
+ </div>
988
+ </div>
989
+ )
990
+ ```
72
991
 
73
- 1. 注册 [npmjs](https://www.npmjs.com/) 账号。
74
- 2. 进入 `Access Tokens`,新建 `Classic Token`,类型选 `Automation`。
75
- 3. 复制生成的 Token。
76
- 4. 打开你的 GitHub 仓库 → Settings → Secrets and variables → Actions。
77
- 5. 新建 `NPM_TOKEN`,粘贴 Token。
78
- 6. 允许 GitHub Actions 创建和批准 PR(Settings → Actions)。
992
+ 确保已引入 Tailwind:
79
993
 
80
- 5. **设置包信息**
994
+ ```css
995
+ @tailwind base;
996
+ @tailwind components;
997
+ @tailwind utilities;
81
998
 
82
- > 包名必须唯一,建议先在 [npm](https://www.npmjs.com/) 搜索确认。
999
+ /* 自定义样式 */
1000
+ .custom-class {
1001
+ /* ... */
1002
+ }
1003
+ ```
83
1004
 
84
- - 初始化时填写的插件名会自动作为 package.json 的 name,无需手动修改。
85
- - 其他如 `author`、`description`、`homepage`、`bugs.url`、`repository` 可在 package.json 中补充完善。
86
- - **CI 配置无需再手动修改 package-name,已自动同步。**
1005
+ **高级用法:复杂布局**
87
1006
 
88
- 6. **自动化发布**
1007
+ ```typescript
1008
+ // 布局组件
1009
+ const DefaultLayout: React.FC<{ children: React.ReactNode }> = ({ children }) => (
1010
+ <div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 p-4">
1011
+ <div className="max-w-4xl mx-auto">
1012
+ {children}
1013
+ </div>
1014
+ </div>
1015
+ )
89
1016
 
90
- > 推送代码后,GitHub Actions 会自动编译并发布到 npm。
1017
+ // 内容组件
1018
+ const ContentCard: React.FC<{ data: any[] }> = ({ data }) => (
1019
+ <DefaultLayout>
1020
+ <div className="bg-white rounded-2xl shadow-xl p-6">
1021
+ <h1 className="text-3xl font-bold mb-4">标题</h1>
1022
+ {data.map((item, idx) => (
1023
+ <div key={idx} className="border-b py-2">
1024
+ {item.name}
1025
+ </div>
1026
+ ))}
1027
+ </div>
1028
+ </DefaultLayout>
1029
+ )
91
1030
 
92
- - 常规开发流程:
93
- 1. `git add . && git commit -m "feat: ..." && git push`
94
- 2. 等待 CI 自动发布
95
- 3. 发布成功后可在 npm 页面看到新版本
1031
+ // 渲染
1032
+ const image = await render.template('content', ContentCard, {
1033
+ data: [{ name: '项目1' }, { name: '项目2' }]
1034
+ })
1035
+ ```
96
1036
 
97
- 7. **安装与验证**
1037
+ **注意事项**
98
1038
 
99
- - karin 根目录下安装你的插件:
100
- ```bash
101
- pnpm add your-package-name -w
102
- ```
103
- - 验证插件是否生效,可查看 karin 启动日志或相关功能。
1039
+ 1. **CSS 文件位置**:CSS 文件必须位于 `resources/styles/{插件名}.css`,否则样式无法加载
1040
+ 2. **图片格式**:`png` 支持透明背景,`jpeg` 文件更小,`webp` 是现代格式
1041
+ 3. **性能优化**:使用 `deviceScaleFactor: 2` 可获得高清图片,但会增加渲染时间
1042
+ 4. **临时文件**:HTML 临时文件保存在 `@karinjs/temp/html/{插件名}/{模板名}/` 目录
1043
+ 5. **资源路径**:在组件中使用 `render.plugin.resources.default` 访问插件资源
104
1044
 
105
1045
  ---
106
1046
 
107
- ## 💡 常见问题与建议
1047
+ ### 工具模块 (utils)
1048
+
1049
+ 工具模块提供了常用的工具函数和渲染功能。
1050
+
1051
+ #### 导入方式
108
1052
 
109
- - **Q: 发布失败怎么办?**
110
- - 检查 NPM_TOKEN 是否配置正确,权限是否足够。
111
- - 包名是否唯一,未被占用。
112
- - Actions 日志可定位具体报错。
113
- - **Q: 如何本地调试插件?**
114
- - 推荐用 `pnpm link` 或本地依赖安装。
115
- - **Q: 如何贡献代码?**
116
- - 欢迎 PR,建议先提 issue 讨论。
1053
+ ```typescript
1054
+ import { common } from 'karin-plugin-mys-core/utils'
1055
+ ```
1056
+
1057
+ #### common 工具函数
1058
+
1059
+ ```typescript
1060
+ // 生成随机字符串
1061
+ const str = common.randomString(10, 'All') // 'Lower' | 'Upper' | 'All'
1062
+
1063
+ // 生成设备 GUID
1064
+ const guid = common.getDeviceGuid()
1065
+
1066
+ // 字符串转对象
1067
+ const obj = common.StrToObj<{ key: string }>('key=value&foo=bar', '&')
1068
+
1069
+ // 对象转字符串
1070
+ const str = common.ObjToStr({ key: 'value', foo: 'bar' }, '&')
1071
+ ```
117
1072
 
118
1073
  ---
119
1074
 
120
1075
  ## 贡献与反馈
121
1076
 
122
- - 有任何建议或问题,欢迎在 [Issues](https://github.com/KarinJS/karin-plugin-template-ts/issues) 提出。
1077
+ - 有任何建议或问题,欢迎在 [Issues](https://github.com/Karin-Mys-Plugins/karin-plugin-mys-core/issues) 提出。
123
1078
  - 也可加入官方交流群交流经验。