befly 3.16.9 → 3.16.11
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 +0 -129
- package/befly.js +12769 -0
- package/befly.min.js +47 -0
- package/package.json +18 -29
- package/dist/befly.config.d.ts +0 -7
- package/dist/befly.config.js +0 -128
- package/dist/befly.js +0 -17276
- package/dist/befly.min.js +0 -23
- package/dist/checks/checkApi.d.ts +0 -1
- package/dist/checks/checkApi.js +0 -124
- package/dist/checks/checkConfig.d.ts +0 -9
- package/dist/checks/checkConfig.js +0 -255
- package/dist/checks/checkHook.d.ts +0 -1
- package/dist/checks/checkHook.js +0 -132
- package/dist/checks/checkMenu.d.ts +0 -3
- package/dist/checks/checkMenu.js +0 -106
- package/dist/checks/checkPlugin.d.ts +0 -1
- package/dist/checks/checkPlugin.js +0 -132
- package/dist/checks/checkTable.d.ts +0 -7
- package/dist/checks/checkTable.js +0 -431
- package/dist/configs/presetRegexp.d.ts +0 -145
- package/dist/configs/presetRegexp.js +0 -218
- package/dist/hooks/auth.d.ts +0 -3
- package/dist/hooks/auth.js +0 -24
- package/dist/hooks/cors.d.ts +0 -7
- package/dist/hooks/cors.js +0 -36
- package/dist/hooks/parser.d.ts +0 -10
- package/dist/hooks/parser.js +0 -76
- package/dist/hooks/permission.d.ts +0 -10
- package/dist/hooks/permission.js +0 -64
- package/dist/hooks/validator.d.ts +0 -7
- package/dist/hooks/validator.js +0 -52
- package/dist/index.d.ts +0 -28
- package/dist/index.js +0 -316
- package/dist/lib/asyncContext.d.ts +0 -21
- package/dist/lib/asyncContext.js +0 -27
- package/dist/lib/cacheHelper.d.ts +0 -128
- package/dist/lib/cacheHelper.js +0 -477
- package/dist/lib/cacheKeys.d.ts +0 -27
- package/dist/lib/cacheKeys.js +0 -37
- package/dist/lib/cipher.d.ts +0 -153
- package/dist/lib/cipher.js +0 -237
- package/dist/lib/connect.d.ts +0 -95
- package/dist/lib/connect.js +0 -313
- package/dist/lib/dbHelper.d.ts +0 -229
- package/dist/lib/dbHelper.js +0 -1069
- package/dist/lib/dbUtils.d.ts +0 -91
- package/dist/lib/dbUtils.js +0 -544
- package/dist/lib/jwt.d.ts +0 -13
- package/dist/lib/jwt.js +0 -77
- package/dist/lib/logger.d.ts +0 -46
- package/dist/lib/logger.js +0 -731
- package/dist/lib/redisHelper.d.ts +0 -193
- package/dist/lib/redisHelper.js +0 -598
- package/dist/lib/sqlBuilder.d.ts +0 -160
- package/dist/lib/sqlBuilder.js +0 -837
- package/dist/lib/sqlCheck.d.ts +0 -23
- package/dist/lib/sqlCheck.js +0 -119
- package/dist/lib/validator.d.ts +0 -45
- package/dist/lib/validator.js +0 -424
- package/dist/loader/loadApis.d.ts +0 -12
- package/dist/loader/loadApis.js +0 -71
- package/dist/loader/loadHooks.d.ts +0 -7
- package/dist/loader/loadHooks.js +0 -50
- package/dist/loader/loadPlugins.d.ts +0 -8
- package/dist/loader/loadPlugins.js +0 -69
- package/dist/paths.d.ts +0 -93
- package/dist/paths.js +0 -100
- package/dist/plugins/cache.d.ts +0 -10
- package/dist/plugins/cache.js +0 -24
- package/dist/plugins/cipher.d.ts +0 -7
- package/dist/plugins/cipher.js +0 -14
- package/dist/plugins/config.d.ts +0 -3
- package/dist/plugins/config.js +0 -9
- package/dist/plugins/db.d.ts +0 -10
- package/dist/plugins/db.js +0 -48
- package/dist/plugins/jwt.d.ts +0 -6
- package/dist/plugins/jwt.js +0 -13
- package/dist/plugins/logger.d.ts +0 -10
- package/dist/plugins/logger.js +0 -21
- package/dist/plugins/redis.d.ts +0 -10
- package/dist/plugins/redis.js +0 -40
- package/dist/plugins/tool.d.ts +0 -75
- package/dist/plugins/tool.js +0 -105
- package/dist/router/api.d.ts +0 -14
- package/dist/router/api.js +0 -109
- package/dist/router/static.d.ts +0 -9
- package/dist/router/static.js +0 -56
- package/dist/scripts/ensureDist.d.ts +0 -1
- package/dist/scripts/ensureDist.js +0 -296
- package/dist/sync/syncApi.d.ts +0 -3
- package/dist/sync/syncApi.js +0 -140
- package/dist/sync/syncCache.d.ts +0 -2
- package/dist/sync/syncCache.js +0 -14
- package/dist/sync/syncDev.d.ts +0 -6
- package/dist/sync/syncDev.js +0 -166
- package/dist/sync/syncMenu.d.ts +0 -14
- package/dist/sync/syncMenu.js +0 -308
- package/dist/sync/syncTable.d.ts +0 -126
- package/dist/sync/syncTable.js +0 -1129
- package/dist/types/api.d.ts +0 -175
- package/dist/types/api.js +0 -4
- package/dist/types/befly.d.ts +0 -231
- package/dist/types/befly.js +0 -4
- package/dist/types/cache.d.ts +0 -96
- package/dist/types/cache.js +0 -4
- package/dist/types/cipher.d.ts +0 -27
- package/dist/types/cipher.js +0 -7
- package/dist/types/common.d.ts +0 -127
- package/dist/types/common.js +0 -5
- package/dist/types/context.d.ts +0 -39
- package/dist/types/context.js +0 -4
- package/dist/types/coreError.d.ts +0 -31
- package/dist/types/coreError.js +0 -38
- package/dist/types/crypto.d.ts +0 -20
- package/dist/types/crypto.js +0 -4
- package/dist/types/database.d.ts +0 -182
- package/dist/types/database.js +0 -4
- package/dist/types/hook.d.ts +0 -30
- package/dist/types/hook.js +0 -19
- package/dist/types/jwt.d.ts +0 -76
- package/dist/types/jwt.js +0 -4
- package/dist/types/logger.d.ts +0 -95
- package/dist/types/logger.js +0 -6
- package/dist/types/plugin.d.ts +0 -27
- package/dist/types/plugin.js +0 -17
- package/dist/types/redis.d.ts +0 -80
- package/dist/types/redis.js +0 -4
- package/dist/types/roleApisCache.d.ts +0 -21
- package/dist/types/roleApisCache.js +0 -8
- package/dist/types/sync.d.ts +0 -93
- package/dist/types/sync.js +0 -4
- package/dist/types/table.d.ts +0 -34
- package/dist/types/table.js +0 -4
- package/dist/types/validate.d.ts +0 -113
- package/dist/types/validate.js +0 -4
- package/dist/utils/calcPerfTime.d.ts +0 -4
- package/dist/utils/calcPerfTime.js +0 -13
- package/dist/utils/cors.d.ts +0 -8
- package/dist/utils/cors.js +0 -17
- package/dist/utils/dbFieldRules.d.ts +0 -31
- package/dist/utils/dbFieldRules.js +0 -94
- package/dist/utils/fieldClear.d.ts +0 -11
- package/dist/utils/fieldClear.js +0 -57
- package/dist/utils/formatYmdHms.d.ts +0 -1
- package/dist/utils/formatYmdHms.js +0 -20
- package/dist/utils/getClientIp.d.ts +0 -6
- package/dist/utils/getClientIp.js +0 -39
- package/dist/utils/importDefault.d.ts +0 -1
- package/dist/utils/importDefault.js +0 -53
- package/dist/utils/isDirentDirectory.d.ts +0 -3
- package/dist/utils/isDirentDirectory.js +0 -18
- package/dist/utils/loadMenuConfigs.d.ts +0 -11
- package/dist/utils/loadMenuConfigs.js +0 -130
- package/dist/utils/loggerUtils.d.ts +0 -18
- package/dist/utils/loggerUtils.js +0 -171
- package/dist/utils/mergeAndConcat.d.ts +0 -7
- package/dist/utils/mergeAndConcat.js +0 -77
- package/dist/utils/normalizeFieldDefinition.d.ts +0 -18
- package/dist/utils/normalizeFieldDefinition.js +0 -27
- package/dist/utils/processInfo.d.ts +0 -26
- package/dist/utils/processInfo.js +0 -41
- package/dist/utils/response.d.ts +0 -20
- package/dist/utils/response.js +0 -96
- package/dist/utils/scanAddons.d.ts +0 -15
- package/dist/utils/scanAddons.js +0 -35
- package/dist/utils/scanCoreBuiltins.d.ts +0 -3
- package/dist/utils/scanCoreBuiltins.js +0 -72
- package/dist/utils/scanFiles.d.ts +0 -32
- package/dist/utils/scanFiles.js +0 -124
- package/dist/utils/scanSources.d.ts +0 -10
- package/dist/utils/scanSources.js +0 -46
- package/dist/utils/sortModules.d.ts +0 -28
- package/dist/utils/sortModules.js +0 -105
- package/dist/utils/sqlUtil.d.ts +0 -33
- package/dist/utils/sqlUtil.js +0 -146
- package/dist/utils/util.d.ts +0 -172
- package/dist/utils/util.js +0 -517
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 内置正则表达式别名
|
|
3
|
-
* 用于表单验证和数据校验
|
|
4
|
-
* 命名规范:小驼峰格式
|
|
5
|
-
*/
|
|
6
|
-
export declare const RegexAliases: {
|
|
7
|
-
/** 正整数(不含0) */
|
|
8
|
-
readonly number: "^\\d+$";
|
|
9
|
-
/** 整数(含负数) */
|
|
10
|
-
readonly integer: "^-?\\d+$";
|
|
11
|
-
/** 浮点数 */
|
|
12
|
-
readonly float: "^-?\\d+(\\.\\d+)?$";
|
|
13
|
-
/** 正整数(不含0) */
|
|
14
|
-
readonly positive: "^[1-9]\\d*$";
|
|
15
|
-
/** 负整数 */
|
|
16
|
-
readonly negative: "^-\\d+$";
|
|
17
|
-
/** 零 */
|
|
18
|
-
readonly zero: "^0$";
|
|
19
|
-
/** 纯字母 */
|
|
20
|
-
readonly word: "^[a-zA-Z]+$";
|
|
21
|
-
/** 字母和数字 */
|
|
22
|
-
readonly alphanumeric: "^[a-zA-Z0-9]+$";
|
|
23
|
-
/** 字母、数字和下划线 */
|
|
24
|
-
readonly alphanumeric_: "^[a-zA-Z0-9_]+$";
|
|
25
|
-
/** 字母、数字、下划线和短横线 */
|
|
26
|
-
readonly alphanumericDash_: "^[a-zA-Z0-9_-]+$";
|
|
27
|
-
/** 小写字母 */
|
|
28
|
-
readonly lowercase: "^[a-z]+$";
|
|
29
|
-
/** 大写字母 */
|
|
30
|
-
readonly uppercase: "^[A-Z]+$";
|
|
31
|
-
/** 纯中文 */
|
|
32
|
-
readonly chinese: "^[\\u4e00-\\u9fa5]+$";
|
|
33
|
-
/** 中文和字母 */
|
|
34
|
-
readonly chineseWord: "^[\\u4e00-\\u9fa5a-zA-Z]+$";
|
|
35
|
-
/** 邮箱地址 */
|
|
36
|
-
readonly email: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$";
|
|
37
|
-
/** 中国大陆手机号 */
|
|
38
|
-
readonly phone: "^1[3-9]\\d{9}$";
|
|
39
|
-
/** 固定电话(区号-号码) */
|
|
40
|
-
readonly telephone: "^0\\d{2,3}-?\\d{7,8}$";
|
|
41
|
-
/** URL 地址 */
|
|
42
|
-
readonly url: "^https?://";
|
|
43
|
-
/** IPv4 地址 */
|
|
44
|
-
readonly ip: "^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$";
|
|
45
|
-
/** IPv6 地址 */
|
|
46
|
-
readonly ipv6: "^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$";
|
|
47
|
-
/** 域名 */
|
|
48
|
-
readonly domain: "^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,}$";
|
|
49
|
-
/** UUID */
|
|
50
|
-
readonly uuid: "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$";
|
|
51
|
-
/** 十六进制字符串 */
|
|
52
|
-
readonly hex: "^[0-9a-fA-F]+$";
|
|
53
|
-
/** Base64 编码 */
|
|
54
|
-
readonly base64: "^[A-Za-z0-9+/=]+$";
|
|
55
|
-
/** MD5 哈希 */
|
|
56
|
-
readonly md5: "^[a-f0-9]{32}$";
|
|
57
|
-
/** SHA1 哈希 */
|
|
58
|
-
readonly sha1: "^[a-f0-9]{40}$";
|
|
59
|
-
/** SHA256 哈希 */
|
|
60
|
-
readonly sha256: "^[a-f0-9]{64}$";
|
|
61
|
-
/** 日期 YYYY-MM-DD */
|
|
62
|
-
readonly date: "^\\d{4}-\\d{2}-\\d{2}$";
|
|
63
|
-
/** 时间 HH:MM:SS */
|
|
64
|
-
readonly time: "^\\d{2}:\\d{2}:\\d{2}$";
|
|
65
|
-
/** ISO 日期时间 */
|
|
66
|
-
readonly datetime: "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}";
|
|
67
|
-
/** 年份 */
|
|
68
|
-
readonly year: "^\\d{4}$";
|
|
69
|
-
/** 月份 01-12 */
|
|
70
|
-
readonly month: "^(0[1-9]|1[0-2])$";
|
|
71
|
-
/** 日期 01-31 */
|
|
72
|
-
readonly day: "^(0[1-9]|[12]\\d|3[01])$";
|
|
73
|
-
/** 变量名 */
|
|
74
|
-
readonly variable: "^[a-zA-Z_][a-zA-Z0-9_]*$";
|
|
75
|
-
/** 常量名(全大写) */
|
|
76
|
-
readonly constant: "^[A-Z][A-Z0-9_]*$";
|
|
77
|
-
/** 包名(小写+连字符) */
|
|
78
|
-
readonly package: "^[a-z][a-z0-9-]*$";
|
|
79
|
-
/** 中国身份证号(18位) */
|
|
80
|
-
readonly idCard: "^\\d{17}[\\dXx]$";
|
|
81
|
-
/** 护照号 */
|
|
82
|
-
readonly passport: "^[a-zA-Z0-9]{5,17}$";
|
|
83
|
-
/** 银行卡号(16-19位数字) */
|
|
84
|
-
readonly bankCard: "^\\d{16,19}$";
|
|
85
|
-
/** 微信号(6-20位,字母开头,可包含字母、数字、下划线、减号) */
|
|
86
|
-
readonly wechat: "^[a-zA-Z][a-zA-Z0-9_-]{5,19}$";
|
|
87
|
-
/** QQ号(5-11位数字,首位非0) */
|
|
88
|
-
readonly qq: "^[1-9]\\d{4,10}$";
|
|
89
|
-
/** 支付宝账号(手机号或邮箱) */
|
|
90
|
-
readonly alipay: "^(1[3-9]\\d{9}|[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,})$";
|
|
91
|
-
/** 用户名(4-20位,字母开头,可包含字母、数字、下划线) */
|
|
92
|
-
readonly username: "^[a-zA-Z][a-zA-Z0-9_]{3,19}$";
|
|
93
|
-
/** 昵称(2-20位,支持中文、字母、数字) */
|
|
94
|
-
readonly nickname: "^[\\u4e00-\\u9fa5a-zA-Z0-9]{2,20}$";
|
|
95
|
-
/** 弱密码(至少6位) */
|
|
96
|
-
readonly passwordWeak: "^.{6,}$";
|
|
97
|
-
/** 中等密码(至少8位,包含字母和数字) */
|
|
98
|
-
readonly passwordMedium: "^(?=.*[a-zA-Z])(?=.*\\d).{8,}$";
|
|
99
|
-
/** 强密码(至少8位,包含大小写字母、数字和特殊字符) */
|
|
100
|
-
readonly passwordStrong: "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[!@#$%^&*]).{8,}$";
|
|
101
|
-
/** 车牌号(新能源+普通) */
|
|
102
|
-
readonly licensePlate: "^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4,5}[A-HJ-NP-Z0-9挂学警港澳]$";
|
|
103
|
-
/** 邮政编码 */
|
|
104
|
-
readonly postalCode: "^\\d{6}$";
|
|
105
|
-
/** 版本号(语义化版本) */
|
|
106
|
-
readonly semver: "^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.]+)?(\\+[a-zA-Z0-9.]+)?$";
|
|
107
|
-
/** 颜色值(十六进制) */
|
|
108
|
-
readonly colorHex: "^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$";
|
|
109
|
-
/** 空字符串 */
|
|
110
|
-
readonly empty: "^$";
|
|
111
|
-
/** 非空 */
|
|
112
|
-
readonly notempty: ".+";
|
|
113
|
-
};
|
|
114
|
-
/**
|
|
115
|
-
* 正则别名类型
|
|
116
|
-
*/
|
|
117
|
-
export type RegexAliasName = keyof typeof RegexAliases;
|
|
118
|
-
/**
|
|
119
|
-
* 获取正则表达式字符串
|
|
120
|
-
* @param name 正则别名(以 @ 开头)或自定义正则字符串
|
|
121
|
-
* @returns 正则表达式字符串
|
|
122
|
-
*/
|
|
123
|
-
export declare function getRegex(name: string): string;
|
|
124
|
-
/**
|
|
125
|
-
* 获取编译后的正则表达式对象(带缓存)
|
|
126
|
-
* @param pattern 正则别名或正则字符串
|
|
127
|
-
* @param flags 正则标志(如 'i', 'g')
|
|
128
|
-
* @returns 编译后的 RegExp 对象
|
|
129
|
-
*/
|
|
130
|
-
export declare function getCompiledRegex(pattern: string, flags?: string): RegExp;
|
|
131
|
-
/**
|
|
132
|
-
* 验证值是否匹配正则(使用缓存)
|
|
133
|
-
* @param value 要验证的值
|
|
134
|
-
* @param pattern 正则别名或正则字符串
|
|
135
|
-
* @returns 是否匹配
|
|
136
|
-
*/
|
|
137
|
-
export declare function matchRegex(value: string, pattern: string): boolean;
|
|
138
|
-
/**
|
|
139
|
-
* 清除正则缓存
|
|
140
|
-
*/
|
|
141
|
-
export declare function clearRegexCache(): void;
|
|
142
|
-
/**
|
|
143
|
-
* 获取缓存大小
|
|
144
|
-
*/
|
|
145
|
-
export declare function getRegexCacheSize(): number;
|
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 内置正则表达式别名
|
|
3
|
-
* 用于表单验证和数据校验
|
|
4
|
-
* 命名规范:小驼峰格式
|
|
5
|
-
*/
|
|
6
|
-
export const RegexAliases = {
|
|
7
|
-
// ============================================
|
|
8
|
-
// 数字类型
|
|
9
|
-
// ============================================
|
|
10
|
-
/** 正整数(不含0) */
|
|
11
|
-
number: "^\\d+$",
|
|
12
|
-
/** 整数(含负数) */
|
|
13
|
-
integer: "^-?\\d+$",
|
|
14
|
-
/** 浮点数 */
|
|
15
|
-
float: "^-?\\d+(\\.\\d+)?$",
|
|
16
|
-
/** 正整数(不含0) */
|
|
17
|
-
positive: "^[1-9]\\d*$",
|
|
18
|
-
/** 负整数 */
|
|
19
|
-
negative: "^-\\d+$",
|
|
20
|
-
/** 零 */
|
|
21
|
-
zero: "^0$",
|
|
22
|
-
// ============================================
|
|
23
|
-
// 字符串类型
|
|
24
|
-
// ============================================
|
|
25
|
-
/** 纯字母 */
|
|
26
|
-
word: "^[a-zA-Z]+$",
|
|
27
|
-
/** 字母和数字 */
|
|
28
|
-
alphanumeric: "^[a-zA-Z0-9]+$",
|
|
29
|
-
/** 字母、数字和下划线 */
|
|
30
|
-
alphanumeric_: "^[a-zA-Z0-9_]+$",
|
|
31
|
-
/** 字母、数字、下划线和短横线 */
|
|
32
|
-
alphanumericDash_: "^[a-zA-Z0-9_-]+$",
|
|
33
|
-
/** 小写字母 */
|
|
34
|
-
lowercase: "^[a-z]+$",
|
|
35
|
-
/** 大写字母 */
|
|
36
|
-
uppercase: "^[A-Z]+$",
|
|
37
|
-
// ============================================
|
|
38
|
-
// 中文
|
|
39
|
-
// ============================================
|
|
40
|
-
/** 纯中文 */
|
|
41
|
-
chinese: "^[\\u4e00-\\u9fa5]+$",
|
|
42
|
-
/** 中文和字母 */
|
|
43
|
-
chineseWord: "^[\\u4e00-\\u9fa5a-zA-Z]+$",
|
|
44
|
-
// ============================================
|
|
45
|
-
// 常用格式
|
|
46
|
-
// ============================================
|
|
47
|
-
/** 邮箱地址 */
|
|
48
|
-
email: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
|
|
49
|
-
/** 中国大陆手机号 */
|
|
50
|
-
phone: "^1[3-9]\\d{9}$",
|
|
51
|
-
/** 固定电话(区号-号码) */
|
|
52
|
-
telephone: "^0\\d{2,3}-?\\d{7,8}$",
|
|
53
|
-
/** URL 地址 */
|
|
54
|
-
url: "^https?://",
|
|
55
|
-
/** IPv4 地址 */
|
|
56
|
-
ip: "^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$",
|
|
57
|
-
/** IPv6 地址 */
|
|
58
|
-
ipv6: "^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$",
|
|
59
|
-
/** 域名 */
|
|
60
|
-
domain: "^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,}$",
|
|
61
|
-
// ============================================
|
|
62
|
-
// 特殊格式
|
|
63
|
-
// ============================================
|
|
64
|
-
/** UUID */
|
|
65
|
-
uuid: "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
|
|
66
|
-
/** 十六进制字符串 */
|
|
67
|
-
hex: "^[0-9a-fA-F]+$",
|
|
68
|
-
/** Base64 编码 */
|
|
69
|
-
base64: "^[A-Za-z0-9+/=]+$",
|
|
70
|
-
/** MD5 哈希 */
|
|
71
|
-
md5: "^[a-f0-9]{32}$",
|
|
72
|
-
/** SHA1 哈希 */
|
|
73
|
-
sha1: "^[a-f0-9]{40}$",
|
|
74
|
-
/** SHA256 哈希 */
|
|
75
|
-
sha256: "^[a-f0-9]{64}$",
|
|
76
|
-
// ============================================
|
|
77
|
-
// 日期时间
|
|
78
|
-
// ============================================
|
|
79
|
-
/** 日期 YYYY-MM-DD */
|
|
80
|
-
date: "^\\d{4}-\\d{2}-\\d{2}$",
|
|
81
|
-
/** 时间 HH:MM:SS */
|
|
82
|
-
time: "^\\d{2}:\\d{2}:\\d{2}$",
|
|
83
|
-
/** ISO 日期时间 */
|
|
84
|
-
datetime: "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}",
|
|
85
|
-
/** 年份 */
|
|
86
|
-
year: "^\\d{4}$",
|
|
87
|
-
/** 月份 01-12 */
|
|
88
|
-
month: "^(0[1-9]|1[0-2])$",
|
|
89
|
-
/** 日期 01-31 */
|
|
90
|
-
day: "^(0[1-9]|[12]\\d|3[01])$",
|
|
91
|
-
// ============================================
|
|
92
|
-
// 代码相关
|
|
93
|
-
// ============================================
|
|
94
|
-
/** 变量名 */
|
|
95
|
-
variable: "^[a-zA-Z_][a-zA-Z0-9_]*$",
|
|
96
|
-
/** 常量名(全大写) */
|
|
97
|
-
constant: "^[A-Z][A-Z0-9_]*$",
|
|
98
|
-
/** 包名(小写+连字符) */
|
|
99
|
-
package: "^[a-z][a-z0-9-]*$",
|
|
100
|
-
// ============================================
|
|
101
|
-
// 证件相关
|
|
102
|
-
// ============================================
|
|
103
|
-
/** 中国身份证号(18位) */
|
|
104
|
-
idCard: "^\\d{17}[\\dXx]$",
|
|
105
|
-
/** 护照号 */
|
|
106
|
-
passport: "^[a-zA-Z0-9]{5,17}$",
|
|
107
|
-
// ============================================
|
|
108
|
-
// 账号相关(国内常用)
|
|
109
|
-
// ============================================
|
|
110
|
-
/** 银行卡号(16-19位数字) */
|
|
111
|
-
bankCard: "^\\d{16,19}$",
|
|
112
|
-
/** 微信号(6-20位,字母开头,可包含字母、数字、下划线、减号) */
|
|
113
|
-
wechat: "^[a-zA-Z][a-zA-Z0-9_-]{5,19}$",
|
|
114
|
-
/** QQ号(5-11位数字,首位非0) */
|
|
115
|
-
qq: "^[1-9]\\d{4,10}$",
|
|
116
|
-
/** 支付宝账号(手机号或邮箱) */
|
|
117
|
-
alipay: "^(1[3-9]\\d{9}|[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,})$",
|
|
118
|
-
/** 用户名(4-20位,字母开头,可包含字母、数字、下划线) */
|
|
119
|
-
username: "^[a-zA-Z][a-zA-Z0-9_]{3,19}$",
|
|
120
|
-
/** 昵称(2-20位,支持中文、字母、数字) */
|
|
121
|
-
nickname: "^[\\u4e00-\\u9fa5a-zA-Z0-9]{2,20}$",
|
|
122
|
-
// ============================================
|
|
123
|
-
// 密码强度
|
|
124
|
-
// ============================================
|
|
125
|
-
/** 弱密码(至少6位) */
|
|
126
|
-
passwordWeak: "^.{6,}$",
|
|
127
|
-
/** 中等密码(至少8位,包含字母和数字) */
|
|
128
|
-
passwordMedium: "^(?=.*[a-zA-Z])(?=.*\\d).{8,}$",
|
|
129
|
-
/** 强密码(至少8位,包含大小写字母、数字和特殊字符) */
|
|
130
|
-
passwordStrong: "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[!@#$%^&*]).{8,}$",
|
|
131
|
-
// ============================================
|
|
132
|
-
// 其他常用
|
|
133
|
-
// ============================================
|
|
134
|
-
/** 车牌号(新能源+普通) */
|
|
135
|
-
licensePlate: "^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4,5}[A-HJ-NP-Z0-9挂学警港澳]$",
|
|
136
|
-
/** 邮政编码 */
|
|
137
|
-
postalCode: "^\\d{6}$",
|
|
138
|
-
/** 版本号(语义化版本) */
|
|
139
|
-
semver: "^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.]+)?(\\+[a-zA-Z0-9.]+)?$",
|
|
140
|
-
/** 颜色值(十六进制) */
|
|
141
|
-
colorHex: "^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$",
|
|
142
|
-
// ============================================
|
|
143
|
-
// 空值
|
|
144
|
-
// ============================================
|
|
145
|
-
/** 空字符串 */
|
|
146
|
-
empty: "^$",
|
|
147
|
-
/** 非空 */
|
|
148
|
-
notempty: ".+"
|
|
149
|
-
};
|
|
150
|
-
// ============================================
|
|
151
|
-
// 正则表达式缓存(性能优化)
|
|
152
|
-
// ============================================
|
|
153
|
-
const regexCache = new Map();
|
|
154
|
-
/**
|
|
155
|
-
* 获取正则表达式字符串
|
|
156
|
-
* @param name 正则别名(以 @ 开头)或自定义正则字符串
|
|
157
|
-
* @returns 正则表达式字符串
|
|
158
|
-
*/
|
|
159
|
-
export function getRegex(name) {
|
|
160
|
-
if (name.startsWith("@")) {
|
|
161
|
-
const alias = name.slice(1);
|
|
162
|
-
return RegexAliases[alias] || name;
|
|
163
|
-
}
|
|
164
|
-
return name;
|
|
165
|
-
}
|
|
166
|
-
function parseRegexLiteral(pattern) {
|
|
167
|
-
const trimmed = String(pattern || "").trim();
|
|
168
|
-
if (trimmed.length < 2)
|
|
169
|
-
return null;
|
|
170
|
-
if (!trimmed.startsWith("/"))
|
|
171
|
-
return null;
|
|
172
|
-
const lastSlash = trimmed.lastIndexOf("/");
|
|
173
|
-
if (lastSlash <= 0)
|
|
174
|
-
return null;
|
|
175
|
-
const flags = trimmed.slice(lastSlash + 1);
|
|
176
|
-
if (flags !== "" && !/^[gimsuy]+$/.test(flags))
|
|
177
|
-
return null;
|
|
178
|
-
return { source: trimmed.slice(1, lastSlash), flags: flags };
|
|
179
|
-
}
|
|
180
|
-
/**
|
|
181
|
-
* 获取编译后的正则表达式对象(带缓存)
|
|
182
|
-
* @param pattern 正则别名或正则字符串
|
|
183
|
-
* @param flags 正则标志(如 'i', 'g')
|
|
184
|
-
* @returns 编译后的 RegExp 对象
|
|
185
|
-
*/
|
|
186
|
-
export function getCompiledRegex(pattern, flags) {
|
|
187
|
-
const literal = parseRegexLiteral(pattern);
|
|
188
|
-
const regexStr = literal ? literal.source : getRegex(pattern);
|
|
189
|
-
const useFlags = literal && literal.flags !== "" ? literal.flags : flags || "";
|
|
190
|
-
const cacheKey = `${regexStr}:${useFlags}`;
|
|
191
|
-
let cached = regexCache.get(cacheKey);
|
|
192
|
-
if (!cached) {
|
|
193
|
-
cached = new RegExp(regexStr, useFlags);
|
|
194
|
-
regexCache.set(cacheKey, cached);
|
|
195
|
-
}
|
|
196
|
-
return cached;
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* 验证值是否匹配正则(使用缓存)
|
|
200
|
-
* @param value 要验证的值
|
|
201
|
-
* @param pattern 正则别名或正则字符串
|
|
202
|
-
* @returns 是否匹配
|
|
203
|
-
*/
|
|
204
|
-
export function matchRegex(value, pattern) {
|
|
205
|
-
return getCompiledRegex(pattern).test(value);
|
|
206
|
-
}
|
|
207
|
-
/**
|
|
208
|
-
* 清除正则缓存
|
|
209
|
-
*/
|
|
210
|
-
export function clearRegexCache() {
|
|
211
|
-
regexCache.clear();
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* 获取缓存大小
|
|
215
|
-
*/
|
|
216
|
-
export function getRegexCacheSize() {
|
|
217
|
-
return regexCache.size;
|
|
218
|
-
}
|
package/dist/hooks/auth.d.ts
DELETED
package/dist/hooks/auth.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { setCtxUser } from "../lib/asyncContext";
|
|
2
|
-
const authHook = {
|
|
3
|
-
name: "auth",
|
|
4
|
-
enable: true,
|
|
5
|
-
deps: ["cors"],
|
|
6
|
-
handler: async (befly, ctx) => {
|
|
7
|
-
const authHeader = ctx.req.headers.get("authorization");
|
|
8
|
-
if (authHeader && authHeader.startsWith("Bearer ")) {
|
|
9
|
-
const token = authHeader.substring(7);
|
|
10
|
-
try {
|
|
11
|
-
const payload = await befly.jwt.verify(token);
|
|
12
|
-
ctx.user = payload;
|
|
13
|
-
setCtxUser(payload.id, payload.roleCode, payload.nickname, payload.roleType);
|
|
14
|
-
}
|
|
15
|
-
catch {
|
|
16
|
-
ctx.user = {};
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
else {
|
|
20
|
-
ctx.user = {};
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
export default authHook;
|
package/dist/hooks/cors.d.ts
DELETED
package/dist/hooks/cors.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
// 相对导入
|
|
2
|
-
import { setCorsOptions } from "../utils/cors";
|
|
3
|
-
/**
|
|
4
|
-
* CORS 跨域处理钩子
|
|
5
|
-
* 设置跨域响应头并处理 OPTIONS 预检请求
|
|
6
|
-
*/
|
|
7
|
-
const corsHook = {
|
|
8
|
-
name: "cors",
|
|
9
|
-
enable: true,
|
|
10
|
-
deps: [],
|
|
11
|
-
handler: async (befly, ctx) => {
|
|
12
|
-
const req = ctx.req;
|
|
13
|
-
// 合并默认配置和用户配置
|
|
14
|
-
const defaultConfig = {
|
|
15
|
-
origin: "*",
|
|
16
|
-
methods: "GET, POST, OPTIONS",
|
|
17
|
-
allowedHeaders: "Content-Type, Authorization, authorization, token",
|
|
18
|
-
exposedHeaders: "Content-Range, X-Content-Range, Authorization, authorization, token",
|
|
19
|
-
maxAge: 86400,
|
|
20
|
-
credentials: "true"
|
|
21
|
-
};
|
|
22
|
-
const corsConfig = Object.assign({}, defaultConfig, befly.config && befly.config.cors ? befly.config.cors : {});
|
|
23
|
-
// 设置 CORS 响应头
|
|
24
|
-
const headers = setCorsOptions(req, corsConfig);
|
|
25
|
-
ctx.corsHeaders = headers;
|
|
26
|
-
// 处理 OPTIONS 预检请求
|
|
27
|
-
if (req.method === "OPTIONS") {
|
|
28
|
-
ctx.response = new Response(null, {
|
|
29
|
-
status: 204,
|
|
30
|
-
headers: headers
|
|
31
|
-
});
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
export default corsHook;
|
package/dist/hooks/parser.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { Hook } from "../types/hook";
|
|
2
|
-
/**
|
|
3
|
-
* 请求参数解析钩子
|
|
4
|
-
* - GET 请求:解析 URL 查询参数
|
|
5
|
-
* - POST 请求:解析 JSON 或 XML 请求体
|
|
6
|
-
* - 仅负责解析与合并参数;字段过滤/映射/校验由 validator hook 处理
|
|
7
|
-
* - rawBody: true 时跳过解析,由 handler 自行处理原始请求
|
|
8
|
-
*/
|
|
9
|
-
declare const parserHook: Hook;
|
|
10
|
-
export default parserHook;
|
package/dist/hooks/parser.js
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
// 外部依赖
|
|
2
|
-
import { XMLParser } from "fast-xml-parser";
|
|
3
|
-
import { ErrorResponse } from "../utils/response";
|
|
4
|
-
const xmlParser = new XMLParser();
|
|
5
|
-
/**
|
|
6
|
-
* 请求参数解析钩子
|
|
7
|
-
* - GET 请求:解析 URL 查询参数
|
|
8
|
-
* - POST 请求:解析 JSON 或 XML 请求体
|
|
9
|
-
* - 仅负责解析与合并参数;字段过滤/映射/校验由 validator hook 处理
|
|
10
|
-
* - rawBody: true 时跳过解析,由 handler 自行处理原始请求
|
|
11
|
-
*/
|
|
12
|
-
const parserHook = {
|
|
13
|
-
name: "parser",
|
|
14
|
-
enable: true,
|
|
15
|
-
deps: ["auth"],
|
|
16
|
-
handler: async (befly, ctx) => {
|
|
17
|
-
if (!ctx.api)
|
|
18
|
-
return;
|
|
19
|
-
// rawBody 模式:跳过解析,保留原始请求供 handler 自行处理
|
|
20
|
-
// 适用于:微信回调、支付回调、webhook 等需要手动解密/验签的场景
|
|
21
|
-
if (ctx.api.rawBody) {
|
|
22
|
-
ctx.body = {};
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
// GET 请求:解析查询参数
|
|
26
|
-
if (ctx.req.method === "GET") {
|
|
27
|
-
const url = new URL(ctx.req.url);
|
|
28
|
-
const params = Object.fromEntries(url.searchParams);
|
|
29
|
-
ctx.body = params;
|
|
30
|
-
}
|
|
31
|
-
else if (ctx.req.method === "POST") {
|
|
32
|
-
// POST 请求:解析请求体
|
|
33
|
-
const contentType = ctx.req.headers.get("content-type") || "";
|
|
34
|
-
// 获取 URL 查询参数(POST 请求也可能带参数)
|
|
35
|
-
const url = new URL(ctx.req.url);
|
|
36
|
-
const queryParams = Object.fromEntries(url.searchParams);
|
|
37
|
-
try {
|
|
38
|
-
// JSON 格式
|
|
39
|
-
if (contentType.includes("application/json")) {
|
|
40
|
-
const body = (await ctx.req.json());
|
|
41
|
-
// 合并 URL 参数和请求体(请求体优先)
|
|
42
|
-
const merged = { ...queryParams, ...body };
|
|
43
|
-
ctx.body = merged;
|
|
44
|
-
}
|
|
45
|
-
else if (contentType.includes("application/xml") || contentType.includes("text/xml")) {
|
|
46
|
-
// XML 格式
|
|
47
|
-
const text = await ctx.req.text();
|
|
48
|
-
const parsed = xmlParser.parse(text);
|
|
49
|
-
// 提取根节点内容(如 xml),使 body 扁平化
|
|
50
|
-
const rootKey = Object.keys(parsed)[0];
|
|
51
|
-
const body = rootKey && typeof parsed[rootKey] === "object" ? parsed[rootKey] : parsed;
|
|
52
|
-
// 合并 URL 参数和请求体(请求体优先)
|
|
53
|
-
const merged = { ...queryParams, ...body };
|
|
54
|
-
ctx.body = merged;
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
// 不支持的 Content-Type
|
|
58
|
-
ctx.response = ErrorResponse(ctx, "无效的请求参数格式", 1, null, {
|
|
59
|
-
location: "content-type",
|
|
60
|
-
value: contentType
|
|
61
|
-
}, "parser");
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
catch {
|
|
66
|
-
// 解析失败:属于客户端输入错误,返回安全 detail(不回传异常栈/原始 body)
|
|
67
|
-
ctx.response = ErrorResponse(ctx, "无效的请求参数格式", 1, null, {
|
|
68
|
-
location: "body",
|
|
69
|
-
reason: contentType.includes("application/json") ? "invalid_json" : contentType.includes("xml") ? "invalid_xml" : "invalid_body"
|
|
70
|
-
}, "parser");
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
export default parserHook;
|
package/dist/hooks/permission.js
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { CacheKeys } from "../lib/cacheKeys";
|
|
2
|
-
import { Logger } from "../lib/logger";
|
|
3
|
-
// 相对导入
|
|
4
|
-
import { ErrorResponse } from "../utils/response";
|
|
5
|
-
/**
|
|
6
|
-
* 权限检查钩子
|
|
7
|
-
* - 接口无需权限(auth=false):直接通过
|
|
8
|
-
* - 用户未登录:返回 401
|
|
9
|
-
* - 开发者角色(dev):最高权限,直接通过
|
|
10
|
-
* - 其他角色:检查 Redis 中的角色权限集合
|
|
11
|
-
*/
|
|
12
|
-
const permissionHook = {
|
|
13
|
-
name: "permission",
|
|
14
|
-
enable: true,
|
|
15
|
-
deps: ["validator"],
|
|
16
|
-
handler: async (befly, ctx) => {
|
|
17
|
-
if (!ctx.api)
|
|
18
|
-
return;
|
|
19
|
-
// 1. 接口无需权限
|
|
20
|
-
if (ctx.api.auth === false) {
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
// 2. 用户未登录
|
|
24
|
-
if (typeof ctx.user.id !== "number") {
|
|
25
|
-
ctx.response = ErrorResponse(ctx, "未登录", 1, null, null, "auth");
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
// 3. 开发者权限(最高权限)
|
|
29
|
-
if (ctx.user.roleCode === "dev") {
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
// 4. 角色权限检查
|
|
33
|
-
// apiPath 在 apiHandler 中已统一生成并写入 ctx.route
|
|
34
|
-
const apiPath = ctx.route;
|
|
35
|
-
const roleCode = ctx.user.roleCode;
|
|
36
|
-
let hasPermission = false;
|
|
37
|
-
if (roleCode && befly.redis) {
|
|
38
|
-
try {
|
|
39
|
-
// 极简方案:每个角色一个 Set,直接判断成员是否存在
|
|
40
|
-
const roleApisKey = CacheKeys.roleApis(roleCode);
|
|
41
|
-
hasPermission = await befly.redis.sismember(roleApisKey, apiPath);
|
|
42
|
-
}
|
|
43
|
-
catch (err) {
|
|
44
|
-
// Redis 异常:记录到 error 日志文件(不回传给客户端),并降级为拒绝访问
|
|
45
|
-
Logger.error({
|
|
46
|
-
event: "hook_permission_redis_error",
|
|
47
|
-
apiPath: apiPath,
|
|
48
|
-
roleCode: roleCode,
|
|
49
|
-
err: err,
|
|
50
|
-
msg: "hook permission redis error"
|
|
51
|
-
});
|
|
52
|
-
hasPermission = false;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
if (!hasPermission) {
|
|
56
|
-
const apiNameLabel = typeof ctx.api.name === "string" && ctx.api.name.length > 0 ? ctx.api.name : null;
|
|
57
|
-
const apiPathLabel = typeof apiPath === "string" && apiPath.length > 0 ? apiPath : null;
|
|
58
|
-
const apiLabel = apiNameLabel ? apiNameLabel : apiPathLabel ? apiPathLabel : "未知接口";
|
|
59
|
-
ctx.response = ErrorResponse(ctx, `无权访问 ${apiLabel} 接口`, 1, null, { apiLabel: apiLabel }, "permission");
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
export default permissionHook;
|
package/dist/hooks/validator.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
// 相对导入
|
|
2
|
-
import { Validator } from "../lib/validator";
|
|
3
|
-
import { normalizeFieldDefinition } from "../utils/normalizeFieldDefinition";
|
|
4
|
-
import { ErrorResponse } from "../utils/response";
|
|
5
|
-
import { isPlainObject, snakeCase } from "../utils/util";
|
|
6
|
-
/**
|
|
7
|
-
* 参数验证钩子
|
|
8
|
-
* 根据 API 定义的 fields 和 required 验证请求参数
|
|
9
|
-
*/
|
|
10
|
-
const validatorHook = {
|
|
11
|
-
name: "validator",
|
|
12
|
-
enable: true,
|
|
13
|
-
deps: ["parser"],
|
|
14
|
-
handler: async (befly, ctx) => {
|
|
15
|
-
if (!ctx.api)
|
|
16
|
-
return;
|
|
17
|
-
// 无需验证
|
|
18
|
-
if (!ctx.api.fields) {
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
// 仅保留 fields 中声明的字段,并支持 snake_case 入参回退(例如 agent_id -> agentId);同时在同一次遍历中应用默认值
|
|
22
|
-
if (isPlainObject(ctx.api.fields)) {
|
|
23
|
-
const rawBody = isPlainObject(ctx.body) ? ctx.body : {};
|
|
24
|
-
const nextBody = {};
|
|
25
|
-
for (const [field, fieldDef] of Object.entries(ctx.api.fields)) {
|
|
26
|
-
const normalized = normalizeFieldDefinition(fieldDef);
|
|
27
|
-
let value = rawBody[field];
|
|
28
|
-
if (value === undefined) {
|
|
29
|
-
const snakeField = snakeCase(field);
|
|
30
|
-
if (rawBody[snakeField] !== undefined) {
|
|
31
|
-
value = rawBody[snakeField];
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
// 字段未传值且定义了默认值时,应用默认值
|
|
35
|
-
if (value === undefined && normalized.default !== null) {
|
|
36
|
-
value = normalized.default;
|
|
37
|
-
}
|
|
38
|
-
if (value !== undefined) {
|
|
39
|
-
nextBody[field] = value;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
ctx.body = nextBody;
|
|
43
|
-
}
|
|
44
|
-
// 验证参数
|
|
45
|
-
const result = Validator.validate(ctx.body, ctx.api.fields, ctx.api.required || []);
|
|
46
|
-
if (result.code !== 0) {
|
|
47
|
-
ctx.response = ErrorResponse(ctx, result.firstError || "参数验证失败", 1, null, result.fieldErrors, "validator");
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
export default validatorHook;
|