koishi-plugin-bind-bot 2.2.8 → 2.3.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.
@@ -2,171 +2,143 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MCIDBINDRepository = void 0;
4
4
  const helpers_1 = require("../utils/helpers");
5
+ const TABLE = 'user';
6
+ const DATE_FIELDS = ['lastModified', 'usernameLastChecked', 'lastActiveTime'];
7
+ function deserialize(row) {
8
+ if (!row)
9
+ return row;
10
+ for (const field of DATE_FIELDS) {
11
+ if (row[field] && typeof row[field] === 'string') {
12
+ row[field] = new Date(row[field]);
13
+ }
14
+ }
15
+ return row;
16
+ }
17
+ function serializeDates(data) {
18
+ const out = { ...data };
19
+ for (const field of DATE_FIELDS) {
20
+ if (out[field] instanceof Date) {
21
+ out[field] = out[field].toISOString();
22
+ }
23
+ }
24
+ return out;
25
+ }
5
26
  /**
6
27
  * MCIDBIND 数据仓储类
7
- * 封装所有 MCIDBIND 表的数据库操作
28
+ * 通过 Supabase REST API 操作 user 表
8
29
  */
9
30
  class MCIDBINDRepository {
10
- ctx;
31
+ supabase;
11
32
  logger;
12
- constructor(ctx, logger) {
13
- this.ctx = ctx;
33
+ constructor(supabase, logger) {
34
+ this.supabase = supabase;
14
35
  this.logger = logger;
15
36
  }
16
- /**
17
- * 根据 QQ 号查询绑定信息
18
- * @param qqId QQ号(已规范化)
19
- * @returns 绑定信息或 null
20
- */
21
37
  async findByQQId(qqId) {
22
38
  try {
23
39
  this.logger.debug('数据库', `查询QQ(${qqId})的绑定信息`);
24
- const binds = await this.ctx.database.get('mcidbind', { qqId });
25
- return binds.length > 0 ? binds[0] : null;
40
+ const rows = await this.supabase.get(TABLE, `qqId=eq.${qqId}&limit=1`);
41
+ return rows.length > 0 ? deserialize(rows[0]) : null;
26
42
  }
27
43
  catch (error) {
28
44
  this.logger.error('数据库', `查询QQ(${qqId})绑定信息失败: ${error.message}`);
29
45
  return null;
30
46
  }
31
47
  }
32
- /**
33
- * 根据 MC 用户名查询绑定信息(精确匹配)
34
- * @param mcUsername MC用户名
35
- * @returns 绑定信息或 null
36
- */
37
48
  async findByMCUsername(mcUsername) {
38
49
  try {
39
50
  this.logger.debug('数据库', `查询MC用户名(${mcUsername})的绑定信息`);
40
- const binds = await this.ctx.database.get('mcidbind', { mcUsername });
41
- return binds.length > 0 ? binds[0] : null;
51
+ const rows = await this.supabase.get(TABLE, `mcUsername=eq.${encodeURIComponent(mcUsername)}&limit=1`);
52
+ return rows.length > 0 ? deserialize(rows[0]) : null;
42
53
  }
43
54
  catch (error) {
44
55
  this.logger.error('数据库', `查询MC用户名(${mcUsername})绑定信息失败: ${error.message}`);
45
56
  return null;
46
57
  }
47
58
  }
48
- /**
49
- * 根据 MC 用户名查询绑定信息(不区分大小写)
50
- * @param mcUsername MC用户名
51
- * @returns 绑定信息或 null
52
- */
53
59
  async findByUsernameIgnoreCase(mcUsername) {
54
60
  try {
55
61
  const normalizedInput = (0, helpers_1.normalizeUsername)(mcUsername, this.logger.getRawLogger());
56
62
  this.logger.debug('数据库', `查询MC用户名(${mcUsername} -> ${normalizedInput})的绑定信息(不区分大小写)`);
57
- // 获取所有绑定记录,然后在应用层过滤(因为 Koishi 数据库不支持不区分大小写查询)
58
- const allBinds = await this.ctx.database.get('mcidbind', {});
59
- const match = allBinds.find(bind => bind.mcUsername && (0, helpers_1.normalizeUsername)(bind.mcUsername) === normalizedInput);
60
- return match || null;
63
+ const rows = await this.supabase.get(TABLE, `mcUsername=ilike.${encodeURIComponent(mcUsername)}`);
64
+ const match = rows.find(bind => bind.mcUsername && (0, helpers_1.normalizeUsername)(bind.mcUsername) === normalizedInput);
65
+ return match ? deserialize(match) : null;
61
66
  }
62
67
  catch (error) {
63
68
  this.logger.error('数据库', `查询MC用户名(${mcUsername})绑定信息失败(不区分大小写): ${error.message}`);
64
69
  return null;
65
70
  }
66
71
  }
67
- /**
68
- * 根据 MC UUID 查询绑定信息
69
- * @param mcUuid MC UUID(可带或不带连字符)
70
- * @returns 绑定信息或 null
71
- */
72
72
  async findByUuid(mcUuid) {
73
73
  try {
74
- // 规范化 UUID(移除连字符)
75
74
  const cleanUuid = mcUuid.replace(/-/g, '');
76
75
  this.logger.debug('数据库', `查询MC UUID(${cleanUuid})的绑定信息`);
77
- // 先尝试精确匹配
78
- let binds = await this.ctx.database.get('mcidbind', { mcUuid: cleanUuid });
79
- if (binds.length > 0)
80
- return binds[0];
81
- // 尝试带连字符的格式
82
76
  const formattedUuid = `${cleanUuid.substring(0, 8)}-${cleanUuid.substring(8, 12)}-${cleanUuid.substring(12, 16)}-${cleanUuid.substring(16, 20)}-${cleanUuid.substring(20)}`;
83
- binds = await this.ctx.database.get('mcidbind', { mcUuid: formattedUuid });
84
- if (binds.length > 0)
85
- return binds[0];
86
- // 如果都没有,在应用层过滤(去除连字符后比较)
87
- const allBinds = await this.ctx.database.get('mcidbind', {});
88
- const match = allBinds.find(bind => bind.mcUuid && bind.mcUuid.replace(/-/g, '') === cleanUuid);
89
- return match || null;
77
+ // or 一次查两种格式
78
+ const rows = await this.supabase.get(TABLE, `or=(mcUuid.eq.${cleanUuid},mcUuid.eq.${formattedUuid})&limit=1`);
79
+ if (rows.length > 0)
80
+ return deserialize(rows[0]);
81
+ // 兜底:用 ilike 模糊匹配
82
+ const fallback = await this.supabase.get(TABLE, `mcUuid=ilike.*${cleanUuid}*&limit=1`);
83
+ if (fallback.length > 0)
84
+ return deserialize(fallback[0]);
85
+ return null;
90
86
  }
91
87
  catch (error) {
92
88
  this.logger.error('数据库', `查询MC UUID(${mcUuid})绑定信息失败: ${error.message}`);
93
89
  return null;
94
90
  }
95
91
  }
96
- /**
97
- * 根据 B站 UID 查询绑定信息
98
- * @param buidUid B站UID
99
- * @returns 绑定信息或 null
100
- */
101
92
  async findByBuidUid(buidUid) {
102
93
  try {
103
94
  this.logger.debug('数据库', `查询B站UID(${buidUid})的绑定信息`);
104
- const binds = await this.ctx.database.get('mcidbind', { buidUid });
105
- return binds.length > 0 ? binds[0] : null;
95
+ const rows = await this.supabase.get(TABLE, `buidUid=eq.${buidUid}&limit=1`);
96
+ return rows.length > 0 ? deserialize(rows[0]) : null;
106
97
  }
107
98
  catch (error) {
108
99
  this.logger.error('数据库', `查询B站UID(${buidUid})绑定信息失败: ${error.message}`);
109
100
  return null;
110
101
  }
111
102
  }
112
- /**
113
- * 获取所有绑定记录
114
- * @param options 查询选项
115
- * @returns 绑定记录列表
116
- */
117
103
  async findAll(options) {
118
104
  try {
119
105
  this.logger.debug('数据库', `获取所有绑定记录${options?.limit ? ` (limit: ${options.limit})` : ''}`);
120
- const records = await this.ctx.database.get('mcidbind', {}, options);
121
- return records;
106
+ const query = options?.limit ? `limit=${options.limit}` : '';
107
+ const rows = await this.supabase.get(TABLE, query);
108
+ return rows.map(deserialize);
122
109
  }
123
110
  catch (error) {
124
111
  this.logger.error('数据库', `获取所有绑定记录失败: ${error.message}`);
125
112
  return [];
126
113
  }
127
114
  }
128
- /**
129
- * 根据标签查询绑定记录
130
- * @param tag 标签名称
131
- * @returns 包含该标签的绑定记录列表
132
- */
133
115
  async findByTag(tag) {
134
116
  try {
135
117
  this.logger.debug('数据库', `查询包含标签"${tag}"的绑定记录`);
136
- const allRecords = await this.ctx.database.get('mcidbind', {});
137
- return allRecords.filter(record => record.tags && record.tags.includes(tag));
118
+ const rows = await this.supabase.get(TABLE, `tags=cs.${encodeURIComponent(JSON.stringify([tag]))}`);
119
+ return rows.map(deserialize);
138
120
  }
139
121
  catch (error) {
140
122
  this.logger.error('数据库', `查询标签"${tag}"的绑定记录失败: ${error.message}`);
141
123
  return [];
142
124
  }
143
125
  }
144
- /**
145
- * 创建新的绑定记录
146
- * @param data 绑定数据
147
- * @returns 创建的记录
148
- */
149
126
  async create(data) {
150
127
  try {
151
128
  this.logger.debug('数据库', `创建QQ(${data.qqId})的绑定记录`);
152
- const created = await this.ctx.database.create('mcidbind', data);
129
+ const created = await this.supabase.post(TABLE, serializeDates(data));
153
130
  this.logger.info('数据库', `成功创建QQ(${data.qqId})的绑定记录`, true);
154
- return created;
131
+ return deserialize(created);
155
132
  }
156
133
  catch (error) {
157
134
  this.logger.error('数据库', `创建QQ(${data.qqId})绑定记录失败: ${error.message}`);
158
135
  throw error;
159
136
  }
160
137
  }
161
- /**
162
- * 更新绑定记录(部分字段)
163
- * @param qqId QQ号
164
- * @param data 要更新的字段
165
- */
166
138
  async update(qqId, data) {
167
139
  try {
168
140
  this.logger.debug('数据库', `更新QQ(${qqId})的绑定记录`);
169
- await this.ctx.database.set('mcidbind', { qqId }, data);
141
+ await this.supabase.patch(TABLE, `qqId=eq.${qqId}`, serializeDates(data));
170
142
  this.logger.info('数据库', `成功更新QQ(${qqId})的绑定记录`, true);
171
143
  }
172
144
  catch (error) {
@@ -174,49 +146,35 @@ class MCIDBINDRepository {
174
146
  throw error;
175
147
  }
176
148
  }
177
- /**
178
- * 删除绑定记录
179
- * @param qqId QQ号
180
- * @returns 删除的记录数
181
- */
182
149
  async delete(qqId) {
183
150
  try {
184
151
  this.logger.debug('数据库', `删除QQ(${qqId})的绑定记录`);
185
- const result = await this.ctx.database.remove('mcidbind', { qqId });
186
- this.logger.info('数据库', `成功删除QQ(${qqId})的绑定记录(删除${result.removed}条)`, true);
187
- return result.removed;
152
+ const removed = await this.supabase.del(TABLE, `qqId=eq.${qqId}`);
153
+ this.logger.info('数据库', `成功删除QQ(${qqId})的绑定记录(删除${removed}条)`, true);
154
+ return removed;
188
155
  }
189
156
  catch (error) {
190
157
  this.logger.error('数据库', `删除QQ(${qqId})绑定记录失败: ${error.message}`);
191
158
  throw error;
192
159
  }
193
160
  }
194
- /**
195
- * 删除所有绑定记录
196
- * @returns 删除的记录数
197
- */
198
161
  async deleteAll() {
199
162
  try {
200
163
  this.logger.debug('数据库', '删除所有绑定记录');
201
- const result = await this.ctx.database.remove('mcidbind', {});
202
- this.logger.info('数据库', `成功删除所有绑定记录(删除${result.removed}条)`, true);
203
- return result.removed;
164
+ const removed = await this.supabase.del(TABLE, 'qqId=not.is.null');
165
+ this.logger.info('数据库', `成功删除所有绑定记录(删除${removed}条)`, true);
166
+ return removed;
204
167
  }
205
168
  catch (error) {
206
169
  this.logger.error('数据库', `删除所有绑定记录失败: ${error.message}`);
207
170
  throw error;
208
171
  }
209
172
  }
210
- /**
211
- * 批量创建绑定记录
212
- * @param records 绑定记录列表
213
- */
214
173
  async batchCreate(records) {
215
174
  try {
216
175
  this.logger.debug('数据库', `批量创建${records.length}条绑定记录`);
217
- for (const record of records) {
218
- await this.ctx.database.create('mcidbind', record);
219
- }
176
+ const serialized = records.map(r => serializeDates(r));
177
+ await this.supabase.postMany(TABLE, serialized);
220
178
  this.logger.info('数据库', `成功批量创建${records.length}条绑定记录`, true);
221
179
  }
222
180
  catch (error) {
@@ -224,11 +182,6 @@ class MCIDBINDRepository {
224
182
  throw error;
225
183
  }
226
184
  }
227
- /**
228
- * 为用户添加标签
229
- * @param qqId QQ号
230
- * @param tag 标签名称
231
- */
232
185
  async addTag(qqId, tag) {
233
186
  try {
234
187
  const bind = await this.findByQQId(qqId);
@@ -247,11 +200,6 @@ class MCIDBINDRepository {
247
200
  throw error;
248
201
  }
249
202
  }
250
- /**
251
- * 为用户移除标签
252
- * @param qqId QQ号
253
- * @param tag 标签名称
254
- */
255
203
  async removeTag(qqId, tag) {
256
204
  try {
257
205
  const bind = await this.findByQQId(qqId);
@@ -271,11 +219,6 @@ class MCIDBINDRepository {
271
219
  throw error;
272
220
  }
273
221
  }
274
- /**
275
- * 为用户添加白名单服务器
276
- * @param qqId QQ号
277
- * @param serverId 服务器ID
278
- */
279
222
  async addWhitelist(qqId, serverId) {
280
223
  try {
281
224
  const bind = await this.findByQQId(qqId);
@@ -294,11 +237,6 @@ class MCIDBINDRepository {
294
237
  throw error;
295
238
  }
296
239
  }
297
- /**
298
- * 为用户移除白名单服务器
299
- * @param qqId QQ号
300
- * @param serverId 服务器ID
301
- */
302
240
  async removeWhitelist(qqId, serverId) {
303
241
  try {
304
242
  const bind = await this.findByQQId(qqId);
@@ -318,15 +256,11 @@ class MCIDBINDRepository {
318
256
  throw error;
319
257
  }
320
258
  }
321
- /**
322
- * 获取所有管理员
323
- * @returns 管理员列表
324
- */
325
259
  async findAllAdmins() {
326
260
  try {
327
261
  this.logger.debug('数据库', '获取所有管理员');
328
- const allRecords = await this.ctx.database.get('mcidbind', {});
329
- return allRecords.filter(record => record.isAdmin);
262
+ const rows = await this.supabase.get(TABLE, 'isAdmin=eq.true');
263
+ return rows.map(deserialize);
330
264
  }
331
265
  catch (error) {
332
266
  this.logger.error('数据库', `获取所有管理员失败: ${error.message}`);
@@ -274,9 +274,7 @@ class DatabaseService {
274
274
  buidUid: buidUser.uid.toString(), // 转换为字符串存储
275
275
  buidUsername: buidUser.username,
276
276
  guardLevel: buidUser.guard_level || 0,
277
- guardLevelText: buidUser.guard_level_text || '',
278
277
  maxGuardLevel: buidUser.max_guard_level || 0,
279
- maxGuardLevelText: buidUser.max_guard_level_text || '',
280
278
  medalName: buidUser.medal?.name || '',
281
279
  medalLevel: buidUser.medal?.level || 0,
282
280
  wealthMedalLevel: buidUser.wealthMedalLevel || 0,
@@ -334,9 +332,7 @@ class DatabaseService {
334
332
  const updateData = {
335
333
  buidUsername: buidUser.username,
336
334
  guardLevel: buidUser.guard_level || 0,
337
- guardLevelText: buidUser.guard_level_text || '',
338
335
  maxGuardLevel: buidUser.max_guard_level || 0,
339
- maxGuardLevelText: buidUser.max_guard_level_text || '',
340
336
  medalName: buidUser.medal?.name || '',
341
337
  medalLevel: buidUser.medal?.level || 0,
342
338
  wealthMedalLevel: buidUser.wealthMedalLevel || 0,
@@ -386,9 +382,7 @@ class DatabaseService {
386
382
  buidUid: null,
387
383
  buidUsername: null,
388
384
  guardLevel: 0,
389
- guardLevelText: '',
390
385
  maxGuardLevel: 0,
391
- maxGuardLevelText: '',
392
386
  medalName: '',
393
387
  medalLevel: 0,
394
388
  wealthMedalLevel: 0,
@@ -53,6 +53,10 @@ export interface Config {
53
53
  forceBindTargetRoomId: number;
54
54
  /** 强制绑定目标粉丝牌名称 */
55
55
  forceBindTargetMedalName: string;
56
+ /** Supabase项目URL */
57
+ supabaseUrl: string;
58
+ /** Supabase API Key */
59
+ supabaseKey: string;
56
60
  /** 入群申请审批功能配置 */
57
61
  groupRequestReview?: GroupRequestReviewConfig;
58
62
  }
@@ -134,9 +138,9 @@ export interface GroupRequestReviewConfig {
134
138
  targetGroupId: string;
135
139
  /** 管理员审批操作所在的群ID(播报群) */
136
140
  reviewGroupId: string;
137
- /** 批准并自动绑定的表情ID(默认:389 /太赞了) */
141
+ /** 批准并自动绑定的表情ID(默认:76 /赞) */
138
142
  approveAutoBindEmoji: string;
139
- /** 批准并交互式绑定的表情ID(默认:427 /偷感) */
143
+ /** 批准并交互式绑定的表情ID(默认:124 /OK) */
140
144
  approveInteractiveBindEmoji: string;
141
145
  /** 拒绝申请的表情ID(默认:123 /NO) */
142
146
  rejectEmoji: string;
@@ -24,9 +24,7 @@
24
24
  * buidUid: '87654321',
25
25
  * buidUsername: 'B站用户名',
26
26
  * guardLevel: 3,
27
- * guardLevelText: '舰长',
28
27
  * maxGuardLevel: 3,
29
- * maxGuardLevelText: '舰长',
30
28
  * medalName: '粉丝牌',
31
29
  * medalLevel: 20,
32
30
  * wealthMedalLevel: 15,
@@ -60,12 +58,8 @@ export interface MCIDBIND {
60
58
  buidUsername: string | null;
61
59
  /** 当前舰长等级 (0=无, 1=总督, 2=提督, 3=舰长) */
62
60
  guardLevel: number;
63
- /** 当前舰长等级文本 (例: '舰长', '提督', '总督') */
64
- guardLevelText: string;
65
61
  /** 历史最高舰长等级 */
66
62
  maxGuardLevel: number;
67
- /** 历史最高舰长等级文本 */
68
- maxGuardLevelText: string;
69
63
  /** 粉丝牌名称 */
70
64
  medalName: string;
71
65
  /** 粉丝牌等级 */
@@ -54,9 +54,7 @@ export interface UpdateMcBindData {
54
54
  * buidUid: '87654321',
55
55
  * buidUsername: 'B站用户名',
56
56
  * guardLevel: 3,
57
- * guardLevelText: '舰长',
58
57
  * maxGuardLevel: 3,
59
- * maxGuardLevelText: '舰长',
60
58
  * medalName: '粉丝牌',
61
59
  * medalLevel: 20,
62
60
  * wealthMedalLevel: 15,
@@ -72,12 +70,8 @@ export interface UpdateBuidBindData {
72
70
  buidUsername?: string | null;
73
71
  /** 当前舰长等级 */
74
72
  guardLevel?: number;
75
- /** 当前舰长等级文本 */
76
- guardLevelText?: string;
77
73
  /** 历史最高舰长等级 */
78
74
  maxGuardLevel?: number;
79
- /** 历史最高舰长等级文本 */
80
- maxGuardLevelText?: string;
81
75
  /** 粉丝牌名称 */
82
76
  medalName?: string;
83
77
  /** 粉丝牌等级 */
@@ -104,7 +98,6 @@ export interface UpdateBuidBindData {
104
98
  * {
105
99
  * buidUsername: '新用户名',
106
100
  * guardLevel: 3,
107
- * guardLevelText: '舰长',
108
101
  * medalLevel: 21
109
102
  * }
110
103
  * ```
@@ -114,12 +107,8 @@ export interface UpdateBuidInfoData {
114
107
  buidUsername?: string;
115
108
  /** 当前舰长等级 */
116
109
  guardLevel?: number;
117
- /** 当前舰长等级文本 */
118
- guardLevelText?: string;
119
110
  /** 历史最高舰长等级 */
120
111
  maxGuardLevel?: number;
121
- /** 历史最高舰长等级文本 */
122
- maxGuardLevelText?: string;
123
112
  /** 粉丝牌名称 */
124
113
  medalName?: string;
125
114
  /** 粉丝牌等级 */
@@ -79,6 +79,20 @@ export declare class BindStatus {
79
79
  * ```
80
80
  */
81
81
  static hasCompletedAllBinds(bind: MCIDBIND | null | undefined): boolean;
82
+ /**
83
+ * 检查是否只绑定了MC(未绑定B站)
84
+ *
85
+ * @param bind - 绑定记录(可为 null 或 undefined)
86
+ * @returns true 表示已绑定MC但未绑定B站
87
+ */
88
+ static hasOnlyMcBind(bind: MCIDBIND | null | undefined): boolean;
89
+ /**
90
+ * 检查是否只绑定了B站(未绑定MC)
91
+ *
92
+ * @param bind - 绑定记录(可为 null 或 undefined)
93
+ * @returns true 表示已绑定B站但未绑定MC
94
+ */
95
+ static hasOnlyBuidBind(bind: MCIDBIND | null | undefined): boolean;
82
96
  /**
83
97
  * 获取绑定状态摘要信息
84
98
  *
@@ -111,6 +111,28 @@ class BindStatus {
111
111
  static hasCompletedAllBinds(bind) {
112
112
  return this.hasValidMcBind(bind) && this.hasValidBuidBind(bind);
113
113
  }
114
+ /**
115
+ * 检查是否只绑定了MC(未绑定B站)
116
+ *
117
+ * @param bind - 绑定记录(可为 null 或 undefined)
118
+ * @returns true 表示已绑定MC但未绑定B站
119
+ */
120
+ static hasOnlyMcBind(bind) {
121
+ return this.hasValidMcBind(bind) && !this.hasValidBuidBind(bind);
122
+ }
123
+ /**
124
+ * 检查是否只绑定了B站(未绑定MC)
125
+ *
126
+ * @param bind - 绑定记录(可为 null 或 undefined)
127
+ * @returns true 表示已绑定B站但未绑定MC
128
+ */
129
+ static hasOnlyBuidBind(bind) {
130
+ return (bind !== null &&
131
+ bind !== undefined &&
132
+ !!bind.buidUid &&
133
+ !!bind.buidUsername &&
134
+ !this.hasValidMcBind(bind));
135
+ }
114
136
  /**
115
137
  * 获取绑定状态摘要信息
116
138
  *
@@ -89,15 +89,7 @@ export declare function levenshteinDistance(str1: string, str2: string): number;
89
89
  * @returns 相似度值(0到1之间,1表示完全相同)
90
90
  */
91
91
  export declare function calculateSimilarity(str1: string, str2: string): number;
92
- /**
93
- * 规范化 Minecraft 用户名(统一小写,用于存储和比较)
94
- * Minecraft 用户名不区分大小写,但 Mojang 返回的是规范大小写
95
- * 为避免 "Notch" 和 "notch" 被视为不同用户,统一转小写存储
96
- *
97
- * @param username MC 用户名
98
- * @param logger Koishi Logger实例(用于日志)
99
- * @returns 规范化后的用户名(小写)
100
- */
92
+ export declare function getGuardLevelText(level: number): string;
101
93
  export declare function normalizeUsername(username: string, logger?: Logger): string;
102
94
  /**
103
95
  * 比较两个 Minecraft 用户名是否相同(不区分大小写)
@@ -11,6 +11,7 @@ exports.escapeRegExp = escapeRegExp;
11
11
  exports.cleanUserInput = cleanUserInput;
12
12
  exports.levenshteinDistance = levenshteinDistance;
13
13
  exports.calculateSimilarity = calculateSimilarity;
14
+ exports.getGuardLevelText = getGuardLevelText;
14
15
  exports.normalizeUsername = normalizeUsername;
15
16
  exports.isSameUsername = isSameUsername;
16
17
  exports.extractBuidUsernameFromNickname = extractBuidUsernameFromNickname;
@@ -369,6 +370,10 @@ function calculateSimilarity(str1, str2) {
369
370
  * @param logger Koishi Logger实例(用于日志)
370
371
  * @returns 规范化后的用户名(小写)
371
372
  */
373
+ const GUARD_LEVEL_TEXT = { 1: '总督', 2: '提督', 3: '舰长' };
374
+ function getGuardLevelText(level) {
375
+ return GUARD_LEVEL_TEXT[level] || '';
376
+ }
372
377
  function normalizeUsername(username, logger) {
373
378
  if (!username) {
374
379
  logger?.warn('[用户名规范化] 收到空用户名');
@@ -0,0 +1,14 @@
1
+ export interface SupabaseConfig {
2
+ url: string;
3
+ key: string;
4
+ }
5
+ export declare class SupabaseClient {
6
+ private config;
7
+ private client;
8
+ constructor(config: SupabaseConfig);
9
+ get<T>(table: string, query?: string): Promise<T[]>;
10
+ post<T>(table: string, body: object | object[]): Promise<T>;
11
+ postMany<T>(table: string, body: object[]): Promise<T[]>;
12
+ patch(table: string, query: string, body: object): Promise<void>;
13
+ del(table: string, query: string): Promise<number>;
14
+ }
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.SupabaseClient = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ class SupabaseClient {
9
+ config;
10
+ client;
11
+ constructor(config) {
12
+ this.config = config;
13
+ this.client = axios_1.default.create({
14
+ baseURL: `${config.url}/rest/v1`,
15
+ headers: {
16
+ apikey: config.key,
17
+ Authorization: `Bearer ${config.key}`,
18
+ 'Content-Type': 'application/json',
19
+ Prefer: 'return=representation',
20
+ },
21
+ });
22
+ }
23
+ async get(table, query = '') {
24
+ const url = query ? `/${table}?${query}` : `/${table}`;
25
+ const { data } = await this.client.get(url);
26
+ return data;
27
+ }
28
+ async post(table, body) {
29
+ const { data } = await this.client.post(`/${table}`, body);
30
+ return Array.isArray(data) ? data[0] : data;
31
+ }
32
+ async postMany(table, body) {
33
+ const { data } = await this.client.post(`/${table}`, body);
34
+ return data;
35
+ }
36
+ async patch(table, query, body) {
37
+ await this.client.patch(`/${table}?${query}`, body);
38
+ }
39
+ async del(table, query) {
40
+ const { data } = await this.client.delete(`/${table}?${query}`);
41
+ return Array.isArray(data) ? data.length : 0;
42
+ }
43
+ }
44
+ exports.SupabaseClient = SupabaseClient;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-bind-bot",
3
3
  "description": "[WittF自用] BIND-BOT - 账号绑定管理机器人,支持Minecraft账号和B站账号绑定与管理。",
4
- "version": "2.2.8",
4
+ "version": "2.3.0",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [