befly 3.14.2 → 3.15.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.
- package/dist/befly.config.js +1 -1
- package/dist/befly.js +618 -209
- package/dist/befly.min.js +13 -13
- package/dist/checks/checkApi.d.ts +1 -1
- package/dist/checks/checkApi.js +64 -24
- package/dist/checks/checkHook.js +20 -14
- package/dist/checks/checkPlugin.js +20 -14
- package/dist/checks/checkTable.js +6 -3
- package/dist/hooks/permission.js +1 -1
- package/dist/lib/cipher.js +3 -4
- package/dist/lib/connect.js +2 -1
- package/dist/lib/dbDialect.d.ts +4 -4
- package/dist/lib/dbDialect.js +3 -12
- package/dist/lib/dbHelper.d.ts +8 -3
- package/dist/lib/dbHelper.js +85 -35
- package/dist/lib/dbUtils.js +2 -2
- package/dist/lib/logger.d.ts +6 -11
- package/dist/lib/logger.js +15 -10
- package/dist/lib/sqlBuilder.js +10 -2
- package/dist/lib/validator.d.ts +3 -3
- package/dist/lib/validator.js +59 -7
- package/dist/loader/loadApis.js +38 -6
- package/dist/loader/loadHooks.js +12 -5
- package/dist/loader/loadPlugins.js +13 -6
- package/dist/plugins/tool.d.ts +11 -9
- package/dist/plugins/tool.js +1 -1
- package/dist/sync/syncApi.d.ts +2 -2
- package/dist/sync/syncApi.js +23 -11
- package/dist/sync/syncDev.js +2 -2
- package/dist/sync/syncMenu.js +3 -2
- package/dist/sync/syncTable.d.ts +22 -26
- package/dist/sync/syncTable.js +114 -25
- package/dist/types/api.d.ts +11 -10
- package/dist/types/befly.d.ts +17 -11
- package/dist/types/common.d.ts +23 -6
- package/dist/types/context.d.ts +7 -3
- package/dist/types/database.d.ts +50 -15
- package/dist/types/jwt.d.ts +3 -2
- package/dist/types/logger.d.ts +24 -7
- package/dist/types/sync.d.ts +7 -7
- package/dist/types/validate.d.ts +12 -4
- package/dist/utils/convertBigIntFields.d.ts +2 -1
- package/dist/utils/convertBigIntFields.js +3 -12
- package/dist/utils/isDirentDirectory.d.ts +2 -1
- package/dist/utils/loadMenuConfigs.d.ts +1 -1
- package/dist/utils/loadMenuConfigs.js +11 -3
- package/dist/utils/mergeAndConcat.d.ts +1 -1
- package/dist/utils/mergeAndConcat.js +22 -17
- package/dist/utils/normalizeFieldDefinition.d.ts +2 -1
- package/dist/utils/scanCoreBuiltins.js +9 -5
- package/dist/utils/scanFiles.d.ts +2 -2
- package/dist/utils/scanFiles.js +1 -1
- package/dist/utils/sortModules.js +8 -1
- package/dist/utils/sqlParams.d.ts +10 -0
- package/dist/utils/sqlParams.js +78 -0
- package/dist/utils/sqlResult.d.ts +5 -0
- package/dist/utils/sqlResult.js +7 -0
- package/dist/utils/util.d.ts +7 -6
- package/dist/utils/util.js +8 -5
- package/package.json +2 -2
package/dist/types/befly.d.ts
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import type { CacheHelper } from "./cache";
|
|
5
5
|
import type { CipherStatic } from "./cipher";
|
|
6
|
-
import type {
|
|
6
|
+
import type { JsonValue } from "./common";
|
|
7
|
+
import type { RequestContext } from "./context";
|
|
7
8
|
import type { DbHelper } from "./database";
|
|
8
9
|
import type { Jwt } from "./jwt";
|
|
9
10
|
import type { Logger, LoggerConfig } from "./logger";
|
|
@@ -161,15 +162,15 @@ export interface BeflyOptions {
|
|
|
161
162
|
* Addon 运行时配置
|
|
162
163
|
* 按 addon 名称分组,如 addons.admin.email
|
|
163
164
|
*/
|
|
164
|
-
addons?: Record<string, Record<string,
|
|
165
|
+
addons?: Record<string, Record<string, JsonValue | undefined>>;
|
|
165
166
|
/** 其他插件配置 */
|
|
166
|
-
[key: string]:
|
|
167
|
+
[key: string]: unknown;
|
|
167
168
|
}
|
|
168
169
|
/**
|
|
169
170
|
* Befly 应用上下文
|
|
170
171
|
* 包含所有插件挂载的实例
|
|
171
172
|
*/
|
|
172
|
-
export interface BeflyContext
|
|
173
|
+
export interface BeflyContext {
|
|
173
174
|
/** 数据库助手 */
|
|
174
175
|
db: DbHelper;
|
|
175
176
|
/** Redis 助手 */
|
|
@@ -180,16 +181,21 @@ export interface BeflyContext extends KeyValue {
|
|
|
180
181
|
cache: CacheHelper;
|
|
181
182
|
/** 工具函数 */
|
|
182
183
|
tool: {
|
|
183
|
-
Yes: (msg: string, data?:
|
|
184
|
+
Yes: <TData extends JsonValue = JsonValue, TOther extends Record<string, JsonValue | undefined> = Record<string, JsonValue | undefined>>(msg: string, data?: TData, other?: TOther) => {
|
|
184
185
|
code: 0;
|
|
185
186
|
msg: string;
|
|
186
|
-
data:
|
|
187
|
-
};
|
|
188
|
-
No: (msg: string, data?:
|
|
187
|
+
data: TData;
|
|
188
|
+
} & TOther;
|
|
189
|
+
No: <TData extends JsonValue = JsonValue, TOther extends Record<string, JsonValue | undefined> = Record<string, JsonValue | undefined>>(msg: string, data?: TData, other?: TOther) => {
|
|
189
190
|
code: 1;
|
|
190
191
|
msg: string;
|
|
191
|
-
data:
|
|
192
|
-
};
|
|
192
|
+
data: TData;
|
|
193
|
+
} & TOther;
|
|
194
|
+
Raw: (ctx: RequestContext, data: JsonValue | string, options?: {
|
|
195
|
+
status?: number;
|
|
196
|
+
contentType?: string;
|
|
197
|
+
headers?: Record<string, string>;
|
|
198
|
+
}) => Response;
|
|
193
199
|
};
|
|
194
200
|
/** 加密解密 */
|
|
195
201
|
cipher: CipherStatic;
|
|
@@ -201,7 +207,7 @@ export interface BeflyContext extends KeyValue {
|
|
|
201
207
|
env: BeflyRuntimeEnv;
|
|
202
208
|
/** 组件插件:addon_{addonName}_{pluginName} */
|
|
203
209
|
/** 项目插件:app_{pluginName} */
|
|
204
|
-
[key: string]:
|
|
210
|
+
[key: string]: unknown;
|
|
205
211
|
}
|
|
206
212
|
/**
|
|
207
213
|
* Validator 静态类(注入到 ctx 的用法)
|
package/dist/types/common.d.ts
CHANGED
|
@@ -2,14 +2,22 @@
|
|
|
2
2
|
* Befly 框架通用类型定义
|
|
3
3
|
* 框架核心通用类型定义
|
|
4
4
|
*/
|
|
5
|
+
/**
|
|
6
|
+
* JSON 可序列化值(用于对外类型的兜底数据类型)
|
|
7
|
+
*/
|
|
8
|
+
export type JsonPrimitive = string | number | boolean | null;
|
|
9
|
+
export interface JsonObject {
|
|
10
|
+
[key: string]: JsonValue | undefined;
|
|
11
|
+
}
|
|
12
|
+
export type JsonValue = JsonPrimitive | JsonObject | JsonValue[];
|
|
5
13
|
/**
|
|
6
14
|
* SQL 值类型
|
|
7
15
|
*/
|
|
8
|
-
export type SqlValue = string | number | boolean | null | Date |
|
|
16
|
+
export type SqlValue = string | number | boolean | null | Date | JsonObject | JsonValue[];
|
|
9
17
|
/**
|
|
10
18
|
* 通用键值对类型
|
|
11
19
|
*/
|
|
12
|
-
export type KeyValue<T =
|
|
20
|
+
export type KeyValue<T = JsonValue> = Record<string, T>;
|
|
13
21
|
/**
|
|
14
22
|
* WHERE 条件操作符
|
|
15
23
|
*/
|
|
@@ -17,7 +25,16 @@ export type WhereOperator = "$eq" | "$ne" | "$not" | "$gt" | "$gte" | "$lt" | "$
|
|
|
17
25
|
/**
|
|
18
26
|
* WHERE 条件类型
|
|
19
27
|
*/
|
|
20
|
-
export
|
|
28
|
+
export interface WhereOperatorObject {
|
|
29
|
+
[op: string]: SqlValue | SqlValue[] | undefined;
|
|
30
|
+
}
|
|
31
|
+
export type WhereFieldValue = SqlValue | SqlValue[] | WhereOperatorObject | WhereConditions;
|
|
32
|
+
export type WhereEntryValue = WhereFieldValue | WhereConditions[];
|
|
33
|
+
export interface WhereConditions {
|
|
34
|
+
$and?: WhereConditions[];
|
|
35
|
+
$or?: WhereConditions[];
|
|
36
|
+
[key: string]: WhereEntryValue | undefined;
|
|
37
|
+
}
|
|
21
38
|
/**
|
|
22
39
|
* 排序方向
|
|
23
40
|
*/
|
|
@@ -47,7 +64,7 @@ export type UpdateData = Record<string, SqlValue>;
|
|
|
47
64
|
/**
|
|
48
65
|
* 任意对象类型
|
|
49
66
|
*/
|
|
50
|
-
export type AnyObject =
|
|
67
|
+
export type AnyObject = JsonObject;
|
|
51
68
|
/**
|
|
52
69
|
* 字段规则字符串(已废弃,保留用于兼容)
|
|
53
70
|
* 格式: "字段名|类型|最小值|最大值|默认值|是否索引|正则约束"
|
|
@@ -68,7 +85,7 @@ export interface ParsedFieldRule {
|
|
|
68
85
|
type: "string" | "number" | "text" | "array_string" | "array_text";
|
|
69
86
|
min: number | null;
|
|
70
87
|
max: number | null;
|
|
71
|
-
default:
|
|
88
|
+
default: JsonValue | null;
|
|
72
89
|
index: 0 | 1;
|
|
73
90
|
regex: string | null;
|
|
74
91
|
}
|
|
@@ -95,7 +112,7 @@ export interface JoinOption {
|
|
|
95
112
|
/**
|
|
96
113
|
* 工具函数返回类型
|
|
97
114
|
*/
|
|
98
|
-
export interface ToolResponse<T =
|
|
115
|
+
export interface ToolResponse<T = JsonValue> {
|
|
99
116
|
success: boolean;
|
|
100
117
|
data?: T;
|
|
101
118
|
error?: string;
|
package/dist/types/context.d.ts
CHANGED
|
@@ -2,16 +2,20 @@
|
|
|
2
2
|
* 请求上下文类型定义
|
|
3
3
|
*/
|
|
4
4
|
import type { ApiRoute } from "./api";
|
|
5
|
+
import type { JsonValue } from "./common";
|
|
6
|
+
import type { JwtPayload } from "./jwt";
|
|
7
|
+
export type RequestUser = Partial<JwtPayload>;
|
|
8
|
+
export type RequestResult = Response | JsonValue;
|
|
5
9
|
/**
|
|
6
10
|
* 请求上下文接口
|
|
7
11
|
*/
|
|
8
|
-
export interface RequestContext<TBody = Record<string,
|
|
12
|
+
export interface RequestContext<TBody = Record<string, JsonValue>> {
|
|
9
13
|
/** 请求方法 (GET/POST) */
|
|
10
14
|
method: string;
|
|
11
15
|
/** 请求体参数 */
|
|
12
16
|
body: TBody;
|
|
13
17
|
/** 用户信息 */
|
|
14
|
-
user:
|
|
18
|
+
user: RequestUser;
|
|
15
19
|
/** 原始请求对象 */
|
|
16
20
|
req: Request;
|
|
17
21
|
/** 请求开始时间(毫秒) */
|
|
@@ -31,5 +35,5 @@ export interface RequestContext<TBody = Record<string, any>> {
|
|
|
31
35
|
/** 响应对象(如果设置了此属性,将直接返回该响应) */
|
|
32
36
|
response?: Response;
|
|
33
37
|
/** 原始处理结果(未转换为 Response 对象前) */
|
|
34
|
-
result?:
|
|
38
|
+
result?: RequestResult;
|
|
35
39
|
}
|
package/dist/types/database.d.ts
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
* 数据库操作相关类型定义
|
|
3
3
|
*/
|
|
4
4
|
import type { JoinOption, SqlValue, WhereConditions } from "./common";
|
|
5
|
+
/**
|
|
6
|
+
* 表名到行类型的映射(项目侧可通过 declaration merging 扩展)。
|
|
7
|
+
*
|
|
8
|
+
* 用法(项目侧):
|
|
9
|
+
* declare module "befly/types/database" {
|
|
10
|
+
* interface DbRowMap {
|
|
11
|
+
* user: { id: number; nickname?: string };
|
|
12
|
+
* }
|
|
13
|
+
* }
|
|
14
|
+
*/
|
|
15
|
+
export interface DbRowMap {
|
|
16
|
+
}
|
|
17
|
+
export type DbTableName = keyof DbRowMap & string;
|
|
5
18
|
/**
|
|
6
19
|
* 数据库类型
|
|
7
20
|
*/
|
|
@@ -63,7 +76,7 @@ export interface DeleteOptions {
|
|
|
63
76
|
*/
|
|
64
77
|
export interface SqlInfo {
|
|
65
78
|
sql: string;
|
|
66
|
-
params:
|
|
79
|
+
params: SqlValue[];
|
|
67
80
|
duration: number;
|
|
68
81
|
}
|
|
69
82
|
/**
|
|
@@ -76,14 +89,15 @@ export interface ListSql {
|
|
|
76
89
|
/**
|
|
77
90
|
* 统一返回结构
|
|
78
91
|
*/
|
|
79
|
-
export type
|
|
92
|
+
export type DbUnknownRow = Record<string, SqlValue>;
|
|
93
|
+
export type DbResult<TData = DbUnknownRow, TSql = SqlInfo> = {
|
|
80
94
|
data: TData;
|
|
81
95
|
sql: TSql;
|
|
82
96
|
};
|
|
83
97
|
/**
|
|
84
98
|
* 分页结果
|
|
85
99
|
*/
|
|
86
|
-
export interface DbPageResult<TItem =
|
|
100
|
+
export interface DbPageResult<TItem = DbUnknownRow> {
|
|
87
101
|
lists: TItem[];
|
|
88
102
|
total: number;
|
|
89
103
|
page: number;
|
|
@@ -93,14 +107,14 @@ export interface DbPageResult<TItem = unknown> {
|
|
|
93
107
|
/**
|
|
94
108
|
* 不分页结果(带 total)
|
|
95
109
|
*/
|
|
96
|
-
export interface DbListResult<TItem =
|
|
110
|
+
export interface DbListResult<TItem = DbUnknownRow> {
|
|
97
111
|
lists: TItem[];
|
|
98
112
|
total: number;
|
|
99
113
|
}
|
|
100
114
|
/**
|
|
101
115
|
* 事务回调
|
|
102
116
|
*/
|
|
103
|
-
export type TransactionCallback<TResult =
|
|
117
|
+
export type TransactionCallback<TResult = void, TDb = DbHelper> = (db: TDb) => Promise<TResult>;
|
|
104
118
|
/**
|
|
105
119
|
* DbHelper 公开接口(类型层)。
|
|
106
120
|
*
|
|
@@ -109,13 +123,35 @@ export type TransactionCallback<TResult = unknown, TDb = unknown> = (db: TDb) =>
|
|
|
109
123
|
*/
|
|
110
124
|
export interface DbHelper {
|
|
111
125
|
tableExists(tableName: string): Promise<DbResult<boolean>>;
|
|
126
|
+
getCount<TTable extends DbTableName>(options: Omit<QueryOptions, "fields" | "page" | "limit" | "orderBy" | "table"> & {
|
|
127
|
+
table: TTable;
|
|
128
|
+
}): Promise<DbResult<number>>;
|
|
112
129
|
getCount(options: Omit<QueryOptions, "fields" | "page" | "limit" | "orderBy">): Promise<DbResult<number>>;
|
|
113
|
-
getOne<
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
130
|
+
getOne<TTable extends DbTableName>(options: Omit<QueryOptions, "table"> & {
|
|
131
|
+
table: TTable;
|
|
132
|
+
}): Promise<DbResult<DbRowMap[TTable]>>;
|
|
133
|
+
getOne<TItem = DbUnknownRow>(options: QueryOptions): Promise<DbResult<TItem>>;
|
|
134
|
+
getDetail<TTable extends DbTableName>(options: Omit<QueryOptions, "table"> & {
|
|
135
|
+
table: TTable;
|
|
136
|
+
}): Promise<DbResult<DbRowMap[TTable]>>;
|
|
137
|
+
getDetail<TItem = DbUnknownRow>(options: QueryOptions): Promise<DbResult<TItem>>;
|
|
138
|
+
getList<TTable extends DbTableName>(options: Omit<QueryOptions, "table"> & {
|
|
139
|
+
table: TTable;
|
|
140
|
+
}): Promise<DbResult<DbPageResult<DbRowMap[TTable]>, ListSql>>;
|
|
141
|
+
getList<TItem = DbUnknownRow>(options: QueryOptions): Promise<DbResult<DbPageResult<TItem>, ListSql>>;
|
|
142
|
+
getAll<TTable extends DbTableName>(options: Omit<QueryOptions, "table" | "page" | "limit"> & {
|
|
143
|
+
table: TTable;
|
|
144
|
+
}): Promise<DbResult<DbListResult<DbRowMap[TTable]>, ListSql>>;
|
|
145
|
+
getAll<TItem = DbUnknownRow>(options: Omit<QueryOptions, "page" | "limit">): Promise<DbResult<DbListResult<TItem>, ListSql>>;
|
|
146
|
+
exists<TTable extends DbTableName>(options: Omit<QueryOptions, "fields" | "orderBy" | "page" | "limit" | "table"> & {
|
|
147
|
+
table: TTable;
|
|
148
|
+
}): Promise<DbResult<boolean>>;
|
|
117
149
|
exists(options: Omit<QueryOptions, "fields" | "orderBy" | "page" | "limit">): Promise<DbResult<boolean>>;
|
|
118
|
-
getFieldValue<
|
|
150
|
+
getFieldValue<TTable extends DbTableName, TField extends keyof DbRowMap[TTable] & string>(options: Omit<QueryOptions, "fields" | "table"> & {
|
|
151
|
+
table: TTable;
|
|
152
|
+
field: TField;
|
|
153
|
+
}): Promise<DbResult<DbRowMap[TTable][TField] | null>>;
|
|
154
|
+
getFieldValue<TValue = SqlValue>(options: Omit<QueryOptions, "fields"> & {
|
|
119
155
|
field: string;
|
|
120
156
|
}): Promise<DbResult<TValue | null>>;
|
|
121
157
|
insData<TInsert extends Record<string, SqlValue> = Record<string, SqlValue>>(options: Omit<InsertOptions, "data"> & {
|
|
@@ -125,17 +161,16 @@ export interface DbHelper {
|
|
|
125
161
|
updData(options: UpdateOptions): Promise<DbResult<number>>;
|
|
126
162
|
updBatch(table: string, dataList: Array<{
|
|
127
163
|
id: number;
|
|
128
|
-
data: Record<string,
|
|
164
|
+
data: Record<string, SqlValue>;
|
|
129
165
|
}>): Promise<DbResult<number>>;
|
|
130
166
|
delData(options: DeleteOptions): Promise<DbResult<number>>;
|
|
131
167
|
delForce(options: Omit<DeleteOptions, "hard">): Promise<DbResult<number>>;
|
|
132
168
|
delForceBatch(table: string, ids: number[]): Promise<DbResult<number>>;
|
|
133
169
|
enableData(options: Omit<DeleteOptions, "hard">): Promise<DbResult<number>>;
|
|
134
170
|
disableData(options: Omit<DeleteOptions, "hard">): Promise<DbResult<number>>;
|
|
135
|
-
query<TResult =
|
|
136
|
-
unsafe<TResult =
|
|
137
|
-
trans<TResult =
|
|
171
|
+
query<TResult = DbUnknownRow[]>(sql: string, params?: SqlValue[]): Promise<DbResult<TResult>>;
|
|
172
|
+
unsafe<TResult = DbUnknownRow[]>(sqlStr: string, params?: SqlValue[]): Promise<DbResult<TResult>>;
|
|
173
|
+
trans<TResult = void>(callback: TransactionCallback<TResult, DbHelper>): Promise<TResult>;
|
|
138
174
|
increment(table: string, field: string, where: WhereConditions, value?: number): Promise<DbResult<number>>;
|
|
139
175
|
decrement(table: string, field: string, where: WhereConditions, value?: number): Promise<DbResult<number>>;
|
|
140
|
-
[key: string]: unknown;
|
|
141
176
|
}
|
package/dist/types/jwt.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* JWT 相关类型定义
|
|
3
3
|
*/
|
|
4
|
+
import type { JsonValue } from "./common";
|
|
4
5
|
/**
|
|
5
6
|
* JWT Payload 类型
|
|
6
7
|
*/
|
|
@@ -18,7 +19,7 @@ export interface JwtPayload {
|
|
|
18
19
|
/** 签发时间 */
|
|
19
20
|
iat?: number;
|
|
20
21
|
/** 其他字段 */
|
|
21
|
-
[key: string]:
|
|
22
|
+
[key: string]: JsonValue | undefined;
|
|
22
23
|
}
|
|
23
24
|
/**
|
|
24
25
|
* JWT header(最常用字段)
|
|
@@ -27,7 +28,7 @@ export interface JwtHeader {
|
|
|
27
28
|
alg?: string;
|
|
28
29
|
typ?: string;
|
|
29
30
|
kid?: string;
|
|
30
|
-
[key: string]:
|
|
31
|
+
[key: string]: JsonValue | undefined;
|
|
31
32
|
}
|
|
32
33
|
/**
|
|
33
34
|
* sign() 选项(映射 fast-jwt 的 signer 参数)
|
package/dist/types/logger.d.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 说明:这里的类型需要与 core/runtime 的 logger 实现保持一致(大量配置项以 0/1 表示开关)。
|
|
5
5
|
*/
|
|
6
|
+
import type { JsonValue } from "./common";
|
|
6
7
|
export type LoggerFlag = 0 | 1;
|
|
7
8
|
/**
|
|
8
9
|
* Logger 插件配置
|
|
@@ -32,14 +33,30 @@ export interface LoggerConfig {
|
|
|
32
33
|
excludeFields?: string[];
|
|
33
34
|
}
|
|
34
35
|
export type LogLevelName = "debug" | "info" | "warn" | "error";
|
|
36
|
+
/**
|
|
37
|
+
* LoggerRecord 允许出现的值类型。
|
|
38
|
+
* - JsonValue:可序列化数据
|
|
39
|
+
* - Error:允许直接传入错误对象(运行时会清洗成可序列化结构)
|
|
40
|
+
* - object:允许传入非 plain object(如 Date/Map/Set/自定义 class 实例),由运行时做安全预览/截断
|
|
41
|
+
*/
|
|
42
|
+
export type LoggerRecordValue = JsonValue | Error | object;
|
|
35
43
|
export type LoggerRecord = {
|
|
36
44
|
/** 文本消息(推荐直接放在 record 里) */
|
|
37
45
|
msg?: string;
|
|
38
46
|
/** 错误对象(会在运行时被清洗为可序列化结构) */
|
|
39
|
-
err?:
|
|
47
|
+
err?: Error | JsonValue;
|
|
40
48
|
/** 其他自定义字段 */
|
|
41
|
-
[key: string]:
|
|
49
|
+
[key: string]: LoggerRecordValue | undefined;
|
|
42
50
|
};
|
|
51
|
+
/**
|
|
52
|
+
* Logger 的可替换 sink(用于测试 mock)。
|
|
53
|
+
*/
|
|
54
|
+
export interface LoggerSink {
|
|
55
|
+
info(record: LoggerRecord): void;
|
|
56
|
+
warn(record: LoggerRecord): void;
|
|
57
|
+
error(record: LoggerRecord): void;
|
|
58
|
+
debug(record: LoggerRecord): void;
|
|
59
|
+
}
|
|
43
60
|
/**
|
|
44
61
|
* Logger 接口(类型层)。
|
|
45
62
|
*
|
|
@@ -52,12 +69,12 @@ export interface Logger {
|
|
|
52
69
|
* - plain object({})会作为 record 写入
|
|
53
70
|
* - 其他任何类型会被包装成对象后写入(例如 { msg: "..." } 或 { value: ... })
|
|
54
71
|
*/
|
|
55
|
-
info(input: unknown):
|
|
56
|
-
warn(input: unknown):
|
|
57
|
-
error(input: unknown):
|
|
58
|
-
debug(input: unknown):
|
|
72
|
+
info(input: unknown): void;
|
|
73
|
+
warn(input: unknown): void;
|
|
74
|
+
error(input: unknown): void;
|
|
75
|
+
debug(input: unknown): void;
|
|
59
76
|
configure(cfg: LoggerConfig): void;
|
|
60
|
-
setMock(mock:
|
|
77
|
+
setMock(mock: LoggerSink | null): void;
|
|
61
78
|
/**
|
|
62
79
|
* 将当前 buffer 尽快刷入 sink(不会关闭文件句柄)。
|
|
63
80
|
*
|
package/dist/types/sync.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* 数据同步相关类型定义
|
|
3
3
|
*/
|
|
4
4
|
import type { BeflyContext } from "./befly";
|
|
5
|
-
import type { KeyValue } from "./common";
|
|
5
|
+
import type { JsonValue, KeyValue } from "./common";
|
|
6
6
|
/**
|
|
7
7
|
* 同步结果
|
|
8
8
|
*/
|
|
@@ -27,7 +27,7 @@ export interface SyncOptions {
|
|
|
27
27
|
/** 同步批次大小 */
|
|
28
28
|
batchSize?: number;
|
|
29
29
|
/** 其他选项 */
|
|
30
|
-
[key: string]:
|
|
30
|
+
[key: string]: JsonValue | undefined;
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
33
|
* 同步器接口
|
|
@@ -54,7 +54,7 @@ export interface MenuConfig {
|
|
|
54
54
|
sort?: number;
|
|
55
55
|
parentPath?: string;
|
|
56
56
|
children?: MenuConfig[];
|
|
57
|
-
[key: string]:
|
|
57
|
+
[key: string]: JsonValue | undefined;
|
|
58
58
|
}
|
|
59
59
|
export interface SyncApiItem {
|
|
60
60
|
type?: "api" | string;
|
|
@@ -64,7 +64,7 @@ export interface SyncApiItem {
|
|
|
64
64
|
path: string;
|
|
65
65
|
parentPath: string;
|
|
66
66
|
addonName: string;
|
|
67
|
-
[key: string]:
|
|
67
|
+
[key: string]: JsonValue | undefined;
|
|
68
68
|
}
|
|
69
69
|
export interface ColumnInfo {
|
|
70
70
|
type: string;
|
|
@@ -72,14 +72,14 @@ export interface ColumnInfo {
|
|
|
72
72
|
length: number | null;
|
|
73
73
|
max: number | null;
|
|
74
74
|
nullable: boolean;
|
|
75
|
-
defaultValue:
|
|
75
|
+
defaultValue: JsonValue;
|
|
76
76
|
comment: string | null;
|
|
77
77
|
}
|
|
78
78
|
export type IndexInfo = Record<string, string[]>;
|
|
79
79
|
export interface FieldChange {
|
|
80
80
|
type: string;
|
|
81
|
-
current:
|
|
82
|
-
expected:
|
|
81
|
+
current: JsonValue;
|
|
82
|
+
expected: JsonValue;
|
|
83
83
|
}
|
|
84
84
|
export interface TablePlan {
|
|
85
85
|
changed: boolean;
|
package/dist/types/validate.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 数据验证相关类型定义
|
|
3
3
|
*/
|
|
4
|
+
import type { JsonValue } from "./common";
|
|
4
5
|
/**
|
|
5
6
|
* 字段类型
|
|
6
7
|
*/
|
|
@@ -27,7 +28,7 @@ export interface FieldDefinition {
|
|
|
27
28
|
* 默认值。
|
|
28
29
|
* - 缺省默认:null(表示字段未提供默认值)
|
|
29
30
|
*/
|
|
30
|
-
default?:
|
|
31
|
+
default?: JsonValue | null;
|
|
31
32
|
/**
|
|
32
33
|
* 字段描述。
|
|
33
34
|
* - 缺省默认:""(空字符串)
|
|
@@ -78,7 +79,7 @@ export interface ValidateResult {
|
|
|
78
79
|
* single(value, fieldDef) 的返回结构
|
|
79
80
|
*/
|
|
80
81
|
export interface SingleResult {
|
|
81
|
-
value:
|
|
82
|
+
value: JsonValue | null;
|
|
82
83
|
error: string | null;
|
|
83
84
|
}
|
|
84
85
|
/**
|
|
@@ -89,6 +90,13 @@ export interface SingleResult {
|
|
|
89
90
|
* - `Validator.single(value, fieldDef)`
|
|
90
91
|
*/
|
|
91
92
|
export interface ValidatorStatic {
|
|
92
|
-
|
|
93
|
-
|
|
93
|
+
/**
|
|
94
|
+
* 推荐签名:正常业务使用。
|
|
95
|
+
*/
|
|
96
|
+
validate(data: Record<string, JsonValue>, rules: TableDefinition, required?: string[]): ValidateResult;
|
|
97
|
+
/**
|
|
98
|
+
* 宽签名:用于边界输入(例如测试传入非法参数)——实现内部会做运行时校验。
|
|
99
|
+
*/
|
|
100
|
+
validate(data: unknown, rules: unknown, required?: string[]): ValidateResult;
|
|
101
|
+
single(value: unknown, fieldDef: FieldDefinition): SingleResult;
|
|
94
102
|
}
|
|
@@ -8,4 +8,5 @@
|
|
|
8
8
|
* 2. 所有以 'Id' 或 '_id' 结尾的字段会被自动转换
|
|
9
9
|
* 3. 所有以 'At' 或 '_at' 结尾的字段会被自动转换(时间戳字段)
|
|
10
10
|
*/
|
|
11
|
-
export declare function convertBigIntFields<T
|
|
11
|
+
export declare function convertBigIntFields<T extends Record<string, unknown> = Record<string, unknown>>(arr: T[], fields?: readonly string[]): T[];
|
|
12
|
+
export declare function convertBigIntFields<T>(arr: T, fields?: readonly string[]): T;
|
|
@@ -1,20 +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
1
|
export function convertBigIntFields(arr, fields = ["id", "pid", "sort"]) {
|
|
12
2
|
if (!arr || !Array.isArray(arr)) {
|
|
13
3
|
return arr;
|
|
14
4
|
}
|
|
15
5
|
return arr.map((item) => {
|
|
6
|
+
const source = item;
|
|
16
7
|
const converted = {};
|
|
17
|
-
for (const [key, value] of Object.entries(
|
|
8
|
+
for (const [key, value] of Object.entries(source)) {
|
|
18
9
|
converted[key] = value;
|
|
19
10
|
}
|
|
20
11
|
for (const [key, value] of Object.entries(converted)) {
|
|
@@ -24,7 +15,7 @@ export function convertBigIntFields(arr, fields = ["id", "pid", "sort"]) {
|
|
|
24
15
|
const shouldConvert = fields.includes(key) || key.endsWith("Id") || key.endsWith("_id") || key.endsWith("At") || key.endsWith("_at");
|
|
25
16
|
if (shouldConvert && typeof value === "string") {
|
|
26
17
|
const num = Number(value);
|
|
27
|
-
if (!isNaN(num)) {
|
|
18
|
+
if (!Number.isNaN(num)) {
|
|
28
19
|
converted[key] = num;
|
|
29
20
|
}
|
|
30
21
|
}
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
import type { Dirent } from "node:fs";
|
|
2
|
-
export
|
|
2
|
+
export type DirentLike = Pick<Dirent, "name" | "isDirectory" | "isSymbolicLink">;
|
|
3
|
+
export declare const isDirentDirectory: (parentDir: string, entry: DirentLike) => boolean;
|
|
@@ -4,7 +4,7 @@ type ViewDirMeta = {
|
|
|
4
4
|
title: string;
|
|
5
5
|
order?: number;
|
|
6
6
|
};
|
|
7
|
-
export declare function normalizeViewDirMeta(input:
|
|
7
|
+
export declare function normalizeViewDirMeta(input: unknown): ViewDirMeta | null;
|
|
8
8
|
export declare function scanViewsDirToMenuConfigs(viewsDir: string, prefix: string, parentPath?: string): Promise<MenuConfig[]>;
|
|
9
9
|
export declare function getParentPath(path: string): string;
|
|
10
10
|
export declare function loadMenuConfigs(addons: AddonInfo[]): Promise<MenuConfig[]>;
|
|
@@ -8,12 +8,20 @@ export function normalizeViewDirMeta(input) {
|
|
|
8
8
|
if (!input || typeof input !== "object") {
|
|
9
9
|
return null;
|
|
10
10
|
}
|
|
11
|
-
|
|
11
|
+
const record = input;
|
|
12
|
+
const title = record["title"];
|
|
13
|
+
if (typeof title !== "string" || !title) {
|
|
12
14
|
return null;
|
|
13
15
|
}
|
|
14
|
-
const
|
|
16
|
+
const orderRaw = record["order"];
|
|
17
|
+
const order = typeof orderRaw === "number" && Number.isFinite(orderRaw) && Number.isInteger(orderRaw) && orderRaw >= 0 ? orderRaw : undefined;
|
|
18
|
+
if (order === undefined) {
|
|
19
|
+
return {
|
|
20
|
+
title: title
|
|
21
|
+
};
|
|
22
|
+
}
|
|
15
23
|
return {
|
|
16
|
-
title:
|
|
24
|
+
title: title,
|
|
17
25
|
order: order
|
|
18
26
|
};
|
|
19
27
|
}
|
|
@@ -9,8 +9,9 @@ function cloneDeepLoose(value) {
|
|
|
9
9
|
}
|
|
10
10
|
if (isPlainObject(value)) {
|
|
11
11
|
const out = {};
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
const record = value;
|
|
13
|
+
for (const key of Object.keys(record)) {
|
|
14
|
+
out[key] = cloneDeepLoose(record[key]);
|
|
14
15
|
}
|
|
15
16
|
return out;
|
|
16
17
|
}
|
|
@@ -21,18 +22,28 @@ function mergeInto(target, source) {
|
|
|
21
22
|
return target;
|
|
22
23
|
}
|
|
23
24
|
if (Array.isArray(target) && Array.isArray(source)) {
|
|
25
|
+
const nextArr = [];
|
|
26
|
+
for (const item of target) {
|
|
27
|
+
nextArr.push(cloneDeepLoose(item));
|
|
28
|
+
}
|
|
24
29
|
for (const item of source) {
|
|
25
|
-
|
|
30
|
+
nextArr.push(cloneDeepLoose(item));
|
|
26
31
|
}
|
|
27
|
-
return
|
|
32
|
+
return nextArr;
|
|
28
33
|
}
|
|
29
34
|
if (isPlainObject(target) && isPlainObject(source)) {
|
|
30
|
-
|
|
31
|
-
|
|
35
|
+
const targetRecord = target;
|
|
36
|
+
const sourceRecord = source;
|
|
37
|
+
const out = {};
|
|
38
|
+
for (const key of Object.keys(targetRecord)) {
|
|
39
|
+
out[key] = cloneDeepLoose(targetRecord[key]);
|
|
40
|
+
}
|
|
41
|
+
for (const key of Object.keys(sourceRecord)) {
|
|
42
|
+
const srcVal = sourceRecord[key];
|
|
32
43
|
if (srcVal === undefined) {
|
|
33
44
|
continue;
|
|
34
45
|
}
|
|
35
|
-
const curVal =
|
|
46
|
+
const curVal = out[key];
|
|
36
47
|
if (Array.isArray(curVal) && Array.isArray(srcVal)) {
|
|
37
48
|
const nextArr = [];
|
|
38
49
|
for (const item of curVal) {
|
|
@@ -41,25 +52,19 @@ function mergeInto(target, source) {
|
|
|
41
52
|
for (const item of srcVal) {
|
|
42
53
|
nextArr.push(cloneDeepLoose(item));
|
|
43
54
|
}
|
|
44
|
-
|
|
55
|
+
out[key] = nextArr;
|
|
45
56
|
continue;
|
|
46
57
|
}
|
|
47
58
|
if (isPlainObject(curVal) && isPlainObject(srcVal)) {
|
|
48
|
-
|
|
59
|
+
out[key] = mergeInto(cloneDeepLoose(curVal), srcVal);
|
|
49
60
|
continue;
|
|
50
61
|
}
|
|
51
|
-
|
|
62
|
+
out[key] = cloneDeepLoose(srcVal);
|
|
52
63
|
}
|
|
53
|
-
return
|
|
64
|
+
return out;
|
|
54
65
|
}
|
|
55
66
|
return cloneDeepLoose(source);
|
|
56
67
|
}
|
|
57
|
-
/**
|
|
58
|
-
* 深度合并对象,并对数组执行 concat(保持 scanConfig 现有语义)。
|
|
59
|
-
* - undefined 会被忽略
|
|
60
|
-
* - plain object 深合并
|
|
61
|
-
* - array 与 array 合并为新数组(保持输入不被污染)
|
|
62
|
-
*/
|
|
63
68
|
export function mergeAndConcat(...items) {
|
|
64
69
|
let acc = {};
|
|
65
70
|
for (const item of items) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { JsonValue } from "../types/common";
|
|
1
2
|
import type { FieldDefinition } from "../types/validate";
|
|
2
3
|
export type NormalizedFieldDefinition = {
|
|
3
4
|
name: string;
|
|
@@ -5,7 +6,7 @@ export type NormalizedFieldDefinition = {
|
|
|
5
6
|
detail: string;
|
|
6
7
|
min: number | null;
|
|
7
8
|
max: number | null;
|
|
8
|
-
default:
|
|
9
|
+
default: JsonValue | null;
|
|
9
10
|
index: boolean;
|
|
10
11
|
unique: boolean;
|
|
11
12
|
nullable: boolean;
|