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
package/bin/befly.ts DELETED
@@ -1,202 +0,0 @@
1
- #!/usr/bin/env -S bun run
2
- /**
3
- * Befly CLI - TypeScript 版本
4
- * 列出并执行 core/scripts 与 tpl/scripts 下的脚本
5
- */
6
-
7
- import path from 'node:path';
8
- import { Glob } from 'bun';
9
- import { __dirscript as coreScriptsDir, getProjectDir } from '../system.js';
10
-
11
- /**
12
- * 脚本项接口
13
- */
14
- interface ScriptItem {
15
- /** 脚本名称 */
16
- name: string;
17
- /** 脚本来源 (core 或 tpl) */
18
- source: 'core' | 'tpl';
19
- /** 是否与另一来源的脚本重名 */
20
- duplicate: boolean;
21
- /** 脚本完整路径 */
22
- path: string;
23
- }
24
-
25
- /**
26
- * 命令行参数接口
27
- */
28
- interface CliArgs {
29
- /** 是否为预演模式(只输出计划不执行) */
30
- DRY_RUN: boolean;
31
- }
32
-
33
- // 解析目录(来自 system.js)
34
- // 核心脚本目录:core/scripts
35
- // 用户项目(如 tpl)的脚本目录:始终基于当前工作目录
36
- const tplScriptsDir = getProjectDir('scripts');
37
-
38
- /**
39
- * 安全地列出目录下的所有 .js/.ts 脚本文件
40
- * @param dir - 目录路径
41
- * @returns 脚本名称数组(不含扩展名)
42
- */
43
- function safeList(dir: string): string[] {
44
- try {
45
- // 使用 Bun.Glob 查找当前目录下的所有 .js 和 .ts 文件(不递归)
46
- const glob = new Glob('*.{js,ts}');
47
- const files = Array.from(
48
- glob.scanSync({
49
- cwd: dir,
50
- absolute: false,
51
- onlyFiles: true,
52
- dot: false
53
- })
54
- );
55
- // 移除扩展名并排序
56
- return files
57
- .map((f) => {
58
- const basename = path.basename(f);
59
- return basename.replace(/\.(js|ts)$/, '');
60
- })
61
- .sort();
62
- } catch {
63
- return [];
64
- }
65
- }
66
-
67
- /**
68
- * 构建所有可用脚本的列表
69
- * @returns 脚本项数组
70
- */
71
- function buildScriptItems(): ScriptItem[] {
72
- const coreList = safeList(coreScriptsDir);
73
- const tplList = safeList(tplScriptsDir);
74
- const coreSet = new Set(coreList);
75
-
76
- const items: ScriptItem[] = [];
77
-
78
- // 添加核心脚本
79
- for (const name of coreList) {
80
- items.push({
81
- name: name,
82
- source: 'core',
83
- duplicate: tplList.includes(name),
84
- path: path.resolve(coreScriptsDir, `${name}.js`) // 优先 .js
85
- });
86
- }
87
-
88
- // 添加用户脚本
89
- for (const name of tplList) {
90
- items.push({
91
- name: name,
92
- source: 'tpl',
93
- duplicate: coreSet.has(name),
94
- path: path.resolve(tplScriptsDir, `${name}.js`) // 优先 .js
95
- });
96
- }
97
-
98
- // 排序:名称字典序,core 在前
99
- items.sort((a, b) => {
100
- if (a.name === b.name) {
101
- return a.source === b.source ? 0 : a.source === 'core' ? -1 : 1;
102
- }
103
- return a.name.localeCompare(b.name);
104
- });
105
-
106
- return items;
107
- }
108
-
109
- /**
110
- * 打印所有可用的脚本列表
111
- */
112
- function printAllScripts(): void {
113
- const items = buildScriptItems();
114
- if (items.length === 0) {
115
- console.log(' • <无>');
116
- return;
117
- }
118
- for (const it of items) {
119
- if (it.source === 'tpl' && it.duplicate) {
120
- console.log(` • ${it.name}(重复)`);
121
- } else {
122
- console.log(` • ${it.name}`);
123
- }
124
- }
125
- }
126
-
127
- /**
128
- * 解析脚本名称到完整路径
129
- * @param name - 脚本名称(可带或不带 .js/.ts 扩展名)
130
- * @returns 脚本完整路径,未找到返回 null
131
- */
132
- async function resolveScriptPath(name: string): Promise<string | null> {
133
- // 移除扩展名
134
- const base = name.replace(/\.(js|ts)$/, '');
135
-
136
- // 检查 .ts 文件(优先)
137
- const coreTsPath = path.resolve(coreScriptsDir, `${base}.ts`);
138
- const tplTsPath = path.resolve(tplScriptsDir, `${base}.ts`);
139
- if (await Bun.file(coreTsPath).exists()) return coreTsPath;
140
- if (await Bun.file(tplTsPath).exists()) return tplTsPath;
141
-
142
- // 回退到 .js 文件
143
- const coreJsPath = path.resolve(coreScriptsDir, `${base}.js`);
144
- const tplJsPath = path.resolve(tplScriptsDir, `${base}.js`);
145
- if (await Bun.file(coreJsPath).exists()) return coreJsPath;
146
- if (await Bun.file(tplJsPath).exists()) return tplJsPath;
147
-
148
- // 回退到列表匹配(防止极端路径或大小写差异)
149
- const items = buildScriptItems();
150
- const hit = items.find((it) => it.name.toLowerCase() === base.toLowerCase() && it.source === 'core') || items.find((it) => it.name.toLowerCase() === base.toLowerCase());
151
-
152
- return hit ? hit.path : null;
153
- }
154
-
155
- /**
156
- * 在指定路径运行脚本
157
- * @param targetPath - 脚本完整路径
158
- * @param label - 脚本标签(用于日志)
159
- * @param args - 传递给脚本的参数
160
- * @returns 脚本退出码
161
- */
162
- async function runScriptAtPath(targetPath: string, label: string, args: string[] = []): Promise<number> {
163
- const bunExe = process.execPath || 'bun';
164
- const child = Bun.spawn({
165
- cmd: [bunExe, targetPath, ...args],
166
- stdio: ['inherit', 'inherit', 'inherit'],
167
- cwd: process.cwd(),
168
- env: { ...process.env, LOG_TO_CONSOLE: '1' }
169
- });
170
- const code = await child.exited;
171
- return code ?? 0;
172
- }
173
-
174
- /**
175
- * CLI 主函数
176
- */
177
- async function main(): Promise<void> {
178
- const [, , cmd, ...args] = process.argv;
179
-
180
- // 无参数:打印所有脚本
181
- if (!cmd) {
182
- printAllScripts();
183
- process.exit(0);
184
- }
185
-
186
- // 按名称执行(将剩余参数透传给脚本)
187
- const target = await resolveScriptPath(cmd);
188
- if (!target) {
189
- console.error(`未找到脚本: ${cmd}`);
190
- printAllScripts();
191
- process.exit(1);
192
- }
193
-
194
- const code = await runScriptAtPath(target, cmd, args);
195
- process.exit(code ?? 0);
196
- }
197
-
198
- // 启动 CLI
199
- main().catch((e: Error) => {
200
- console.error('Befly CLI 执行失败:', e);
201
- process.exit(1);
202
- });
package/bunfig.toml DELETED
@@ -1,3 +0,0 @@
1
- [install]
2
- linker = "isolated"
3
- node-gyp = "bun x node-gyp"
package/plugins/tool.ts DELETED
@@ -1,34 +0,0 @@
1
- /**
2
- * Tool 插件 - TypeScript 版本
3
- * 提供数据处理工具
4
- */
5
-
6
- import { Tool } from '../utils/tool.js';
7
- import { Logger } from '../utils/logger.js';
8
- import type { Plugin } from '../types/plugin.js';
9
- import type { BeflyContext } from '../types/befly.js';
10
-
11
- /**
12
- * Tool 插件
13
- */
14
- const toolPlugin: Plugin = {
15
- name: '_tool',
16
- after: ['_redis', '_db'],
17
-
18
- async onInit(befly: BeflyContext): Promise<Tool> {
19
- try {
20
- const tool = new Tool(befly);
21
- Logger.info('Tool 插件初始化成功');
22
- return tool;
23
- } catch (error: any) {
24
- Logger.error({
25
- msg: 'Tool 初始化失败',
26
- message: error.message,
27
- stack: error.stack
28
- });
29
- throw error;
30
- }
31
- }
32
- };
33
-
34
- export default toolPlugin;
@@ -1,112 +0,0 @@
1
- /**
2
- * 同步开发者用户到数据库
3
- * - 用户名: Env.DEV_USERNAME (默认 dev)
4
- * - 密码: Crypto2.hmacMd5(Crypto2.md5(Env.DEV_PASSWORD), Env.MD5_SALT)
5
- */
6
-
7
- import { DB } from '../plugins/db.js';
8
- import { Env } from '../config/env.js';
9
- import { Logger } from '../utils/logger.js';
10
- import { Crypto2 } from '../utils/crypto.js';
11
- import { createSqlClient } from '../utils/dbHelper.js';
12
-
13
- // CLI 参数类型
14
- interface CliArgs {
15
- DRY_RUN: boolean;
16
- }
17
-
18
- // 解析命令行参数
19
- const ARGV = Array.isArray(process.argv) ? process.argv : [];
20
- const CLI: CliArgs = { DRY_RUN: ARGV.includes('--plan') };
21
-
22
- /**
23
- * 执行 SQL 查询
24
- */
25
- const exec = async (client: any, query: string, params: any[] = []): Promise<any> => {
26
- if (params && params.length > 0) {
27
- return await client.unsafe(query, params);
28
- }
29
- return await client.unsafe(query);
30
- };
31
-
32
- /**
33
- * 同步开发管理员账号
34
- * @param client 可选,复用已有 SQL 客户端;不传则内部创建与关闭
35
- * @returns 是否成功
36
- */
37
- export async function SyncDev(client: any = null): Promise<boolean> {
38
- let ownClient = false;
39
-
40
- try {
41
- if (CLI.DRY_RUN) {
42
- Logger.info('[计划] 同步完成后将初始化/更新 admin.dev 账号(plan 模式不执行)');
43
- return true;
44
- }
45
-
46
- if (!Env.DEV_PASSWORD || !Env.MD5_SALT) {
47
- Logger.warn('跳过开发管理员初始化:缺少 DEV_PASSWORD 或 MD5_SALT 配置');
48
- return false;
49
- }
50
-
51
- if (!client) {
52
- client = await createSqlClient({ max: 1 });
53
- ownClient = true;
54
- }
55
-
56
- // 检查 sys_admin 表是否存在(核心表带 sys_ 前缀)
57
- const exist = await exec(client, 'SELECT COUNT(*) AS cnt FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? LIMIT 1', [Env.DB_NAME || '', 'sys_admin']);
58
-
59
- if (!exist || !exist[0] || Number(exist[0].cnt) === 0) {
60
- Logger.warn('跳过开发管理员初始化:未检测到 sys_admin 表');
61
- return false;
62
- }
63
-
64
- const nowTs = Date.now();
65
- // 对密码进行双重加密
66
- const hashed = Crypto2.hmacMd5(Crypto2.md5(Env.DEV_PASSWORD), Env.MD5_SALT);
67
-
68
- // 更新存在的 dev 账号
69
- const updateRes = await exec(client, 'UPDATE `sys_admin` SET `password` = ?, `updated_at` = ? WHERE `account` = ? LIMIT 1', [hashed, nowTs, 'dev']);
70
-
71
- const affected = updateRes?.affectedRows ?? updateRes?.rowsAffected ?? 0;
72
-
73
- if (!affected || affected === 0) {
74
- // 插入新账号
75
- const id = nowTs;
76
- await exec(client, 'INSERT INTO `sys_admin` (`id`, `created_at`, `updated_at`, `deleted_at`, `state`, `account`, `password`) VALUES (?, ?, ?, 0, 0, ?, ?)', [id, nowTs, nowTs, 'dev', hashed]);
77
- Logger.info('开发管理员已初始化:account=dev');
78
- } else {
79
- Logger.info('开发管理员已更新密码并刷新更新时间:account=dev');
80
- }
81
-
82
- return true;
83
- } catch (error: any) {
84
- Logger.warn(`开发管理员初始化步骤出错:${error.message}`);
85
- return false;
86
- } finally {
87
- if (ownClient && client) {
88
- try {
89
- await client.close();
90
- } catch (error: any) {
91
- Logger.warn('关闭数据库连接时出错:', error.message);
92
- }
93
- }
94
- }
95
- }
96
-
97
- /**
98
- * 允许直接运行该脚本
99
- */
100
- if (import.meta.main) {
101
- SyncDev()
102
- .then((ok: boolean) => {
103
- if (CLI.DRY_RUN) {
104
- process.exit(0);
105
- }
106
- process.exit(ok ? 0 : 1);
107
- })
108
- .catch((err: Error) => {
109
- console.error('❌ 开发管理员同步失败:', err);
110
- process.exit(1);
111
- });
112
- }
package/system.ts DELETED
@@ -1,149 +0,0 @@
1
- /**
2
- * Befly 框架系统路径定义 - TypeScript 版本
3
- * 提供统一的路径变量,供整个框架使用
4
- */
5
-
6
- import { fileURLToPath } from 'node:url';
7
- import { dirname, join, resolve, relative } from 'node:path';
8
-
9
- // 当前文件的路径信息
10
- const __filename = fileURLToPath(import.meta.url);
11
- const __dirname = dirname(__filename);
12
-
13
- // Befly 框架根目录
14
- export const __dirroot = __dirname;
15
-
16
- // 各个重要目录的路径
17
- export const __dirscript = join(__dirroot, 'scripts');
18
- export const __dirbin = join(__dirroot, 'bin');
19
- export const __dirutils = join(__dirroot, 'utils');
20
- export const __dirconfig = join(__dirroot, 'config');
21
- export const __dirtables = join(__dirroot, 'tables');
22
- export const __dirchecks = join(__dirroot, 'checks');
23
- export const __dirapis = join(__dirroot, 'apis');
24
- export const __dirplugins = join(__dirroot, 'plugins');
25
- export const __dirlibs = join(__dirroot, 'libs');
26
- export const __dirtests = join(__dirroot, 'tests');
27
-
28
- /**
29
- * 获取项目根目录(befly 框架的使用方项目)
30
- */
31
- export const getProjectRoot = (): string => {
32
- return process.cwd();
33
- };
34
-
35
- /**
36
- * 获取项目中的特定目录
37
- * @param subdir - 子目录名称
38
- */
39
- export const getProjectDir = (subdir: string = ''): string => {
40
- return subdir ? join(getProjectRoot(), subdir) : getProjectRoot();
41
- };
42
-
43
- /**
44
- * 创建路径解析器,基于 befly 根目录
45
- * @param paths - 路径片段
46
- */
47
- export const resolveBeflyPath = (...paths: string[]): string => {
48
- return resolve(__dirroot, ...paths);
49
- };
50
-
51
- /**
52
- * 创建路径解析器,基于项目根目录
53
- * @param paths - 路径片段
54
- */
55
- export const resolveProjectPath = (...paths: string[]): string => {
56
- return resolve(getProjectRoot(), ...paths);
57
- };
58
-
59
- /**
60
- * 获取相对于 befly 根目录的相对路径
61
- * @param targetPath - 目标路径
62
- */
63
- export const getRelativeBeflyPath = (targetPath: string): string => {
64
- return relative(__dirroot, targetPath);
65
- };
66
-
67
- /**
68
- * 获取相对于项目根目录的相对路径
69
- * @param targetPath - 目标路径
70
- */
71
- export const getRelativeProjectPath = (targetPath: string): string => {
72
- return relative(getProjectRoot(), targetPath);
73
- };
74
-
75
- /**
76
- * 系统路径配置对象
77
- */
78
- export interface SystemPaths {
79
- script: string;
80
- bin: string;
81
- utils: string;
82
- config: string;
83
- tables: string;
84
- checks: string;
85
- apis: string;
86
- plugins: string;
87
- libs: string;
88
- tests: string;
89
- }
90
-
91
- /**
92
- * 系统工具函数集合
93
- */
94
- export interface SystemUtils {
95
- getProjectRoot: typeof getProjectRoot;
96
- getProjectDir: typeof getProjectDir;
97
- resolveBeflyPath: typeof resolveBeflyPath;
98
- resolveProjectPath: typeof resolveProjectPath;
99
- getRelativeBeflyPath: typeof getRelativeBeflyPath;
100
- getRelativeProjectPath: typeof getRelativeProjectPath;
101
- }
102
-
103
- /**
104
- * 系统配置对象
105
- */
106
- export interface SystemConfig {
107
- __filename: string;
108
- __dirname: string;
109
- __dirroot: string;
110
- paths: SystemPaths;
111
- utils: SystemUtils;
112
- }
113
-
114
- /**
115
- * 默认导出包含所有路径信息的对象
116
- */
117
- const system: SystemConfig = {
118
- // 基础路径变量
119
- __filename,
120
- __dirname,
121
- __dirroot,
122
-
123
- // Befly 框架目录
124
- paths: {
125
- script: __dirscript,
126
- bin: __dirbin,
127
- utils: __dirutils,
128
- config: __dirconfig,
129
- tables: __dirtables,
130
- checks: __dirchecks,
131
- apis: __dirapis,
132
- plugins: __dirplugins,
133
- libs: __dirlibs,
134
- tests: __dirtests
135
- },
136
-
137
- // 工具函数
138
- utils: {
139
- getProjectRoot,
140
- getProjectDir,
141
- resolveBeflyPath,
142
- resolveProjectPath,
143
- getRelativeBeflyPath,
144
- getRelativeProjectPath
145
- }
146
- };
147
-
148
- // 重新导出基础路径变量和 system 对象
149
- export { __filename, __dirname, system };
@@ -1,21 +0,0 @@
1
- {
2
- "id": "ID|number|1|null|null|1|null",
3
- "email": "邮箱|string|5|100|null|1|^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
4
- "phone": "手机号|string|11|11|null|1|^1[3-9]\\d{9}$",
5
- "page": "页码|number|1|9999|1|0|null",
6
- "limit": "每页数量|number|1|100|10|0|null",
7
- "title": "标题|string|1|200|null|0|null",
8
- "description": "描述|string|0|500|null|0|null",
9
- "keyword": "关键词|string|1|50|null|1|null",
10
- "keywords": "关键词列表|array|0|50|null|0|null",
11
- "enabled": "启用状态|number|0|1|1|0|^(0|1)$",
12
- "date": "日期|string|10|10|null|0|^\\d{4}-\\d{2}-\\d{2}$",
13
- "datetime": "日期时间|string|19|25|null|0|^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}",
14
- "filename": "文件名|string|1|255|null|0|null",
15
- "url": "网址|string|5|500|null|0|^https?://",
16
- "tag": "标签|array|0|10|null|0|null",
17
- "orderBy": "排序字段|array|0|20|null|0|null",
18
- "where": "查询条件|object|null|null|null|0|null",
19
- "startTime": "开始时间|number|0|9999999999999|null|0|null",
20
- "endTime": "结束时间|number|0|9999999999999|null|0|null"
21
- }
package/tables/admin.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "account": "账号|string|3|50|null|1|^[a-zA-Z0-9_]+$",
3
- "password": "密码|string|32|255|null|0|null",
4
- "nickname": "昵称|string|0|50|null|0|null",
5
- "avatar": "头像|string|0|500|null|0|null",
6
- "email": "邮箱|string|0|100|null|0|^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
7
- "phone": "手机号|string|0|11|null|0|^1[3-9]\\d{9}$",
8
- "role": "角色|string|1|20|admin|1|^(superadmin|admin|user)$",
9
- "status": "状态|number|0|1|1|1|^(0|1)$"
10
- }
@@ -1,60 +0,0 @@
1
- /**
2
- * Addon 辅助工具函数
3
- * 提供 addon 扫描、路径获取等功能
4
- */
5
-
6
- import fs from 'node:fs';
7
- import { join } from 'node:path';
8
- import { getProjectRoot } from '../system.js';
9
-
10
- /**
11
- * 获取 addons 目录路径
12
- */
13
- export const getAddonsDir = (): string => {
14
- return join(getProjectRoot(), 'addons');
15
- };
16
-
17
- /**
18
- * 扫描所有可用的 addon
19
- * @returns addon 名称数组(过滤掉 _ 开头的目录)
20
- */
21
- export const scanAddons = (): string[] => {
22
- const addonsDir = getAddonsDir();
23
- if (!fs.existsSync(addonsDir)) {
24
- return [];
25
- }
26
-
27
- try {
28
- return fs
29
- .readdirSync(addonsDir)
30
- .filter((name) => {
31
- const fullPath = join(addonsDir, name);
32
- const stat = fs.statSync(fullPath);
33
- const isDir = stat.isDirectory();
34
- const notSkip = !name.startsWith('_'); // 跳过 _ 开头的目录
35
- return isDir && notSkip;
36
- })
37
- .sort(); // 按字母顺序排序
38
- } catch (error) {
39
- return [];
40
- }
41
- };
42
-
43
- /**
44
- * 获取 addon 的指定子目录路径
45
- * @param addonName - addon 名称
46
- * @param subDir - 子目录名称(apis, checks, plugins, tables, types, config)
47
- */
48
- export const getAddonDir = (addonName: string, subDir: string): string => {
49
- return join(getAddonsDir(), addonName, subDir);
50
- };
51
-
52
- /**
53
- * 检查 addon 是否存在指定子目录
54
- * @param addonName - addon 名称
55
- * @param subDir - 子目录名称
56
- */
57
- export const hasAddonDir = (addonName: string, subDir: string): boolean => {
58
- const dir = getAddonDir(addonName, subDir);
59
- return fs.existsSync(dir) && fs.statSync(dir).isDirectory();
60
- };
package/utils/api.ts DELETED
@@ -1,23 +0,0 @@
1
- /**
2
- * API 工具类 - TypeScript 版本
3
- * 提供 API 路由定义的便捷方法
4
- */
5
-
6
- import type { ApiRoute, ApiOptions } from '../types/api.js';
7
-
8
- /**
9
- * 定义 API 路由(主函数)
10
- * @param name - 接口名称
11
- * @param options - 接口配置选项
12
- * @returns API 路由定义
13
- */
14
- export function Api(name: string, options: ApiOptions): ApiRoute {
15
- return {
16
- method: options.method || 'POST',
17
- name: name,
18
- auth: options.auth ?? false,
19
- fields: options.fields ?? {},
20
- required: options.required ?? [],
21
- handler: async (befly, ctx, req) => await options.handler(befly, ctx, req)
22
- };
23
- }
package/utils/datetime.ts DELETED
@@ -1,51 +0,0 @@
1
- /**
2
- * Befly 日期时间工具
3
- * 提供日期格式化和性能计时功能
4
- */
5
-
6
- /**
7
- * 格式化日期
8
- * @param date - 日期对象、时间戳或日期字符串
9
- * @param format - 格式化模板(支持 YYYY, MM, DD, HH, mm, ss)
10
- * @returns 格式化后的日期字符串
11
- *
12
- * @example
13
- * formatDate(new Date('2025-10-11 15:30:45')) // '2025-10-11 15:30:45'
14
- * formatDate(new Date('2025-10-11'), 'YYYY-MM-DD') // '2025-10-11'
15
- * formatDate(1728648645000, 'YYYY/MM/DD HH:mm') // '2025/10/11 15:30'
16
- * formatDate('2025-10-11', 'MM-DD') // '10-11'
17
- */
18
- export const formatDate = (date: Date | string | number = new Date(), format: string = 'YYYY-MM-DD HH:mm:ss'): string => {
19
- const d = new Date(date);
20
- const year = d.getFullYear();
21
- const month = String(d.getMonth() + 1).padStart(2, '0');
22
- const day = String(d.getDate()).padStart(2, '0');
23
- const hour = String(d.getHours()).padStart(2, '0');
24
- const minute = String(d.getMinutes()).padStart(2, '0');
25
- const second = String(d.getSeconds()).padStart(2, '0');
26
-
27
- return format.replace('YYYY', String(year)).replace('MM', month).replace('DD', day).replace('HH', hour).replace('mm', minute).replace('ss', second);
28
- };
29
-
30
- /**
31
- * 计算性能时间差
32
- * 用于测量代码执行时间(使用 Bun.nanoseconds())
33
- * @param startTime - 开始时间(Bun.nanoseconds()返回值)
34
- * @param endTime - 结束时间(可选,默认为当前时间)
35
- * @returns 时间差(毫秒或秒)
36
- *
37
- * @example
38
- * const start = Bun.nanoseconds();
39
- * // ... 执行代码 ...
40
- * const elapsed = calcPerfTime(start); // '15.23 毫秒' 或 '2.45 秒'
41
- */
42
- export const calcPerfTime = (startTime: number, endTime: number = Bun.nanoseconds()): string => {
43
- const elapsedMs = (endTime - startTime) / 1_000_000;
44
-
45
- if (elapsedMs < 1000) {
46
- return `${elapsedMs.toFixed(2)} 毫秒`;
47
- } else {
48
- const elapsedSeconds = elapsedMs / 1000;
49
- return `${elapsedSeconds.toFixed(2)} 秒`;
50
- }
51
- };