befly 3.0.0 → 3.1.1

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 (60) hide show
  1. package/checks/conflict.ts +35 -114
  2. package/checks/table.ts +31 -63
  3. package/config/env.ts +3 -3
  4. package/config/fields.ts +55 -0
  5. package/config/regexAliases.ts +51 -0
  6. package/config/reserved.ts +1 -1
  7. package/main.ts +17 -71
  8. package/package.json +7 -28
  9. package/plugins/db.ts +11 -10
  10. package/plugins/redis.ts +5 -9
  11. package/scripts/syncDb/apply.ts +3 -3
  12. package/scripts/syncDb/constants.ts +2 -1
  13. package/scripts/syncDb/ddl.ts +15 -8
  14. package/scripts/syncDb/helpers.ts +3 -2
  15. package/scripts/syncDb/index.ts +23 -35
  16. package/scripts/syncDb/state.ts +8 -6
  17. package/scripts/syncDb/table.ts +32 -22
  18. package/scripts/syncDb/tableCreate.ts +9 -3
  19. package/scripts/syncDb/tests/constants.test.ts +2 -1
  20. package/scripts/syncDb.ts +10 -9
  21. package/types/addon.d.ts +53 -0
  22. package/types/api.d.ts +17 -14
  23. package/types/befly.d.ts +2 -6
  24. package/types/context.d.ts +7 -0
  25. package/types/database.d.ts +9 -14
  26. package/types/index.d.ts +442 -8
  27. package/types/index.ts +35 -56
  28. package/types/redis.d.ts +2 -0
  29. package/types/validator.d.ts +0 -2
  30. package/types/validator.ts +43 -0
  31. package/utils/colors.ts +117 -37
  32. package/utils/database.ts +348 -0
  33. package/utils/dbHelper.ts +687 -116
  34. package/utils/helper.ts +812 -0
  35. package/utils/index.ts +10 -23
  36. package/utils/logger.ts +78 -171
  37. package/utils/redisHelper.ts +135 -152
  38. package/{types/context.ts → utils/requestContext.ts} +3 -3
  39. package/utils/sqlBuilder.ts +142 -165
  40. package/utils/validate.ts +51 -9
  41. package/apis/health/info.ts +0 -64
  42. package/apis/tool/tokenCheck.ts +0 -51
  43. package/bin/befly.ts +0 -202
  44. package/bunfig.toml +0 -3
  45. package/plugins/tool.ts +0 -34
  46. package/scripts/syncDev.ts +0 -112
  47. package/system.ts +0 -149
  48. package/tables/_common.json +0 -21
  49. package/tables/admin.json +0 -10
  50. package/utils/addonHelper.ts +0 -60
  51. package/utils/api.ts +0 -23
  52. package/utils/datetime.ts +0 -51
  53. package/utils/errorHandler.ts +0 -68
  54. package/utils/objectHelper.ts +0 -68
  55. package/utils/pluginHelper.ts +0 -62
  56. package/utils/response.ts +0 -38
  57. package/utils/sqlHelper.ts +0 -447
  58. package/utils/tableHelper.ts +0 -167
  59. package/utils/tool.ts +0 -230
  60. package/utils/typeHelper.ts +0 -101
@@ -6,114 +6,30 @@
6
6
  import { RedisClient } from 'bun';
7
7
  import { Env } from '../config/env.js';
8
8
  import { Logger } from './logger.js';
9
+ import { getRedis } from './database.js';
9
10
 
10
11
  /**
11
12
  * Redis 键前缀
12
13
  */
13
14
  const prefix = Env.REDIS_KEY_PREFIX ? `${Env.REDIS_KEY_PREFIX}:` : '';
14
15
 
15
- /**
16
- * 构建 Redis 连接 URL
17
- * @returns Redis 连接 URL
18
- */
19
- function buildRedisUrl(): string {
20
- const { REDIS_HOST, REDIS_PORT, REDIS_USERNAME, REDIS_PASSWORD, REDIS_DB } = Env;
21
-
22
- // 构建认证部分
23
- let auth = '';
24
- if (REDIS_USERNAME && REDIS_PASSWORD) {
25
- auth = `${REDIS_USERNAME}:${REDIS_PASSWORD}@`;
26
- } else if (REDIS_PASSWORD) {
27
- auth = `:${REDIS_PASSWORD}@`;
28
- }
29
-
30
- // 构建完整 URL
31
- const url = `redis://${auth}${REDIS_HOST}:${REDIS_PORT}/${REDIS_DB}`;
32
-
33
- return url;
34
- }
35
-
36
- /**
37
- * Redis 客户端实例
38
- */
39
- let redisClient: RedisClient | null = null;
40
-
41
- /**
42
- * 初始化 Redis 客户端
43
- * @returns Redis 客户端实例
44
- * @throws 如果连接失败
45
- */
46
- export const initRedisClient = async (): Promise<RedisClient> => {
47
- if (!redisClient) {
48
- try {
49
- const url = buildRedisUrl();
50
- redisClient = new RedisClient(url, {
51
- // 连接超时(毫秒)
52
- connectionTimeout: 10000,
53
- // 空闲超时设为 0,表示永不超时
54
- idleTimeout: 0,
55
- // 断开连接时自动重连
56
- autoReconnect: true,
57
- // 最大重连次数,0 表示无限重连
58
- maxRetries: 0,
59
- // 断开连接时缓存命令
60
- enableOfflineQueue: true,
61
- // 自动管道化命令
62
- enableAutoPipelining: true
63
- });
64
-
65
- // 测试连接是否成功
66
- await redisClient.ping();
67
- Logger.info('Redis 连接成功');
68
- } catch (error: any) {
69
- redisClient = null;
70
- Logger.error({
71
- msg: 'Redis 连接失败',
72
- message: error.message,
73
- code: error.code,
74
- stack: error.stack
75
- });
76
- throw new Error(`Redis 连接失败: ${error.message}`);
77
- }
78
- }
79
- return redisClient;
80
- };
81
-
82
16
  /**
83
17
  * 获取 Redis 客户端
84
18
  * @returns Redis 客户端实例
85
- * @throws 如果连接失败
19
+ * @throws 如果客户端未初始化
86
20
  */
87
- export const getRedisClient = async (): Promise<RedisClient> => {
88
- if (!redisClient) {
89
- return await initRedisClient();
21
+ function getClient(): RedisClient {
22
+ const client = getRedis();
23
+ if (!client) {
24
+ throw new Error('Redis 客户端未初始化,请先调用 initDatabase() 或 initRedisOnly()');
90
25
  }
91
- return redisClient;
92
- };
93
-
94
- /**
95
- * 关闭 Redis 连接
96
- */
97
- export const closeRedisClient = (): void => {
98
- if (redisClient) {
99
- redisClient.close();
100
- redisClient = null;
101
- }
102
- };
26
+ return client;
27
+ }
103
28
 
104
29
  /**
105
30
  * Redis 助手对象
106
31
  */
107
32
  export const RedisHelper = {
108
- /**
109
- * 获取 Redis 客户端实例
110
- * @returns Redis 客户端
111
- * @throws 如果连接失败
112
- */
113
- async getRedisClient(): Promise<RedisClient> {
114
- return await getRedisClient();
115
- },
116
-
117
33
  /**
118
34
  * 设置对象到 Redis
119
35
  * @param key - 键名
@@ -123,7 +39,7 @@ export const RedisHelper = {
123
39
  */
124
40
  async setObject<T = any>(key: string, obj: T, ttl: number | null = null): Promise<string | null> {
125
41
  try {
126
- const client = await getRedisClient();
42
+ const client = getClient();
127
43
  const data = JSON.stringify(obj);
128
44
  const pkey = `${prefix}${key}`;
129
45
 
@@ -132,11 +48,7 @@ export const RedisHelper = {
132
48
  }
133
49
  return await client.set(pkey, data);
134
50
  } catch (error: any) {
135
- Logger.error({
136
- msg: 'Redis setObject 错误',
137
- message: error.message,
138
- stack: error.stack
139
- });
51
+ Logger.error('Redis setObject 错误', error);
140
52
  return null;
141
53
  }
142
54
  },
@@ -148,16 +60,12 @@ export const RedisHelper = {
148
60
  */
149
61
  async getObject<T = any>(key: string): Promise<T | null> {
150
62
  try {
151
- const client = await getRedisClient();
63
+ const client = getClient();
152
64
  const pkey = `${prefix}${key}`;
153
65
  const data = await client.get(pkey);
154
66
  return data ? JSON.parse(data) : null;
155
67
  } catch (error: any) {
156
- Logger.error({
157
- msg: 'Redis getObject 错误',
158
- message: error.message,
159
- stack: error.stack
160
- });
68
+ Logger.error('Redis getObject 错误', error);
161
69
  return null;
162
70
  }
163
71
  },
@@ -168,56 +76,53 @@ export const RedisHelper = {
168
76
  */
169
77
  async delObject(key: string): Promise<void> {
170
78
  try {
171
- const client = await getRedisClient();
79
+ const client = getClient();
172
80
  const pkey = `${prefix}${key}`;
173
81
  await client.del(pkey);
174
82
  } catch (error: any) {
175
- Logger.error({
176
- msg: 'Redis delObject 错误',
177
- message: error.message,
178
- stack: error.stack
179
- });
83
+ Logger.error('Redis delObject 错误', error);
180
84
  }
181
85
  },
182
86
 
183
87
  /**
184
88
  * 生成基于时间的唯一 ID
185
- * 格式: Date.now()(13位) + 3位自增 = 16位纯数字
186
- * 容量: 1000/毫秒 = 1,000,000/秒
187
- * @returns 唯一 ID (16位纯数字)
89
+ * 格式: 秒级时间戳(10位) + 4位自增 = 14位纯数字
90
+ * 容量: 10000/秒 = 864,000,000/天
91
+ * 范围: 2286年9月
92
+ * @returns 唯一 ID (14位纯数字)
188
93
  */
189
94
  async genTimeID(): Promise<number> {
190
- const client = await getRedisClient();
191
- const timestamp = Date.now();
95
+ const client = getClient();
96
+ const timestamp = Math.floor(Date.now() / 1000); // 秒级时间戳
192
97
  const key = `${prefix}time_id_counter:${timestamp}`;
193
98
 
194
99
  const counter = await client.incr(key);
195
100
  await client.expire(key, 1);
196
101
 
197
- const counterSuffix = (counter % 1000).toString().padStart(3, '0');
102
+ const counterSuffix = (counter % 10000).toString().padStart(4, '0');
198
103
 
199
104
  return Number(`${timestamp}${counterSuffix}`);
200
105
  },
201
106
 
202
107
  /**
203
108
  * 批量生成基于时间的唯一 ID
204
- * 格式: Date.now()(13位) + 3位自增 = 16位纯数字
109
+ * 格式: 秒级时间戳(10位) + 4位自增 = 14位纯数字
205
110
  * @param count - 需要生成的 ID 数量
206
- * @returns ID 数组 (16位纯数字)
111
+ * @returns ID 数组 (14位纯数字)
207
112
  */
208
113
  async genTimeIDBatch(count: number): Promise<number[]> {
209
114
  if (count <= 0) {
210
115
  return [];
211
116
  }
212
117
 
213
- // 限制单次批量生成数量
118
+ // 限制单次批量生成数量(每秒最多10000个)
214
119
  const MAX_BATCH_SIZE = 10000;
215
120
  if (count > MAX_BATCH_SIZE) {
216
121
  throw new Error(`批量大小 ${count} 超过最大限制 ${MAX_BATCH_SIZE}`);
217
122
  }
218
123
 
219
- const client = await getRedisClient();
220
- const timestamp = Date.now();
124
+ const client = getClient();
125
+ const timestamp = Math.floor(Date.now() / 1000); // 秒级时间戳
221
126
  const key = `${prefix}time_id_counter:${timestamp}`;
222
127
 
223
128
  // 使用 INCRBY 一次性获取 N 个连续计数
@@ -228,7 +133,7 @@ export const RedisHelper = {
228
133
  const ids: number[] = [];
229
134
  for (let i = 0; i < count; i++) {
230
135
  const counter = startCounter - count + i + 1; // 计算每个 ID 的计数值
231
- const counterSuffix = (counter % 1000).toString().padStart(3, '0');
136
+ const counterSuffix = (counter % 10000).toString().padStart(4, '0');
232
137
  ids.push(Number(`${timestamp}${counterSuffix}`));
233
138
  }
234
139
 
@@ -243,18 +148,14 @@ export const RedisHelper = {
243
148
  */
244
149
  async setString(key: string, value: string, ttl: number | null = null): Promise<string | null> {
245
150
  try {
246
- const client = await getRedisClient();
151
+ const client = getClient();
247
152
  const pkey = `${prefix}${key}`;
248
153
  if (ttl) {
249
154
  return await client.setEx(pkey, ttl, value);
250
155
  }
251
156
  return await client.set(pkey, value);
252
157
  } catch (error: any) {
253
- Logger.error({
254
- msg: 'Redis setString 错误',
255
- message: error.message,
256
- stack: error.stack
257
- });
158
+ Logger.error('Redis setString 错误', error);
258
159
  return null;
259
160
  }
260
161
  },
@@ -265,15 +166,11 @@ export const RedisHelper = {
265
166
  */
266
167
  async getString(key: string): Promise<string | null> {
267
168
  try {
268
- const client = await getRedisClient();
169
+ const client = getClient();
269
170
  const pkey = `${prefix}${key}`;
270
171
  return await client.get(pkey);
271
172
  } catch (error: any) {
272
- Logger.error({
273
- msg: 'Redis getString 错误',
274
- message: error.message,
275
- stack: error.stack
276
- });
173
+ Logger.error('Redis getString 错误', error);
277
174
  return null;
278
175
  }
279
176
  },
@@ -284,15 +181,11 @@ export const RedisHelper = {
284
181
  */
285
182
  async exists(key: string): Promise<number> {
286
183
  try {
287
- const client = await getRedisClient();
184
+ const client = getClient();
288
185
  const pkey = `${prefix}${key}`;
289
186
  return await client.exists(pkey);
290
187
  } catch (error: any) {
291
- Logger.error({
292
- msg: 'Redis exists 错误',
293
- message: error.message,
294
- stack: error.stack
295
- });
188
+ Logger.error('Redis exists 错误', error);
296
189
  return 0;
297
190
  }
298
191
  },
@@ -304,15 +197,11 @@ export const RedisHelper = {
304
197
  */
305
198
  async expire(key: string, seconds: number): Promise<number> {
306
199
  try {
307
- const client = await getRedisClient();
200
+ const client = getClient();
308
201
  const pkey = `${prefix}${key}`;
309
202
  return await client.expire(pkey, seconds);
310
203
  } catch (error: any) {
311
- Logger.error({
312
- msg: 'Redis expire 错误',
313
- message: error.message,
314
- stack: error.stack
315
- });
204
+ Logger.error('Redis expire 错误', error);
316
205
  return 0;
317
206
  }
318
207
  },
@@ -323,16 +212,110 @@ export const RedisHelper = {
323
212
  */
324
213
  async ttl(key: string): Promise<number> {
325
214
  try {
326
- const client = await getRedisClient();
215
+ const client = getClient();
327
216
  const pkey = `${prefix}${key}`;
328
217
  return await client.ttl(pkey);
329
218
  } catch (error: any) {
330
- Logger.error({
331
- msg: 'Redis ttl 错误',
332
- message: error.message,
333
- stack: error.stack
334
- });
219
+ Logger.error('Redis ttl 错误', error);
335
220
  return -1;
336
221
  }
222
+ },
223
+
224
+ /**
225
+ * 向 Set 中添加一个或多个成员
226
+ * @param key - 键名
227
+ * @param members - 成员数组
228
+ * @returns 成功添加的成员数量
229
+ */
230
+ async sadd(key: string, members: string[]): Promise<number> {
231
+ try {
232
+ if (members.length === 0) return 0;
233
+
234
+ const client = getClient();
235
+ const pkey = `${prefix}${key}`;
236
+ return await client.sadd(pkey, ...members);
237
+ } catch (error: any) {
238
+ Logger.error('Redis sadd 错误', error);
239
+ return 0;
240
+ }
241
+ },
242
+
243
+ /**
244
+ * 判断成员是否在 Set 中
245
+ * @param key - 键名
246
+ * @param member - 成员
247
+ * @returns 1 表示存在,0 表示不存在
248
+ */
249
+ async sismember(key: string, member: string): Promise<number> {
250
+ try {
251
+ const client = getClient();
252
+ const pkey = `${prefix}${key}`;
253
+ return await client.sismember(pkey, member);
254
+ } catch (error: any) {
255
+ Logger.error('Redis sismember 错误', error);
256
+ return 0;
257
+ }
258
+ },
259
+
260
+ /**
261
+ * 获取 Set 的成员数量
262
+ * @param key - 键名
263
+ * @returns 成员数量
264
+ */
265
+ async scard(key: string): Promise<number> {
266
+ try {
267
+ const client = getClient();
268
+ const pkey = `${prefix}${key}`;
269
+ return await client.scard(pkey);
270
+ } catch (error: any) {
271
+ Logger.error('Redis scard 错误', error);
272
+ return 0;
273
+ }
274
+ },
275
+
276
+ /**
277
+ * 获取 Set 的所有成员
278
+ * @param key - 键名
279
+ * @returns 成员数组
280
+ */
281
+ async smembers(key: string): Promise<string[]> {
282
+ try {
283
+ const client = getClient();
284
+ const pkey = `${prefix}${key}`;
285
+ return await client.smembers(pkey);
286
+ } catch (error: any) {
287
+ Logger.error('Redis smembers 错误', error);
288
+ return [];
289
+ }
290
+ },
291
+
292
+ /**
293
+ * 删除键
294
+ * @param key - 键名
295
+ * @returns 删除的键数量
296
+ */
297
+ async del(key: string): Promise<number> {
298
+ try {
299
+ const client = getClient();
300
+ const pkey = `${prefix}${key}`;
301
+ return await client.del(pkey);
302
+ } catch (error: any) {
303
+ Logger.error('Redis del 错误', error);
304
+ return 0;
305
+ }
306
+ },
307
+
308
+ /**
309
+ * 测试 Redis 连接
310
+ * @returns ping 响应结果
311
+ */
312
+ async ping(): Promise<string> {
313
+ try {
314
+ const client = getClient();
315
+ return await client.ping();
316
+ } catch (error: any) {
317
+ Logger.error('Redis ping 错误', error);
318
+ throw error;
319
+ }
337
320
  }
338
321
  };
@@ -106,14 +106,14 @@ export class RequestContext {
106
106
  * @param key - 参数键名
107
107
  */
108
108
  has(key: string): boolean {
109
- return key in this.params;
109
+ return key in this.body;
110
110
  }
111
111
 
112
112
  /**
113
113
  * 获取所有参数
114
114
  */
115
115
  all(): Record<string, any> {
116
- return { ...this.params };
116
+ return { ...this.body };
117
117
  }
118
118
 
119
119
  /**
@@ -162,6 +162,6 @@ export class RequestContext {
162
162
  * 获取用户角色
163
163
  */
164
164
  getUserRole(): string | null {
165
- return this.user.role || this.user.role_type || null;
165
+ return this.user.role || this.user.roleType || null;
166
166
  }
167
167
  }