befly 3.8.17 → 3.8.19
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/check.ts +9 -3
- package/env.ts +13 -5
- package/lib/validator.ts +11 -4
- package/loader/loadApis.ts +13 -5
- package/loader/loadPlugins.ts +15 -10
- package/main.ts +1 -1
- package/package.json +2 -2
package/check.ts
CHANGED
|
@@ -255,7 +255,7 @@ export const checkTable = async function (): Promise<boolean> {
|
|
|
255
255
|
*/
|
|
256
256
|
export const checkApi = async function (): Promise<boolean> {
|
|
257
257
|
try {
|
|
258
|
-
const apiGlob = new Bun.Glob('**/*.ts');
|
|
258
|
+
const apiGlob = new Bun.Glob('**/*.{ts,js}');
|
|
259
259
|
|
|
260
260
|
// 收集所有 API 文件
|
|
261
261
|
const allApiFiles: Array<{ file: string; displayName: string }> = [];
|
|
@@ -267,6 +267,9 @@ export const checkApi = async function (): Promise<boolean> {
|
|
|
267
267
|
onlyFiles: true,
|
|
268
268
|
absolute: true
|
|
269
269
|
})) {
|
|
270
|
+
if (file.endsWith('.d.ts')) {
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
270
273
|
allApiFiles.push({
|
|
271
274
|
file: file,
|
|
272
275
|
displayName: '用户'
|
|
@@ -285,6 +288,9 @@ export const checkApi = async function (): Promise<boolean> {
|
|
|
285
288
|
onlyFiles: true,
|
|
286
289
|
absolute: true
|
|
287
290
|
})) {
|
|
291
|
+
if (file.endsWith('.d.ts')) {
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
288
294
|
allApiFiles.push({
|
|
289
295
|
file: file,
|
|
290
296
|
displayName: `组件${addon}`
|
|
@@ -294,8 +300,8 @@ export const checkApi = async function (): Promise<boolean> {
|
|
|
294
300
|
|
|
295
301
|
// 合并进行验证逻辑
|
|
296
302
|
for (const item of allApiFiles) {
|
|
297
|
-
const fileName = basename(item.file).replace(/\.ts$/, '');
|
|
298
|
-
const apiPath = relative(item.displayName === '用户' ? projectApiDir : getAddonDir(item.displayName.replace('组件', ''), 'apis'), item.file).replace(/\.ts$/, '');
|
|
303
|
+
const fileName = basename(item.file).replace(/\.(ts|js)$/, '');
|
|
304
|
+
const apiPath = relative(item.displayName === '用户' ? projectApiDir : getAddonDir(item.displayName.replace('组件', ''), 'apis'), item.file).replace(/\.(ts|js)$/, '');
|
|
299
305
|
|
|
300
306
|
// 跳过以下划线开头的文件
|
|
301
307
|
if (apiPath.indexOf('_') !== -1) continue;
|
package/env.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 环境变量配置
|
|
3
3
|
* 根据 NODE_ENV 自动切换开发/生产环境配置
|
|
4
|
-
* 项目可通过创建 env.ts 文件覆盖这些配置
|
|
4
|
+
* 项目可通过创建 env.ts 或 env.js 文件覆盖这些配置
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { existsSync } from 'node:fs';
|
|
@@ -22,6 +22,7 @@ const coreEnv: EnvConfig = {
|
|
|
22
22
|
DEV_EMAIL: '',
|
|
23
23
|
DEV_PASSWORD: '123456',
|
|
24
24
|
BODY_LIMIT: 10 * 1024 * 1024, // 10MB
|
|
25
|
+
DATABASE_ENABLE: 0,
|
|
25
26
|
// ========== 时区配置 ==========
|
|
26
27
|
TZ: 'Asia/Shanghai',
|
|
27
28
|
|
|
@@ -33,7 +34,6 @@ const coreEnv: EnvConfig = {
|
|
|
33
34
|
LOG_MAX_SIZE: 10 * 1024 * 1024, // 10MB
|
|
34
35
|
|
|
35
36
|
// ========== 数据库配置 ==========
|
|
36
|
-
DATABASE_ENABLE: 0,
|
|
37
37
|
DB_TYPE: 'mysql',
|
|
38
38
|
DB_HOST: '127.0.0.1',
|
|
39
39
|
DB_PORT: 3306,
|
|
@@ -69,11 +69,19 @@ const coreEnv: EnvConfig = {
|
|
|
69
69
|
*/
|
|
70
70
|
async function loadProjectEnv(): Promise<Partial<EnvConfig>> {
|
|
71
71
|
try {
|
|
72
|
-
// 尝试从项目根目录加载 env.ts
|
|
73
|
-
const
|
|
72
|
+
// 尝试从项目根目录加载 env.ts 或 env.js
|
|
73
|
+
const projectEnvPathTs = process.cwd() + '/env.ts';
|
|
74
|
+
const projectEnvPathJs = process.cwd() + '/env.js';
|
|
75
|
+
|
|
76
|
+
let projectEnvPath = '';
|
|
77
|
+
if (existsSync(projectEnvPathTs)) {
|
|
78
|
+
projectEnvPath = projectEnvPathTs;
|
|
79
|
+
} else if (existsSync(projectEnvPathJs)) {
|
|
80
|
+
projectEnvPath = projectEnvPathJs;
|
|
81
|
+
}
|
|
74
82
|
|
|
75
83
|
// 检查文件是否存在
|
|
76
|
-
if (!
|
|
84
|
+
if (!projectEnvPath) {
|
|
77
85
|
return {};
|
|
78
86
|
}
|
|
79
87
|
|
package/lib/validator.ts
CHANGED
|
@@ -154,22 +154,29 @@ export class Validator {
|
|
|
154
154
|
*/
|
|
155
155
|
private validateNumber(value: any, name: string, min: number | null, max: number | null, spec: string | null, fieldName: string): ValidationError {
|
|
156
156
|
try {
|
|
157
|
-
|
|
157
|
+
// 允许数字类型的字符串
|
|
158
|
+
let numValue = value;
|
|
159
|
+
if (typeof value === 'string') {
|
|
160
|
+
numValue = Number(value);
|
|
161
|
+
if (Number.isNaN(numValue) || !isFinite(numValue)) {
|
|
162
|
+
return `${name}(${fieldName})必须是数字`;
|
|
163
|
+
}
|
|
164
|
+
} else if (typeof numValue !== 'number' || Number.isNaN(numValue) || !isFinite(numValue)) {
|
|
158
165
|
return `${name}(${fieldName})必须是数字`;
|
|
159
166
|
}
|
|
160
167
|
|
|
161
|
-
if (min !== null &&
|
|
168
|
+
if (min !== null && numValue < min) {
|
|
162
169
|
return `${name}(${fieldName})不能小于${min}`;
|
|
163
170
|
}
|
|
164
171
|
|
|
165
|
-
if (max !== null && max > 0 &&
|
|
172
|
+
if (max !== null && max > 0 && numValue > max) {
|
|
166
173
|
return `${name}(${fieldName})不能大于${max}`;
|
|
167
174
|
}
|
|
168
175
|
|
|
169
176
|
if (spec && spec.trim() !== '') {
|
|
170
177
|
try {
|
|
171
178
|
const regExp = new RegExp(spec);
|
|
172
|
-
if (!regExp.test(String(
|
|
179
|
+
if (!regExp.test(String(numValue))) {
|
|
173
180
|
return `${name}(${fieldName})格式不正确`;
|
|
174
181
|
}
|
|
175
182
|
} catch (error: any) {
|
package/loader/loadApis.ts
CHANGED
|
@@ -12,6 +12,8 @@ import { projectApiDir } from '../paths.js';
|
|
|
12
12
|
import { scanAddons, getAddonDir, addonDirExists } from '../util.js';
|
|
13
13
|
import type { ApiRoute } from '../types/api.js';
|
|
14
14
|
|
|
15
|
+
const API_GLOB_PATTERN = '**/*.{ts,js}';
|
|
16
|
+
|
|
15
17
|
/**
|
|
16
18
|
* API 默认字段定义
|
|
17
19
|
* 这些字段会自动合并到所有 API 的 fields 中
|
|
@@ -60,14 +62,17 @@ async function scanUserApis(): Promise<Array<{ file: string; routePrefix: string
|
|
|
60
62
|
return apis;
|
|
61
63
|
}
|
|
62
64
|
|
|
63
|
-
const glob = new Bun.Glob(
|
|
65
|
+
const glob = new Bun.Glob(API_GLOB_PATTERN);
|
|
64
66
|
|
|
65
67
|
for await (const file of glob.scan({
|
|
66
68
|
cwd: projectApiDir,
|
|
67
69
|
onlyFiles: true,
|
|
68
70
|
absolute: true
|
|
69
71
|
})) {
|
|
70
|
-
|
|
72
|
+
if (file.endsWith('.d.ts')) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const apiPath = relative(projectApiDir, file).replace(/\.(ts|js)$/, '');
|
|
71
76
|
if (apiPath.indexOf('_') !== -1) continue;
|
|
72
77
|
|
|
73
78
|
apis.push({
|
|
@@ -85,7 +90,7 @@ async function scanUserApis(): Promise<Array<{ file: string; routePrefix: string
|
|
|
85
90
|
*/
|
|
86
91
|
async function scanAddonApis(): Promise<Array<{ file: string; routePrefix: string; displayName: string }>> {
|
|
87
92
|
const apis: Array<{ file: string; routePrefix: string; displayName: string }> = [];
|
|
88
|
-
const glob = new Bun.Glob(
|
|
93
|
+
const glob = new Bun.Glob(API_GLOB_PATTERN);
|
|
89
94
|
const addons = scanAddons();
|
|
90
95
|
|
|
91
96
|
for (const addon of addons) {
|
|
@@ -97,7 +102,10 @@ async function scanAddonApis(): Promise<Array<{ file: string; routePrefix: strin
|
|
|
97
102
|
onlyFiles: true,
|
|
98
103
|
absolute: true
|
|
99
104
|
})) {
|
|
100
|
-
|
|
105
|
+
if (file.endsWith('.d.ts')) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
const apiPath = relative(addonApiDir, file).replace(/\.(ts|js)$/, '');
|
|
101
109
|
if (apiPath.indexOf('_') !== -1) continue;
|
|
102
110
|
|
|
103
111
|
apis.push({
|
|
@@ -117,7 +125,7 @@ async function scanAddonApis(): Promise<Array<{ file: string; routePrefix: strin
|
|
|
117
125
|
async function initApi(apiRoutes: Map<string, ApiRoute>, apiInfo: { file: string; routePrefix: string; displayName: string }): Promise<void> {
|
|
118
126
|
const { file, routePrefix, displayName } = apiInfo;
|
|
119
127
|
const apiDir = routePrefix === '' ? projectApiDir : getAddonDir(routePrefix.replace('addon/', ''), 'apis');
|
|
120
|
-
const apiPath = relative(apiDir, file).replace(/\.ts$/, '');
|
|
128
|
+
const apiPath = relative(apiDir, file).replace(/\.(ts|js)$/, '');
|
|
121
129
|
|
|
122
130
|
try {
|
|
123
131
|
// Windows 下路径需要转换为正斜杠格式
|
package/loader/loadPlugins.ts
CHANGED
|
@@ -49,14 +49,15 @@ function sortPlugins(plugins: Plugin[]): Plugin[] | false {
|
|
|
49
49
|
*/
|
|
50
50
|
async function scanCorePlugins(loadedPluginNames: Set<string>): Promise<Plugin[]> {
|
|
51
51
|
const plugins: Plugin[] = [];
|
|
52
|
-
const glob = new Bun.Glob('*.ts');
|
|
52
|
+
const glob = new Bun.Glob('*.{ts,js}');
|
|
53
53
|
|
|
54
54
|
for await (const file of glob.scan({
|
|
55
55
|
cwd: corePluginDir,
|
|
56
56
|
onlyFiles: true,
|
|
57
57
|
absolute: true
|
|
58
58
|
})) {
|
|
59
|
-
|
|
59
|
+
if (file.endsWith('.d.ts')) continue;
|
|
60
|
+
const fileName = basename(file).replace(/\.(ts|js)$/, '');
|
|
60
61
|
if (fileName.startsWith('_')) continue;
|
|
61
62
|
|
|
62
63
|
try {
|
|
@@ -79,7 +80,7 @@ async function scanCorePlugins(loadedPluginNames: Set<string>): Promise<Plugin[]
|
|
|
79
80
|
*/
|
|
80
81
|
async function scanAddonPlugins(loadedPluginNames: Set<string>): Promise<Plugin[]> {
|
|
81
82
|
const plugins: Plugin[] = [];
|
|
82
|
-
const glob = new Bun.Glob('*.ts');
|
|
83
|
+
const glob = new Bun.Glob('*.{ts,js}');
|
|
83
84
|
const addons = scanAddons();
|
|
84
85
|
|
|
85
86
|
for (const addon of addons) {
|
|
@@ -91,7 +92,8 @@ async function scanAddonPlugins(loadedPluginNames: Set<string>): Promise<Plugin[
|
|
|
91
92
|
onlyFiles: true,
|
|
92
93
|
absolute: true
|
|
93
94
|
})) {
|
|
94
|
-
|
|
95
|
+
if (file.endsWith('.d.ts')) continue;
|
|
96
|
+
const fileName = basename(file).replace(/\.(ts|js)$/, '');
|
|
95
97
|
if (fileName.startsWith('_')) continue;
|
|
96
98
|
|
|
97
99
|
const addonCamelCase = camelCase(addon);
|
|
@@ -103,10 +105,11 @@ async function scanAddonPlugins(loadedPluginNames: Set<string>): Promise<Plugin[
|
|
|
103
105
|
}
|
|
104
106
|
|
|
105
107
|
try {
|
|
106
|
-
const
|
|
108
|
+
const normalizedFilePath = file.replace(/\\/g, '/');
|
|
109
|
+
const pluginImport = await import(normalizedFilePath);
|
|
107
110
|
const plugin = pluginImport.default;
|
|
108
111
|
plugin.pluginName = pluginFullName;
|
|
109
|
-
plugins.push(
|
|
112
|
+
plugins.push(plugin);
|
|
110
113
|
loadedPluginNames.add(pluginFullName);
|
|
111
114
|
} catch (err: any) {
|
|
112
115
|
Logger.error(`组件${addon} ${fileName} 导入失败`, err);
|
|
@@ -128,13 +131,14 @@ async function scanUserPlugins(loadedPluginNames: Set<string>): Promise<Plugin[]
|
|
|
128
131
|
return plugins;
|
|
129
132
|
}
|
|
130
133
|
|
|
131
|
-
const glob = new Bun.Glob('*.ts');
|
|
134
|
+
const glob = new Bun.Glob('*.{ts,js}');
|
|
132
135
|
for await (const file of glob.scan({
|
|
133
136
|
cwd: projectPluginDir,
|
|
134
137
|
onlyFiles: true,
|
|
135
138
|
absolute: true
|
|
136
139
|
})) {
|
|
137
|
-
|
|
140
|
+
if (file.endsWith('.d.ts')) continue;
|
|
141
|
+
const fileName = basename(file).replace(/\.(ts|js)$/, '');
|
|
138
142
|
if (fileName.startsWith('_')) continue;
|
|
139
143
|
|
|
140
144
|
const fileNameCamelCase = camelCase(fileName);
|
|
@@ -145,10 +149,11 @@ async function scanUserPlugins(loadedPluginNames: Set<string>): Promise<Plugin[]
|
|
|
145
149
|
}
|
|
146
150
|
|
|
147
151
|
try {
|
|
148
|
-
const
|
|
152
|
+
const normalizedFilePath = file.replace(/\\/g, '/');
|
|
153
|
+
const pluginImport = await import(normalizedFilePath);
|
|
149
154
|
const plugin = pluginImport.default;
|
|
150
155
|
plugin.pluginName = pluginFullName;
|
|
151
|
-
plugins.push(
|
|
156
|
+
plugins.push(plugin);
|
|
152
157
|
loadedPluginNames.add(pluginFullName);
|
|
153
158
|
} catch (err: any) {
|
|
154
159
|
Logger.error(`用户插件 ${fileName} 导入失败`, err);
|
package/main.ts
CHANGED
|
@@ -120,7 +120,7 @@ export class Befly {
|
|
|
120
120
|
});
|
|
121
121
|
|
|
122
122
|
const finalStartupTime = calcPerfTime(startTime);
|
|
123
|
-
Logger.info(`${Env.APP_NAME}
|
|
123
|
+
Logger.info(`${Env.APP_NAME} 启动成功! `);
|
|
124
124
|
Logger.info(`服务器启动耗时: ${finalStartupTime}`);
|
|
125
125
|
Logger.info(`服务器监听地址: http://${Env.APP_HOST}:${Env.APP_PORT}`);
|
|
126
126
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "befly",
|
|
3
|
-
"version": "3.8.
|
|
3
|
+
"version": "3.8.19",
|
|
4
4
|
"description": "Befly - 为 Bun 专属打造的 TypeScript API 接口框架核心引擎",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -65,5 +65,5 @@
|
|
|
65
65
|
"es-toolkit": "^1.41.0",
|
|
66
66
|
"pathe": "^2.0.3"
|
|
67
67
|
},
|
|
68
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "0619a7cfdd889be9fdd1b187c3d6522288707df0"
|
|
69
69
|
}
|