befly 3.10.18 → 3.11.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.
- package/README.md +83 -307
- package/dist/befly.config.d.ts +7 -0
- package/{befly.config.ts → dist/befly.config.js} +11 -36
- package/dist/befly.js +15621 -0
- package/dist/befly.min.js +21 -0
- package/dist/checks/checkApi.d.ts +1 -0
- package/{checks/checkApi.ts → dist/checks/checkApi.js} +12 -30
- package/dist/checks/checkHook.d.ts +1 -0
- package/dist/checks/checkHook.js +86 -0
- package/dist/checks/checkMenu.d.ts +7 -0
- package/{checks/checkMenu.ts → dist/checks/checkMenu.js} +18 -53
- package/dist/checks/checkPlugin.d.ts +1 -0
- package/dist/checks/checkPlugin.js +86 -0
- package/dist/checks/checkTable.d.ts +6 -0
- package/{checks/checkTable.ts → dist/checks/checkTable.js} +17 -41
- package/dist/configs/presetFields.d.ts +4 -0
- package/{configs/presetFields.ts → dist/configs/presetFields.js} +1 -1
- package/dist/configs/presetRegexp.d.ts +145 -0
- package/{utils/regex.ts → dist/configs/presetRegexp.js} +8 -31
- package/dist/hooks/auth.d.ts +7 -0
- package/{hooks/auth.ts → dist/hooks/auth.js} +8 -10
- package/dist/hooks/cors.d.ts +11 -0
- package/{hooks/cors.ts → dist/hooks/cors.js} +5 -13
- package/dist/hooks/parser.d.ts +14 -0
- package/{hooks/parser.ts → dist/hooks/parser.js} +31 -45
- package/dist/hooks/permission.d.ts +14 -0
- package/{hooks/permission.ts → dist/hooks/permission.js} +16 -25
- package/dist/hooks/validator.d.ts +11 -0
- package/{hooks/validator.ts → dist/hooks/validator.js} +9 -14
- package/dist/index.d.ts +26 -0
- package/{main.ts → dist/index.js} +61 -100
- package/dist/lib/asyncContext.d.ts +21 -0
- package/dist/lib/asyncContext.js +27 -0
- package/dist/lib/cacheHelper.d.ts +95 -0
- package/{lib/cacheHelper.ts → dist/lib/cacheHelper.js} +45 -105
- package/dist/lib/cacheKeys.d.ts +23 -0
- package/{lib/cacheKeys.ts → dist/lib/cacheKeys.js} +5 -10
- package/dist/lib/cipher.d.ts +153 -0
- package/{lib/cipher.ts → dist/lib/cipher.js} +23 -44
- package/dist/lib/connect.d.ts +91 -0
- package/{lib/connect.ts → dist/lib/connect.js} +47 -88
- package/dist/lib/dbDialect.d.ts +87 -0
- package/{lib/dbDialect.ts → dist/lib/dbDialect.js} +32 -112
- package/dist/lib/dbHelper.d.ts +204 -0
- package/{lib/dbHelper.ts → dist/lib/dbHelper.js} +82 -241
- package/dist/lib/dbUtils.d.ts +68 -0
- package/{lib/dbUtils.ts → dist/lib/dbUtils.js} +51 -126
- package/dist/lib/jwt.d.ts +13 -0
- package/{lib/jwt.ts → dist/lib/jwt.js} +11 -32
- package/dist/lib/logger.d.ts +42 -0
- package/dist/lib/logger.js +1144 -0
- package/dist/lib/redisHelper.d.ts +185 -0
- package/{lib/redisHelper.ts → dist/lib/redisHelper.js} +97 -141
- package/dist/lib/sqlBuilder.d.ts +160 -0
- package/{lib/sqlBuilder.ts → dist/lib/sqlBuilder.js} +132 -278
- package/dist/lib/sqlCheck.d.ts +23 -0
- package/{lib/sqlCheck.ts → dist/lib/sqlCheck.js} +24 -41
- package/dist/lib/validator.d.ts +45 -0
- package/{lib/validator.ts → dist/lib/validator.js} +44 -61
- package/dist/loader/loadApis.d.ts +12 -0
- package/{loader/loadApis.ts → dist/loader/loadApis.js} +10 -20
- package/dist/loader/loadHooks.d.ts +7 -0
- package/dist/loader/loadHooks.js +35 -0
- package/dist/loader/loadPlugins.d.ts +8 -0
- package/{loader/loadPlugins.ts → dist/loader/loadPlugins.js} +14 -26
- package/dist/paths.d.ts +93 -0
- package/{paths.ts → dist/paths.js} +6 -19
- package/dist/plugins/cache.d.ts +16 -0
- package/{plugins/cache.ts → dist/plugins/cache.js} +7 -12
- package/dist/plugins/cipher.d.ts +12 -0
- package/{plugins/cipher.ts → dist/plugins/cipher.js} +4 -6
- package/dist/plugins/config.d.ts +12 -0
- package/dist/plugins/config.js +8 -0
- package/dist/plugins/db.d.ts +16 -0
- package/{plugins/db.ts → dist/plugins/db.js} +11 -17
- package/dist/plugins/jwt.d.ts +12 -0
- package/dist/plugins/jwt.js +12 -0
- package/dist/plugins/logger.d.ts +32 -0
- package/{plugins/logger.ts → dist/plugins/logger.js} +5 -8
- package/dist/plugins/redis.d.ts +16 -0
- package/{plugins/redis.ts → dist/plugins/redis.js} +9 -12
- package/dist/plugins/tool.d.ts +81 -0
- package/{plugins/tool.ts → dist/plugins/tool.js} +9 -30
- package/dist/router/api.d.ts +14 -0
- package/dist/router/api.js +107 -0
- package/dist/router/static.d.ts +9 -0
- package/{router/static.ts → dist/router/static.js} +20 -34
- package/dist/scripts/ensureDist.d.ts +1 -0
- package/dist/scripts/ensureDist.js +296 -0
- package/dist/sync/syncApi.d.ts +3 -0
- package/{sync/syncApi.ts → dist/sync/syncApi.js} +35 -55
- package/dist/sync/syncCache.d.ts +2 -0
- package/{sync/syncCache.ts → dist/sync/syncCache.js} +1 -6
- package/dist/sync/syncDev.d.ts +6 -0
- package/{sync/syncDev.ts → dist/sync/syncDev.js} +29 -62
- package/dist/sync/syncMenu.d.ts +14 -0
- package/{sync/syncMenu.ts → dist/sync/syncMenu.js} +65 -125
- package/dist/sync/syncTable.d.ts +151 -0
- package/{sync/syncTable.ts → dist/sync/syncTable.js} +172 -379
- package/{types → dist/types}/api.d.ts +12 -51
- package/dist/types/api.js +4 -0
- package/{types → dist/types}/befly.d.ts +32 -227
- package/dist/types/befly.js +4 -0
- package/{types → dist/types}/cache.d.ts +7 -15
- package/dist/types/cache.js +4 -0
- package/dist/types/cipher.d.ts +27 -0
- package/dist/types/cipher.js +7 -0
- package/{types → dist/types}/common.d.ts +8 -33
- package/dist/types/common.js +5 -0
- package/{types → dist/types}/context.d.ts +3 -5
- package/dist/types/context.js +4 -0
- package/{types → dist/types}/crypto.d.ts +0 -3
- package/dist/types/crypto.js +4 -0
- package/dist/types/database.d.ts +138 -0
- package/dist/types/database.js +4 -0
- package/dist/types/hook.d.ts +17 -0
- package/dist/types/hook.js +6 -0
- package/dist/types/jwt.d.ts +75 -0
- package/dist/types/jwt.js +4 -0
- package/dist/types/logger.d.ts +59 -0
- package/dist/types/logger.js +6 -0
- package/dist/types/plugin.d.ts +16 -0
- package/dist/types/plugin.js +6 -0
- package/dist/types/redis.d.ts +71 -0
- package/dist/types/redis.js +4 -0
- package/{types/roleApisCache.ts → dist/types/roleApisCache.d.ts} +0 -2
- package/dist/types/roleApisCache.js +8 -0
- package/dist/types/sync.d.ts +92 -0
- package/dist/types/sync.js +4 -0
- package/dist/types/table.d.ts +34 -0
- package/dist/types/table.js +4 -0
- package/dist/types/validate.d.ts +67 -0
- package/dist/types/validate.js +4 -0
- package/dist/utils/calcPerfTime.d.ts +4 -0
- package/{utils/calcPerfTime.ts → dist/utils/calcPerfTime.js} +3 -3
- package/dist/utils/convertBigIntFields.d.ts +11 -0
- package/{utils/convertBigIntFields.ts → dist/utils/convertBigIntFields.js} +5 -9
- package/dist/utils/cors.d.ts +8 -0
- package/{utils/cors.ts → dist/utils/cors.js} +1 -3
- package/dist/utils/disableMenusGlob.d.ts +13 -0
- package/{utils/disableMenusGlob.ts → dist/utils/disableMenusGlob.js} +9 -29
- package/dist/utils/fieldClear.d.ts +11 -0
- package/{utils/fieldClear.ts → dist/utils/fieldClear.js} +15 -33
- package/dist/utils/getClientIp.d.ts +6 -0
- package/{utils/getClientIp.ts → dist/utils/getClientIp.js} +1 -7
- package/dist/utils/importDefault.d.ts +1 -0
- package/dist/utils/importDefault.js +29 -0
- package/dist/utils/isDirentDirectory.d.ts +2 -0
- package/{utils/isDirentDirectory.ts → dist/utils/isDirentDirectory.js} +3 -8
- package/dist/utils/loadMenuConfigs.d.ts +29 -0
- package/{utils/loadMenuConfigs.ts → dist/utils/loadMenuConfigs.js} +66 -52
- package/dist/utils/mergeAndConcat.d.ts +7 -0
- package/dist/utils/mergeAndConcat.js +72 -0
- package/dist/utils/processAtSymbol.d.ts +4 -0
- package/{utils/processFields.ts → dist/utils/processAtSymbol.js} +5 -9
- package/dist/utils/processInfo.d.ts +24 -0
- package/{utils/process.ts → dist/utils/processInfo.js} +2 -18
- package/dist/utils/response.d.ts +20 -0
- package/{utils/response.ts → dist/utils/response.js} +28 -49
- package/dist/utils/scanAddons.d.ts +17 -0
- package/{utils/scanAddons.ts → dist/utils/scanAddons.js} +7 -41
- package/dist/utils/scanConfig.d.ts +26 -0
- package/{utils/scanConfig.ts → dist/utils/scanConfig.js} +28 -66
- package/dist/utils/scanCoreBuiltins.d.ts +3 -0
- package/dist/utils/scanCoreBuiltins.js +65 -0
- package/dist/utils/scanFiles.d.ts +30 -0
- package/{utils/scanFiles.ts → dist/utils/scanFiles.js} +44 -71
- package/dist/utils/scanSources.d.ts +10 -0
- package/dist/utils/scanSources.js +46 -0
- package/dist/utils/sortModules.d.ts +28 -0
- package/{utils/sortModules.ts → dist/utils/sortModules.js} +26 -66
- package/dist/utils/util.d.ts +84 -0
- package/dist/utils/util.js +262 -0
- package/package.json +26 -34
- package/.gitignore +0 -0
- package/bunfig.toml +0 -3
- package/checks/checkHook.ts +0 -48
- package/checks/checkPlugin.ts +0 -48
- package/configs/presetRegexp.ts +0 -225
- package/docs/README.md +0 -98
- package/docs/api/api.md +0 -1921
- package/docs/guide/examples.md +0 -926
- package/docs/guide/quickstart.md +0 -354
- package/docs/hooks/auth.md +0 -38
- package/docs/hooks/cors.md +0 -28
- package/docs/hooks/hook.md +0 -838
- package/docs/hooks/parser.md +0 -19
- package/docs/hooks/rateLimit.md +0 -47
- package/docs/infra/redis.md +0 -628
- package/docs/plugins/cipher.md +0 -61
- package/docs/plugins/database.md +0 -189
- package/docs/plugins/plugin.md +0 -986
- package/docs/reference/addon.md +0 -510
- package/docs/reference/config.md +0 -573
- package/docs/reference/logger.md +0 -495
- package/docs/reference/sync.md +0 -478
- package/docs/reference/table.md +0 -763
- package/docs/reference/validator.md +0 -620
- package/lib/asyncContext.ts +0 -43
- package/lib/logger.ts +0 -811
- package/loader/loadHooks.ts +0 -51
- package/plugins/config.ts +0 -13
- package/plugins/jwt.ts +0 -15
- package/router/api.ts +0 -130
- package/tsconfig.json +0 -8
- package/types/database.d.ts +0 -541
- package/types/hook.d.ts +0 -25
- package/types/jwt.d.ts +0 -118
- package/types/logger.d.ts +0 -65
- package/types/plugin.d.ts +0 -19
- package/types/redis.d.ts +0 -83
- package/types/sync.d.ts +0 -398
- package/types/table.d.ts +0 -216
- package/types/validate.d.ts +0 -69
- package/utils/arrayKeysToCamel.ts +0 -18
- package/utils/configTypes.ts +0 -3
- package/utils/genShortId.ts +0 -12
- package/utils/importDefault.ts +0 -21
- package/utils/keysToCamel.ts +0 -22
- package/utils/keysToSnake.ts +0 -22
- package/utils/pickFields.ts +0 -19
- package/utils/scanSources.ts +0 -64
- package/utils/sqlLog.ts +0 -37
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 数据同步相关类型定义
|
|
3
|
+
*/
|
|
4
|
+
import type { BeflyContext } from "./befly";
|
|
5
|
+
import type { KeyValue } from "./common";
|
|
6
|
+
/**
|
|
7
|
+
* 同步结果
|
|
8
|
+
*/
|
|
9
|
+
export interface SyncResult {
|
|
10
|
+
/** 是否成功 */
|
|
11
|
+
success: boolean;
|
|
12
|
+
/** 同步的数量 */
|
|
13
|
+
count: number;
|
|
14
|
+
/** 错误信息 */
|
|
15
|
+
error?: string;
|
|
16
|
+
/** 额外数据 */
|
|
17
|
+
data?: KeyValue;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 同步选项
|
|
21
|
+
*/
|
|
22
|
+
export interface SyncOptions {
|
|
23
|
+
/** 是否强制同步(覆盖已有数据) */
|
|
24
|
+
force?: boolean;
|
|
25
|
+
/** 是否跳过已存在的数据 */
|
|
26
|
+
skipExisting?: boolean;
|
|
27
|
+
/** 同步批次大小 */
|
|
28
|
+
batchSize?: number;
|
|
29
|
+
/** 其他选项 */
|
|
30
|
+
[key: string]: any;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 同步器接口
|
|
34
|
+
*/
|
|
35
|
+
export interface Syncer {
|
|
36
|
+
/** 同步菜单 */
|
|
37
|
+
syncMenus(): Promise<SyncResult>;
|
|
38
|
+
/** 同步 API */
|
|
39
|
+
syncApis(): Promise<SyncResult>;
|
|
40
|
+
/** 同步字段定义 */
|
|
41
|
+
syncFields(): Promise<SyncResult>;
|
|
42
|
+
/** 同步所有 */
|
|
43
|
+
syncAll(): Promise<SyncResult>;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Syncer 构造函数
|
|
47
|
+
*/
|
|
48
|
+
export interface SyncerConstructor {
|
|
49
|
+
new (befly: BeflyContext, options?: SyncOptions): Syncer;
|
|
50
|
+
}
|
|
51
|
+
export interface MenuConfig {
|
|
52
|
+
path?: string;
|
|
53
|
+
name?: string;
|
|
54
|
+
sort?: number;
|
|
55
|
+
parentPath?: string;
|
|
56
|
+
children?: MenuConfig[];
|
|
57
|
+
[key: string]: any;
|
|
58
|
+
}
|
|
59
|
+
export interface SyncApiItem {
|
|
60
|
+
type?: "api" | string;
|
|
61
|
+
name: string;
|
|
62
|
+
routePath: string;
|
|
63
|
+
addonName: string;
|
|
64
|
+
[key: string]: any;
|
|
65
|
+
}
|
|
66
|
+
export interface ColumnInfo {
|
|
67
|
+
type: string;
|
|
68
|
+
columnType: string;
|
|
69
|
+
length: number | null;
|
|
70
|
+
max: number | null;
|
|
71
|
+
nullable: boolean;
|
|
72
|
+
defaultValue: any;
|
|
73
|
+
comment: string | null;
|
|
74
|
+
}
|
|
75
|
+
export type IndexInfo = Record<string, string[]>;
|
|
76
|
+
export interface FieldChange {
|
|
77
|
+
type: string;
|
|
78
|
+
current: any;
|
|
79
|
+
expected: any;
|
|
80
|
+
}
|
|
81
|
+
export interface TablePlan {
|
|
82
|
+
changed: boolean;
|
|
83
|
+
addClauses: string[];
|
|
84
|
+
modifyClauses: string[];
|
|
85
|
+
defaultClauses: string[];
|
|
86
|
+
indexActions: Array<{
|
|
87
|
+
action: "create" | "drop";
|
|
88
|
+
indexName: string;
|
|
89
|
+
fieldName: string;
|
|
90
|
+
}>;
|
|
91
|
+
commentActions?: string[];
|
|
92
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 表结构相关类型定义
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* 字段信息
|
|
6
|
+
*/
|
|
7
|
+
export interface FieldInfo {
|
|
8
|
+
name: string;
|
|
9
|
+
type: string;
|
|
10
|
+
isPrimary: boolean;
|
|
11
|
+
isNotNull: boolean;
|
|
12
|
+
defaultValue?: any;
|
|
13
|
+
isAutoIncrement?: boolean;
|
|
14
|
+
isUnique?: boolean;
|
|
15
|
+
comment?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 创建表选项
|
|
19
|
+
*/
|
|
20
|
+
export interface CreateTableOptions {
|
|
21
|
+
table: string;
|
|
22
|
+
fields: Record<string, string>;
|
|
23
|
+
indexes?: string[];
|
|
24
|
+
unique?: string[];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* SQL 帮助器选项
|
|
28
|
+
*/
|
|
29
|
+
export interface SqlHelperOptions {
|
|
30
|
+
/** 数据库类型 */
|
|
31
|
+
type: "mysql" | "postgres" | "sqlite";
|
|
32
|
+
/** 表名前缀 */
|
|
33
|
+
prefix?: string;
|
|
34
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 数据验证相关类型定义
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* 字段类型
|
|
6
|
+
*/
|
|
7
|
+
export type FieldType = "string" | "number" | "text" | "array_string" | "array_text" | "array_number_string" | "array_number_text";
|
|
8
|
+
/**
|
|
9
|
+
* 字段定义(表字段 JSON 结构)
|
|
10
|
+
*/
|
|
11
|
+
export interface FieldDefinition {
|
|
12
|
+
/** 字段标签(中文名) */
|
|
13
|
+
name: string;
|
|
14
|
+
/** 字段类型 */
|
|
15
|
+
type: FieldType | string;
|
|
16
|
+
/** 最小值/最小长度(null 表示不限制) */
|
|
17
|
+
min: number | null;
|
|
18
|
+
/** 最大值/最大长度(null 表示不限制) */
|
|
19
|
+
max: number | null;
|
|
20
|
+
/** 默认值(可为 null) */
|
|
21
|
+
default: any;
|
|
22
|
+
/** 字段描述 */
|
|
23
|
+
detail?: string;
|
|
24
|
+
/** 是否创建索引 */
|
|
25
|
+
index?: boolean;
|
|
26
|
+
/** 是否唯一约束 */
|
|
27
|
+
unique?: boolean;
|
|
28
|
+
/** 是否可为 NULL */
|
|
29
|
+
nullable?: boolean;
|
|
30
|
+
/** number 类型是否无符号(仅 MySQL 语义生效) */
|
|
31
|
+
unsigned?: boolean;
|
|
32
|
+
/** 正则(或 @alias);null 表示无约束 */
|
|
33
|
+
regexp: string | null;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 表定义(字段名 -> 字段定义)
|
|
37
|
+
*/
|
|
38
|
+
export type TableDefinition = Record<string, FieldDefinition>;
|
|
39
|
+
/**
|
|
40
|
+
* validate(data, rules) 的返回结构
|
|
41
|
+
*/
|
|
42
|
+
export interface ValidateResult {
|
|
43
|
+
code: 0 | 1;
|
|
44
|
+
failed: boolean;
|
|
45
|
+
firstError: string | null;
|
|
46
|
+
errors: string[];
|
|
47
|
+
errorFields: string[];
|
|
48
|
+
fieldErrors: Record<string, string>;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* single(value, fieldDef) 的返回结构
|
|
52
|
+
*/
|
|
53
|
+
export interface SingleResult {
|
|
54
|
+
value: any;
|
|
55
|
+
error: string | null;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Validator 静态类类型(对外)。
|
|
59
|
+
*
|
|
60
|
+
* 说明:runtime 实现是 `export class Validator`,以静态方法形式提供:
|
|
61
|
+
* - `Validator.validate(data, rules, required)`
|
|
62
|
+
* - `Validator.single(value, fieldDef)`
|
|
63
|
+
*/
|
|
64
|
+
export interface ValidatorStatic {
|
|
65
|
+
validate(data: Record<string, any>, rules: TableDefinition, required?: string[]): ValidateResult;
|
|
66
|
+
single(value: any, fieldDef: FieldDefinition): SingleResult;
|
|
67
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 计算性能时间差
|
|
3
3
|
*/
|
|
4
|
-
export const calcPerfTime = (startTime
|
|
4
|
+
export const calcPerfTime = (startTime, endTime = Bun.nanoseconds()) => {
|
|
5
5
|
const elapsedMs = (endTime - startTime) / 1_000_000;
|
|
6
|
-
|
|
7
6
|
if (elapsedMs < 1000) {
|
|
8
7
|
return `${elapsedMs.toFixed(2)} 毫秒`;
|
|
9
|
-
}
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
10
|
const elapsedSeconds = elapsedMs / 1000;
|
|
11
11
|
return `${elapsedSeconds.toFixed(2)} 秒`;
|
|
12
12
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 转换数据库 BIGINT 字段为数字类型
|
|
3
|
+
*
|
|
4
|
+
* 当 bigint: false 时,Bun SQL 会将大于 u32 的 BIGINT 返回为字符串,此方法将其转换为 number。
|
|
5
|
+
*
|
|
6
|
+
* 转换规则:
|
|
7
|
+
* 1. 白名单中的字段会被转换
|
|
8
|
+
* 2. 所有以 'Id' 或 '_id' 结尾的字段会被自动转换
|
|
9
|
+
* 3. 所有以 'At' 或 '_at' 结尾的字段会被自动转换(时间戳字段)
|
|
10
|
+
*/
|
|
11
|
+
export declare function convertBigIntFields<T = any>(arr: Record<string, any>[], fields?: string[]): T[];
|
|
@@ -8,22 +8,19 @@
|
|
|
8
8
|
* 2. 所有以 'Id' 或 '_id' 结尾的字段会被自动转换
|
|
9
9
|
* 3. 所有以 'At' 或 '_at' 结尾的字段会被自动转换(时间戳字段)
|
|
10
10
|
*/
|
|
11
|
-
export function convertBigIntFields
|
|
11
|
+
export function convertBigIntFields(arr, fields = ["id", "pid", "sort"]) {
|
|
12
12
|
if (!arr || !Array.isArray(arr)) {
|
|
13
|
-
return arr
|
|
13
|
+
return arr;
|
|
14
14
|
}
|
|
15
|
-
|
|
16
15
|
return arr.map((item) => {
|
|
17
|
-
const converted
|
|
16
|
+
const converted = {};
|
|
18
17
|
for (const [key, value] of Object.entries(item)) {
|
|
19
18
|
converted[key] = value;
|
|
20
19
|
}
|
|
21
|
-
|
|
22
20
|
for (const [key, value] of Object.entries(converted)) {
|
|
23
21
|
if (value === undefined || value === null) {
|
|
24
22
|
continue;
|
|
25
23
|
}
|
|
26
|
-
|
|
27
24
|
const shouldConvert = fields.includes(key) || key.endsWith("Id") || key.endsWith("_id") || key.endsWith("At") || key.endsWith("_at");
|
|
28
25
|
if (shouldConvert && typeof value === "string") {
|
|
29
26
|
const num = Number(value);
|
|
@@ -32,7 +29,6 @@ export function convertBigIntFields<T = any>(arr: Record<string, any>[], fields:
|
|
|
32
29
|
}
|
|
33
30
|
}
|
|
34
31
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}) as T[];
|
|
32
|
+
return converted;
|
|
33
|
+
});
|
|
38
34
|
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import type { CorsConfig } from "../types/befly.ts";
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* 设置 CORS 响应头
|
|
5
3
|
* @param req - 请求对象
|
|
6
4
|
* @param config - CORS 配置(可选)
|
|
7
5
|
* @returns CORS 响应头对象
|
|
8
6
|
*/
|
|
9
|
-
export function setCorsOptions(req
|
|
7
|
+
export function setCorsOptions(req, config = {}) {
|
|
10
8
|
const origin = config.origin || "*";
|
|
11
9
|
return {
|
|
12
10
|
"Access-Control-Allow-Origin": origin === "*" ? req.headers.get("origin") || "*" : origin,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Glob } from "bun";
|
|
2
|
+
export type DisableMenuGlobRule = {
|
|
3
|
+
type: "glob";
|
|
4
|
+
raw: string;
|
|
5
|
+
glob: Glob;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* 将 disableMenus 编译为 Bun.Glob 规则(带进程级缓存)。
|
|
9
|
+
* - 仅使用 Bun.Glob 的语法与 API。
|
|
10
|
+
* - 此函数也会做基础的 disableMenus 配置校验(数组/string/非空)。
|
|
11
|
+
*/
|
|
12
|
+
export declare function compileDisableMenuGlobRules(disableMenus: unknown): DisableMenuGlobRule[];
|
|
13
|
+
export declare function isMenuPathDisabledByGlobRules(path: string, rules: DisableMenuGlobRule[]): boolean;
|
|
@@ -1,64 +1,45 @@
|
|
|
1
1
|
import { Glob } from "bun";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
type: "glob";
|
|
5
|
-
raw: string;
|
|
6
|
-
glob: Glob;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
const compiledGlobCache = new Map<string, Glob>();
|
|
10
|
-
|
|
11
|
-
function normalizeDisableMenusRules(disableMenus: unknown): string[] {
|
|
2
|
+
const compiledGlobCache = new Map();
|
|
3
|
+
function normalizeDisableMenusRules(disableMenus) {
|
|
12
4
|
if (typeof disableMenus === "undefined") {
|
|
13
5
|
return [];
|
|
14
6
|
}
|
|
15
|
-
|
|
16
7
|
if (!Array.isArray(disableMenus)) {
|
|
17
8
|
throw new Error("disableMenus 配置不合法:必须是 string[]");
|
|
18
9
|
}
|
|
19
|
-
|
|
20
|
-
const normalized: string[] = [];
|
|
21
|
-
|
|
10
|
+
const normalized = [];
|
|
22
11
|
for (const rawRule of disableMenus) {
|
|
23
12
|
if (typeof rawRule !== "string") {
|
|
24
13
|
throw new Error("disableMenus 配置不合法:数组元素必须是 string");
|
|
25
14
|
}
|
|
26
|
-
|
|
27
15
|
const rule = rawRule.trim();
|
|
28
16
|
if (!rule) {
|
|
29
17
|
throw new Error("disableMenus 配置不合法:不允许空字符串");
|
|
30
18
|
}
|
|
31
|
-
|
|
32
19
|
normalized.push(rule);
|
|
33
20
|
}
|
|
34
|
-
|
|
35
21
|
return normalized;
|
|
36
22
|
}
|
|
37
|
-
|
|
38
|
-
function getOrCreateGlob(pattern: string): Glob {
|
|
23
|
+
function getOrCreateGlob(pattern) {
|
|
39
24
|
const existed = compiledGlobCache.get(pattern);
|
|
40
25
|
if (existed) {
|
|
41
26
|
return existed;
|
|
42
27
|
}
|
|
43
|
-
|
|
44
28
|
const created = new Glob(pattern);
|
|
45
29
|
compiledGlobCache.set(pattern, created);
|
|
46
30
|
return created;
|
|
47
31
|
}
|
|
48
|
-
|
|
49
32
|
/**
|
|
50
33
|
* 将 disableMenus 编译为 Bun.Glob 规则(带进程级缓存)。
|
|
51
34
|
* - 仅使用 Bun.Glob 的语法与 API。
|
|
52
35
|
* - 此函数也会做基础的 disableMenus 配置校验(数组/string/非空)。
|
|
53
36
|
*/
|
|
54
|
-
export function compileDisableMenuGlobRules(disableMenus
|
|
37
|
+
export function compileDisableMenuGlobRules(disableMenus) {
|
|
55
38
|
const normalized = normalizeDisableMenusRules(disableMenus);
|
|
56
39
|
if (normalized.length === 0) {
|
|
57
40
|
return [];
|
|
58
41
|
}
|
|
59
|
-
|
|
60
|
-
const rules: DisableMenuGlobRule[] = [];
|
|
61
|
-
|
|
42
|
+
const rules = [];
|
|
62
43
|
for (const rule of normalized) {
|
|
63
44
|
try {
|
|
64
45
|
const glob = getOrCreateGlob(rule);
|
|
@@ -67,15 +48,14 @@ export function compileDisableMenuGlobRules(disableMenus: unknown): DisableMenuG
|
|
|
67
48
|
raw: rule,
|
|
68
49
|
glob: glob
|
|
69
50
|
});
|
|
70
|
-
}
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
71
53
|
throw new Error(`disableMenus 配置不合法:glob 规则 ${rule} 解析失败:${error?.message || String(error)}`);
|
|
72
54
|
}
|
|
73
55
|
}
|
|
74
|
-
|
|
75
56
|
return rules;
|
|
76
57
|
}
|
|
77
|
-
|
|
78
|
-
export function isMenuPathDisabledByGlobRules(path: string, rules: DisableMenuGlobRule[]): boolean {
|
|
58
|
+
export function isMenuPathDisabledByGlobRules(path, rules) {
|
|
79
59
|
for (const rule of rules) {
|
|
80
60
|
if (rule.glob.match(path)) {
|
|
81
61
|
return true;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface FieldClearOptions {
|
|
2
|
+
pickKeys?: string[];
|
|
3
|
+
omitKeys?: string[];
|
|
4
|
+
keepValues?: any[];
|
|
5
|
+
excludeValues?: any[];
|
|
6
|
+
keepMap?: Record<string, any>;
|
|
7
|
+
}
|
|
8
|
+
export type FieldClearResult<T> = T extends Array<infer U> ? Array<FieldClearResult<U>> : T extends object ? {
|
|
9
|
+
[K in keyof T]?: T[K];
|
|
10
|
+
} : T;
|
|
11
|
+
export declare function fieldClear<T = any>(data: T | T[], options?: FieldClearOptions): FieldClearResult<T>;
|
|
@@ -1,29 +1,15 @@
|
|
|
1
1
|
// fieldClear 工具函数实现
|
|
2
2
|
// 支持 pick/omit/keepValues/excludeValues,处理对象和数组
|
|
3
|
-
|
|
4
|
-
export interface FieldClearOptions {
|
|
5
|
-
pickKeys?: string[]; // 只保留这些字段
|
|
6
|
-
omitKeys?: string[]; // 排除这些字段
|
|
7
|
-
keepValues?: any[]; // 只保留这些值
|
|
8
|
-
excludeValues?: any[]; // 排除这些值
|
|
9
|
-
keepMap?: Record<string, any>; // 强制保留的键值对(优先级最高,忽略 excludeValues)
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export type FieldClearResult<T> = T extends Array<infer U> ? Array<FieldClearResult<U>> : T extends object ? { [K in keyof T]?: T[K] } : T;
|
|
13
|
-
|
|
14
|
-
function isObject(val: unknown): val is Record<string, any> {
|
|
3
|
+
function isObject(val) {
|
|
15
4
|
return val !== null && typeof val === "object" && !Array.isArray(val);
|
|
16
5
|
}
|
|
17
|
-
|
|
18
|
-
function isArray(val: unknown): val is any[] {
|
|
6
|
+
function isArray(val) {
|
|
19
7
|
return Array.isArray(val);
|
|
20
8
|
}
|
|
21
|
-
|
|
22
|
-
export function fieldClear<T = any>(data: T | T[], options: FieldClearOptions = {}): FieldClearResult<T> {
|
|
9
|
+
export function fieldClear(data, options = {}) {
|
|
23
10
|
const { pickKeys, omitKeys, keepValues, excludeValues, keepMap } = options;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
let result: Record<string, any> = {};
|
|
11
|
+
const filterObj = (obj) => {
|
|
12
|
+
let result = {};
|
|
27
13
|
let keys = Object.keys(obj);
|
|
28
14
|
if (pickKeys && pickKeys.length) {
|
|
29
15
|
keys = keys.filter((k) => pickKeys.includes(k));
|
|
@@ -33,7 +19,6 @@ export function fieldClear<T = any>(data: T | T[], options: FieldClearOptions =
|
|
|
33
19
|
}
|
|
34
20
|
for (const key of keys) {
|
|
35
21
|
const value = obj[key];
|
|
36
|
-
|
|
37
22
|
// 1. 优先检查 keepMap
|
|
38
23
|
if (keepMap && key in keepMap) {
|
|
39
24
|
if (Object.is(keepMap[key], value)) {
|
|
@@ -41,12 +26,10 @@ export function fieldClear<T = any>(data: T | T[], options: FieldClearOptions =
|
|
|
41
26
|
continue;
|
|
42
27
|
}
|
|
43
28
|
}
|
|
44
|
-
|
|
45
29
|
// 2. 检查 keepValues (只保留指定值)
|
|
46
30
|
if (keepValues && keepValues.length && !keepValues.includes(value)) {
|
|
47
31
|
continue;
|
|
48
32
|
}
|
|
49
|
-
|
|
50
33
|
// 3. 检查 excludeValues (排除指定值)
|
|
51
34
|
if (excludeValues && excludeValues.length && excludeValues.includes(value)) {
|
|
52
35
|
continue;
|
|
@@ -55,21 +38,20 @@ export function fieldClear<T = any>(data: T | T[], options: FieldClearOptions =
|
|
|
55
38
|
}
|
|
56
39
|
return result;
|
|
57
40
|
};
|
|
58
|
-
|
|
59
41
|
if (isArray(data)) {
|
|
60
|
-
return
|
|
42
|
+
return data
|
|
61
43
|
.map((item) => (isObject(item) ? filterObj(item) : item))
|
|
62
44
|
.filter((item) => {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
45
|
+
if (isObject(item)) {
|
|
46
|
+
// 只保留有内容的对象
|
|
47
|
+
return Object.keys(item).length > 0;
|
|
48
|
+
}
|
|
49
|
+
// 原始值直接保留
|
|
50
|
+
return true;
|
|
51
|
+
});
|
|
70
52
|
}
|
|
71
53
|
if (isObject(data)) {
|
|
72
|
-
return filterObj(data
|
|
54
|
+
return filterObj(data);
|
|
73
55
|
}
|
|
74
|
-
return data
|
|
56
|
+
return data;
|
|
75
57
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 注意:目前策略是“尽量取到 IP”,未做 trustProxy 防伪造控制。
|
|
5
5
|
*/
|
|
6
|
-
export function getClientIp(req
|
|
6
|
+
export function getClientIp(req, server) {
|
|
7
7
|
// 1) 代理/网关常见头(优先取)
|
|
8
8
|
const xForwardedFor = req.headers.get("x-forwarded-for");
|
|
9
9
|
if (typeof xForwardedFor === "string" && xForwardedFor.trim()) {
|
|
@@ -12,27 +12,22 @@ export function getClientIp(req: Request, server?: any): string {
|
|
|
12
12
|
return first.trim();
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
|
-
|
|
16
15
|
const xRealIp = req.headers.get("x-real-ip");
|
|
17
16
|
if (typeof xRealIp === "string" && xRealIp.trim()) {
|
|
18
17
|
return xRealIp.trim();
|
|
19
18
|
}
|
|
20
|
-
|
|
21
19
|
const cfConnectingIp = req.headers.get("cf-connecting-ip");
|
|
22
20
|
if (typeof cfConnectingIp === "string" && cfConnectingIp.trim()) {
|
|
23
21
|
return cfConnectingIp.trim();
|
|
24
22
|
}
|
|
25
|
-
|
|
26
23
|
const xClientIp = req.headers.get("x-client-ip");
|
|
27
24
|
if (typeof xClientIp === "string" && xClientIp.trim()) {
|
|
28
25
|
return xClientIp.trim();
|
|
29
26
|
}
|
|
30
|
-
|
|
31
27
|
const trueClientIp = req.headers.get("true-client-ip");
|
|
32
28
|
if (typeof trueClientIp === "string" && trueClientIp.trim()) {
|
|
33
29
|
return trueClientIp.trim();
|
|
34
30
|
}
|
|
35
|
-
|
|
36
31
|
// 2) 连接层兜底:Bun server.requestIP(req)
|
|
37
32
|
if (server && typeof server.requestIP === "function") {
|
|
38
33
|
const ipInfo = server.requestIP(req);
|
|
@@ -40,6 +35,5 @@ export function getClientIp(req: Request, server?: any): string {
|
|
|
40
35
|
return ipInfo.address.trim();
|
|
41
36
|
}
|
|
42
37
|
}
|
|
43
|
-
|
|
44
38
|
return "unknown";
|
|
45
39
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function importDefault<T>(file: string, defaultValue: T): Promise<T>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* 动态导入模块并优先返回其 default 导出。
|
|
11
|
+
*
|
|
12
|
+
* - import() 报错:返回 defaultValue
|
|
13
|
+
* - default 导出为 null/undefined:返回 defaultValue
|
|
14
|
+
*/
|
|
15
|
+
import { Logger } from "../lib/logger";
|
|
16
|
+
export async function importDefault(file, defaultValue) {
|
|
17
|
+
try {
|
|
18
|
+
const mod = (await import(__rewriteRelativeImportExtension(file)));
|
|
19
|
+
const value = mod?.default;
|
|
20
|
+
if (value === null || value === undefined) {
|
|
21
|
+
return defaultValue;
|
|
22
|
+
}
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
Logger.warn({ err: err, file: file }, "importDefault 导入失败,已回退到默认值");
|
|
27
|
+
return defaultValue;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -1,23 +1,18 @@
|
|
|
1
|
-
import type { Dirent } from "node:fs";
|
|
2
|
-
|
|
3
1
|
import { statSync } from "node:fs";
|
|
4
|
-
|
|
5
2
|
import { join } from "pathe";
|
|
6
|
-
|
|
7
|
-
export const isDirentDirectory = (parentDir: string, entry: Dirent): boolean => {
|
|
3
|
+
export const isDirentDirectory = (parentDir, entry) => {
|
|
8
4
|
if (entry.isDirectory()) {
|
|
9
5
|
return true;
|
|
10
6
|
}
|
|
11
|
-
|
|
12
7
|
// 兼容 Windows 下的 junction / workspace link:Dirent.isDirectory() 可能为 false,但它实际指向目录。
|
|
13
8
|
if (!entry.isSymbolicLink()) {
|
|
14
9
|
return false;
|
|
15
10
|
}
|
|
16
|
-
|
|
17
11
|
try {
|
|
18
12
|
const stats = statSync(join(parentDir, entry.name));
|
|
19
13
|
return stats.isDirectory();
|
|
20
|
-
}
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
21
16
|
return false;
|
|
22
17
|
}
|
|
23
18
|
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { MenuConfig } from "../types/sync";
|
|
2
|
+
import type { AddonInfo } from "./scanAddons";
|
|
3
|
+
type ViewDirMeta = {
|
|
4
|
+
title: string;
|
|
5
|
+
order?: number;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* 清理目录名中的数字后缀
|
|
9
|
+
* 如:login_1 → login, index_2 → index
|
|
10
|
+
*/
|
|
11
|
+
export declare function cleanDirName(name: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* 只取第一个 <script ... setup ...> 块
|
|
14
|
+
*/
|
|
15
|
+
export declare function extractScriptSetupBlock(vueContent: string): string | null;
|
|
16
|
+
/**
|
|
17
|
+
* 从 <script setup> 中提取 definePage({ meta })
|
|
18
|
+
*
|
|
19
|
+
* 简化约束:
|
|
20
|
+
* - 每个页面只有一个 definePage
|
|
21
|
+
* - title 是纯字符串字面量
|
|
22
|
+
* - order 是数字字面量(可选)
|
|
23
|
+
* - 不考虑变量/表达式/多段 meta 组合
|
|
24
|
+
*/
|
|
25
|
+
export declare function extractDefinePageMetaFromScriptSetup(scriptSetup: string): ViewDirMeta | null;
|
|
26
|
+
export declare function scanViewsDirToMenuConfigs(viewsDir: string, prefix: string, parentPath?: string): Promise<MenuConfig[]>;
|
|
27
|
+
export declare function getParentPath(path: string): string;
|
|
28
|
+
export declare function loadMenuConfigs(addons: AddonInfo[]): Promise<MenuConfig[]>;
|
|
29
|
+
export {};
|