befly 3.8.18 → 3.8.20
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 +7 -6
- package/bunfig.toml +1 -1
- package/lib/database.ts +28 -25
- package/lib/dbHelper.ts +3 -3
- package/lib/jwt.ts +90 -99
- package/lib/logger.ts +44 -23
- package/lib/redisHelper.ts +19 -22
- package/lib/validator.ts +11 -4
- package/loader/loadApis.ts +69 -114
- package/loader/loadHooks.ts +65 -0
- package/loader/loadPlugins.ts +50 -219
- package/main.ts +106 -133
- package/package.json +15 -7
- package/paths.ts +20 -0
- package/plugins/cache.ts +1 -3
- package/plugins/db.ts +8 -11
- package/plugins/logger.ts +5 -3
- package/plugins/redis.ts +10 -14
- package/router/api.ts +60 -106
- package/router/root.ts +15 -12
- package/router/static.ts +54 -58
- package/sync/syncAll.ts +58 -0
- package/sync/syncApi.ts +264 -0
- package/sync/syncDb/apply.ts +194 -0
- package/sync/syncDb/constants.ts +76 -0
- package/sync/syncDb/ddl.ts +194 -0
- package/sync/syncDb/helpers.ts +200 -0
- package/sync/syncDb/index.ts +164 -0
- package/sync/syncDb/schema.ts +201 -0
- package/sync/syncDb/sqlite.ts +50 -0
- package/sync/syncDb/table.ts +321 -0
- package/sync/syncDb/tableCreate.ts +146 -0
- package/sync/syncDb/version.ts +72 -0
- package/sync/syncDb.ts +19 -0
- package/sync/syncDev.ts +206 -0
- package/sync/syncMenu.ts +331 -0
- package/tsconfig.json +2 -4
- package/types/api.d.ts +6 -0
- package/types/befly.d.ts +152 -28
- package/types/context.d.ts +29 -3
- package/types/hook.d.ts +35 -0
- package/types/index.ts +14 -1
- package/types/plugin.d.ts +6 -7
- package/types/sync.d.ts +403 -0
- package/check.ts +0 -378
- package/env.ts +0 -106
- package/lib/middleware.ts +0 -275
- package/types/env.ts +0 -65
- package/types/util.d.ts +0 -45
- package/util.ts +0 -257
package/plugins/cache.ts
CHANGED
|
@@ -11,9 +11,7 @@ import type { BeflyContext } from '../types/befly.js';
|
|
|
11
11
|
* 缓存插件
|
|
12
12
|
*/
|
|
13
13
|
const cachePlugin: Plugin = {
|
|
14
|
-
|
|
15
|
-
after: ['_db', '_redis'],
|
|
16
|
-
|
|
14
|
+
after: ['db', 'redis'],
|
|
17
15
|
async onInit(befly: BeflyContext): Promise<CacheHelper> {
|
|
18
16
|
return new CacheHelper(befly);
|
|
19
17
|
}
|
package/plugins/db.ts
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
* 初始化数据库连接和 SQL 管理器
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { Env } from '../env.js';
|
|
7
6
|
import { Logger } from '../lib/logger.js';
|
|
8
7
|
import { Database } from '../lib/database.js';
|
|
9
8
|
import { DbHelper } from '../lib/dbHelper.js';
|
|
@@ -14,21 +13,19 @@ import type { BeflyContext } from '../types/befly.js';
|
|
|
14
13
|
* 数据库插件
|
|
15
14
|
*/
|
|
16
15
|
const dbPlugin: Plugin = {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
async onInit(befly: BeflyContext): Promise<DbHelper | Record<string, never>> {
|
|
16
|
+
after: ['redis'],
|
|
17
|
+
async onInit(this: Plugin, befly: BeflyContext): Promise<DbHelper | Record<string, never>> {
|
|
21
18
|
let sql: any = null;
|
|
19
|
+
const config = this.config || {};
|
|
22
20
|
|
|
23
21
|
try {
|
|
24
|
-
|
|
22
|
+
// 默认启用,除非显式禁用
|
|
23
|
+
if (config.enable !== 0) {
|
|
25
24
|
// 创建 Bun SQL 客户端(内置连接池),并确保连接验证成功后再继续
|
|
26
|
-
//
|
|
27
|
-
const connectionTimeout =
|
|
25
|
+
// 从配置读取连接超时配置
|
|
26
|
+
// const connectionTimeout = config.connectionTimeout ? parseInt(config.connectionTimeout) : 30000;
|
|
28
27
|
|
|
29
|
-
sql = await Database.connectSql(
|
|
30
|
-
connectionTimeout
|
|
31
|
-
});
|
|
28
|
+
sql = await Database.connectSql(config);
|
|
32
29
|
|
|
33
30
|
// 创建数据库管理器实例,直接传入 sql 对象
|
|
34
31
|
const dbManager = new DbHelper(befly, sql);
|
package/plugins/logger.ts
CHANGED
|
@@ -11,11 +11,13 @@ import type { BeflyContext } from '../types/befly.js';
|
|
|
11
11
|
* 日志插件
|
|
12
12
|
*/
|
|
13
13
|
const loggerPlugin: Plugin = {
|
|
14
|
-
name: '_logger',
|
|
15
14
|
after: [],
|
|
16
|
-
|
|
17
|
-
async onInit(befly: BeflyContext): Promise<typeof Logger> {
|
|
15
|
+
async onInit(this: Plugin, befly: BeflyContext): Promise<typeof Logger> {
|
|
18
16
|
try {
|
|
17
|
+
// 配置 Logger
|
|
18
|
+
if (this.config) {
|
|
19
|
+
Logger.configure(this.config);
|
|
20
|
+
}
|
|
19
21
|
return Logger;
|
|
20
22
|
} catch (error: any) {
|
|
21
23
|
// 插件内禁止直接退出进程,抛出异常交由主流程统一处理
|
package/plugins/redis.ts
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
* 初始化 Redis 连接和助手工具
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { Env } from '../env.js';
|
|
7
6
|
import { Logger } from '../lib/logger.js';
|
|
8
7
|
import { RedisHelper } from '../lib/redisHelper.js';
|
|
9
8
|
import { Database } from '../lib/database.js';
|
|
@@ -14,21 +13,18 @@ import type { BeflyContext } from '../types/befly.js';
|
|
|
14
13
|
* Redis 插件
|
|
15
14
|
*/
|
|
16
15
|
const redisPlugin: Plugin = {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
async onInit(befly: BeflyContext): Promise<RedisHelper | Record<string, never>> {
|
|
16
|
+
after: ['logger'],
|
|
17
|
+
async onInit(this: Plugin, befly: BeflyContext): Promise<RedisHelper | Record<string, never>> {
|
|
18
|
+
const config = this.config || {};
|
|
21
19
|
try {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
// 默认启用,除非显式禁用 (这里假设只要配置了 redis 插件就启用,或者检查 enable 字段)
|
|
21
|
+
// 为了兼容性,如果 config 为空,可能意味着使用默认值连接本地 redis
|
|
22
|
+
|
|
23
|
+
// 初始化 Redis 客户端(统一使用 database.ts 的连接管理)
|
|
24
|
+
await Database.connectRedis(config);
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
} else {
|
|
29
|
-
Logger.warn('Redis 未启用,跳过初始化');
|
|
30
|
-
return {};
|
|
31
|
-
}
|
|
26
|
+
// 返回 RedisHelper 实例
|
|
27
|
+
return new RedisHelper(config.prefix);
|
|
32
28
|
} catch (error: any) {
|
|
33
29
|
Logger.error('Redis 初始化失败', error);
|
|
34
30
|
|
package/router/api.ts
CHANGED
|
@@ -3,129 +3,83 @@
|
|
|
3
3
|
* 处理 /api/* 路径的请求
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
import type { RequestContext } from '../
|
|
6
|
+
// 相对导入
|
|
7
|
+
import { compose, JsonResponse } from '../util.js';
|
|
8
|
+
|
|
9
|
+
// 类型导入
|
|
10
|
+
import type { RequestContext } from '../types/context.js';
|
|
11
11
|
import type { ApiRoute } from '../types/api.js';
|
|
12
|
-
import type {
|
|
12
|
+
import type { Hook } from '../types/hook.js';
|
|
13
13
|
import type { BeflyContext } from '../types/befly.js';
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* API处理器工厂函数
|
|
17
17
|
* @param apiRoutes - API路由映射表
|
|
18
|
-
* @param
|
|
18
|
+
* @param hookLists - 钩子列表
|
|
19
19
|
* @param appContext - 应用上下文
|
|
20
20
|
*/
|
|
21
|
-
export function apiHandler(apiRoutes: Map<string, ApiRoute>,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
let ctx: RequestContext | null = null;
|
|
25
|
-
let api: ApiRoute | undefined;
|
|
26
|
-
let apiPath = '';
|
|
27
|
-
|
|
28
|
-
try {
|
|
29
|
-
// 1. OPTIONS预检请求
|
|
30
|
-
if (req.method === 'OPTIONS') {
|
|
31
|
-
return handleOptionsRequest(corsOptions);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// 2. 创建请求上下文
|
|
35
|
-
ctx = {
|
|
36
|
-
body: {},
|
|
37
|
-
user: {},
|
|
38
|
-
request: req,
|
|
39
|
-
startTime: Date.now()
|
|
40
|
-
};
|
|
21
|
+
export function apiHandler(apiRoutes: Map<string, ApiRoute>, hookLists: Hook[], appContext: BeflyContext) {
|
|
22
|
+
// 提取所有钩子的处理函数
|
|
23
|
+
const middleware = hookLists.map((h) => h.handler);
|
|
41
24
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
apiPath = `${req.method}${url.pathname}`;
|
|
45
|
-
api = apiRoutes.get(apiPath);
|
|
25
|
+
// 组合钩子链
|
|
26
|
+
const fn = compose(middleware);
|
|
46
27
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
28
|
+
return async (req: Request): Promise<Response> => {
|
|
29
|
+
// 1. 创建请求上下文
|
|
30
|
+
const url = new URL(req.url);
|
|
31
|
+
const apiPath = `${req.method}${url.pathname}`;
|
|
32
|
+
|
|
33
|
+
const ctx: RequestContext = {
|
|
34
|
+
body: {},
|
|
35
|
+
user: {},
|
|
36
|
+
req: req,
|
|
37
|
+
now: Date.now(),
|
|
38
|
+
corsHeaders: {},
|
|
39
|
+
ip: req.headers.get('x-forwarded-for')?.split(',')[0]?.trim() || req.headers.get('x-real-ip') || 'unknown',
|
|
40
|
+
route: apiPath
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// 2. 获取API路由
|
|
44
|
+
const api = apiRoutes.get(apiPath);
|
|
45
|
+
|
|
46
|
+
// 注意:即使 api 不存在,也需要执行插件链(以便处理 CORS OPTIONS 请求或 404 响应)
|
|
47
|
+
// 如果是 OPTIONS 请求,通常不需要 api 对象
|
|
48
|
+
if (api) {
|
|
49
|
+
ctx.api = api;
|
|
50
|
+
}
|
|
55
51
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
52
|
+
// 3. 执行插件链(洋葱模型)
|
|
53
|
+
// 错误处理已由 errorHandler 插件接管
|
|
54
|
+
await fn(appContext, ctx, async () => {
|
|
55
|
+
// 核心执行器:执行 API handler
|
|
56
|
+
// 如果没有找到 API 且没有被前面的插件拦截(如 CORS),则返回 404
|
|
57
|
+
if (!ctx.api) {
|
|
58
|
+
// 只有非 OPTIONS 请求才报 404(OPTIONS 请求通常由 cors 插件处理并返回)
|
|
59
|
+
if (req.method !== 'OPTIONS') {
|
|
60
|
+
ctx.response = JsonResponse(ctx, '接口不存在');
|
|
65
61
|
}
|
|
62
|
+
return;
|
|
66
63
|
}
|
|
67
64
|
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
if (ctx.api.handler) {
|
|
66
|
+
const result = await ctx.api.handler(appContext, ctx, req);
|
|
70
67
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
// 使用 Redis SISMEMBER 直接判断接口是否在角色权限集合中(O(1)复杂度)
|
|
78
|
-
const roleApisKey = `role:apis:${ctx.user.roleCode}`;
|
|
79
|
-
const isMember = await appContext.redis.sismember(roleApisKey, apiPath);
|
|
80
|
-
hasPermission = isMember === 1;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const permissionResult = checkPermission(api, ctx, hasPermission);
|
|
84
|
-
if (permissionResult.code !== 0) {
|
|
85
|
-
return Response.json(permissionResult, {
|
|
86
|
-
headers: corsOptions.headers
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// 9. 参数验证
|
|
91
|
-
const validateResult = validateParams(api, ctx);
|
|
92
|
-
if (validateResult.code !== 0) {
|
|
93
|
-
return Response.json(No('无效的请求参数格式', validateResult.fields), {
|
|
94
|
-
headers: corsOptions.headers
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// 10. 执行API处理器
|
|
99
|
-
const result = await api.handler(appContext, ctx, req);
|
|
100
|
-
|
|
101
|
-
// 11. 返回响应
|
|
102
|
-
// 🔥 新增:直接返回 Response 对象
|
|
103
|
-
if (result instanceof Response) {
|
|
104
|
-
return result;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// 12. 返回响应
|
|
108
|
-
if (result && typeof result === 'object' && 'code' in result) {
|
|
109
|
-
// 处理 BigInt 序列化问题
|
|
110
|
-
const jsonString = JSON.stringify(result, (key, value) => (typeof value === 'bigint' ? value.toString() : value));
|
|
111
|
-
return new Response(jsonString, {
|
|
112
|
-
headers: {
|
|
113
|
-
...corsOptions.headers,
|
|
114
|
-
'Content-Type': 'application/json'
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
} else {
|
|
118
|
-
return new Response(result, {
|
|
119
|
-
headers: corsOptions.headers
|
|
120
|
-
});
|
|
68
|
+
if (result instanceof Response) {
|
|
69
|
+
ctx.response = result;
|
|
70
|
+
} else {
|
|
71
|
+
// 将结果存入 ctx.result,由 responseFormatter 插件统一处理
|
|
72
|
+
ctx.result = result;
|
|
73
|
+
}
|
|
121
74
|
}
|
|
122
|
-
}
|
|
123
|
-
// 记录详细的错误日志
|
|
124
|
-
Logger.error(api ? `接口 [${api.name}] 执行失败` : '处理接口请求时发生错误', error);
|
|
75
|
+
});
|
|
125
76
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
77
|
+
// 4. 返回响应
|
|
78
|
+
if (ctx.response) {
|
|
79
|
+
return ctx.response;
|
|
129
80
|
}
|
|
81
|
+
|
|
82
|
+
// 兜底响应(理论上不应执行到这里,responseFormatter 会处理)
|
|
83
|
+
return JsonResponse(ctx, 'No response generated');
|
|
130
84
|
};
|
|
131
85
|
}
|
package/router/root.ts
CHANGED
|
@@ -3,29 +3,29 @@
|
|
|
3
3
|
* 处理 / 路径的请求
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
import { setCorsOptions } from '../lib/middleware.js';
|
|
6
|
+
// 相对导入
|
|
8
7
|
import { Logger } from '../lib/logger.js';
|
|
9
|
-
import {
|
|
8
|
+
import { setCorsOptions } from '../util.js';
|
|
10
9
|
|
|
11
10
|
/**
|
|
12
11
|
* 根路径处理器
|
|
13
12
|
*/
|
|
14
13
|
export async function rootHandler(req: Request): Promise<Response> {
|
|
15
|
-
|
|
14
|
+
// 设置 CORS 响应头
|
|
15
|
+
const corsHeaders = setCorsOptions(req);
|
|
16
16
|
|
|
17
17
|
try {
|
|
18
18
|
return Response.json(
|
|
19
19
|
{
|
|
20
20
|
code: 0,
|
|
21
|
-
msg:
|
|
21
|
+
msg: `Befly 接口服务已启动`,
|
|
22
22
|
data: {
|
|
23
|
-
mode:
|
|
23
|
+
mode: process.env.NODE_ENV || 'development',
|
|
24
24
|
timestamp: Date.now()
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
|
-
headers:
|
|
28
|
+
headers: corsHeaders
|
|
29
29
|
}
|
|
30
30
|
);
|
|
31
31
|
} catch (error: any) {
|
|
@@ -37,7 +37,7 @@ export async function rootHandler(req: Request): Promise<Response> {
|
|
|
37
37
|
let errorDetail = {};
|
|
38
38
|
|
|
39
39
|
// 开发环境返回详细错误信息
|
|
40
|
-
if (
|
|
40
|
+
if (process.env.NODE_ENV === 'development') {
|
|
41
41
|
errorDetail = {
|
|
42
42
|
type: error.constructor?.name || 'Error',
|
|
43
43
|
message: error.message,
|
|
@@ -45,9 +45,12 @@ export async function rootHandler(req: Request): Promise<Response> {
|
|
|
45
45
|
};
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
return Response.json(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
return Response.json(
|
|
49
|
+
{ code: 1, msg: errorMessage, data: errorDetail },
|
|
50
|
+
{
|
|
51
|
+
status: 500,
|
|
52
|
+
headers: corsHeaders
|
|
53
|
+
}
|
|
54
|
+
);
|
|
52
55
|
}
|
|
53
56
|
}
|
package/router/static.ts
CHANGED
|
@@ -3,74 +3,70 @@
|
|
|
3
3
|
* 处理 /* 路径的静态文件请求
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
// 外部依赖
|
|
6
7
|
import { join } from 'pathe';
|
|
8
|
+
|
|
9
|
+
// 相对导入
|
|
7
10
|
import { projectDir } from '../paths.js';
|
|
8
|
-
import { No } from '../util.js';
|
|
9
|
-
import { setCorsOptions } from '../lib/middleware.js';
|
|
10
11
|
import { Logger } from '../lib/logger.js';
|
|
11
|
-
import {
|
|
12
|
+
import { setCorsOptions } from '../util.js';
|
|
13
|
+
|
|
14
|
+
// 类型导入
|
|
15
|
+
import type { CorsConfig } from '../types/befly.js';
|
|
12
16
|
|
|
13
17
|
/**
|
|
14
|
-
*
|
|
18
|
+
* 静态文件处理器工厂
|
|
19
|
+
* @param corsConfig - CORS 配置
|
|
15
20
|
*/
|
|
16
|
-
export
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
21
|
+
export function staticHandler(corsConfig: CorsConfig = {}) {
|
|
22
|
+
return async (req: Request): Promise<Response> => {
|
|
23
|
+
// 设置 CORS 响应头
|
|
24
|
+
const corsHeaders = setCorsOptions(req, corsConfig);
|
|
20
25
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (req.method === 'OPTIONS') {
|
|
24
|
-
return new Response(null, {
|
|
25
|
-
status: 204,
|
|
26
|
-
headers: corsOptions.headers
|
|
27
|
-
});
|
|
28
|
-
}
|
|
26
|
+
const url = new URL(req.url);
|
|
27
|
+
const filePath = join(projectDir, 'public', url.pathname);
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
} else {
|
|
39
|
-
return Response.json(No('文件未找到'), {
|
|
40
|
-
status: 404,
|
|
41
|
-
headers: corsOptions.headers
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
} catch (error: any) {
|
|
45
|
-
// 记录详细的错误日志
|
|
46
|
-
Logger.error('静态文件处理失败', error);
|
|
29
|
+
try {
|
|
30
|
+
// OPTIONS预检请求
|
|
31
|
+
if (req.method === 'OPTIONS') {
|
|
32
|
+
return new Response(null, {
|
|
33
|
+
status: 204,
|
|
34
|
+
headers: corsHeaders
|
|
35
|
+
});
|
|
36
|
+
}
|
|
47
37
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
38
|
+
const file = Bun.file(filePath);
|
|
39
|
+
if (await file.exists()) {
|
|
40
|
+
return new Response(file, {
|
|
41
|
+
headers: {
|
|
42
|
+
'Content-Type': file.type || 'application/octet-stream',
|
|
43
|
+
...corsHeaders
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
} else {
|
|
47
|
+
return Response.json(
|
|
48
|
+
{ code: 1, msg: '文件未找到' },
|
|
49
|
+
{
|
|
50
|
+
status: 404,
|
|
51
|
+
headers: corsHeaders
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
} catch (error: any) {
|
|
56
|
+
// 记录详细的错误日志
|
|
57
|
+
Logger.error('静态文件处理失败', error);
|
|
51
58
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
// 路径错误
|
|
57
|
-
else if (error.message?.includes('ENOENT') || error.message?.includes('not found')) {
|
|
58
|
-
errorMessage = '文件路径不存在';
|
|
59
|
-
}
|
|
59
|
+
// 根据错误类型返回不同的错误信息
|
|
60
|
+
let errorMessage = '文件读取失败';
|
|
61
|
+
let errorDetail = {};
|
|
60
62
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
};
|
|
63
|
+
return Response.json(
|
|
64
|
+
{ code: 1, msg: errorMessage, data: errorDetail },
|
|
65
|
+
{
|
|
66
|
+
status: 500,
|
|
67
|
+
headers: corsHeaders
|
|
68
|
+
}
|
|
69
|
+
);
|
|
69
70
|
}
|
|
70
|
-
|
|
71
|
-
return Response.json(No(errorMessage, errorDetail), {
|
|
72
|
-
status: 500,
|
|
73
|
-
headers: corsOptions.headers
|
|
74
|
-
});
|
|
75
|
-
}
|
|
71
|
+
};
|
|
76
72
|
}
|
package/sync/syncAll.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync 命令 - 一次性执行所有同步操作
|
|
3
|
+
* 按顺序执行:syncDb → syncApi → syncMenu → syncDev
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { checkApp } from '../checks/checkApp.js';
|
|
7
|
+
import { Logger } from '../lib/logger.js';
|
|
8
|
+
import { syncDbCommand } from './syncDb.js';
|
|
9
|
+
import { syncApiCommand } from './syncApi.js';
|
|
10
|
+
import { syncMenuCommand } from './syncMenu.js';
|
|
11
|
+
import { syncDevCommand } from './syncDev.js';
|
|
12
|
+
import type { SyncOptions, BeflyOptions } from '../types/index.js';
|
|
13
|
+
|
|
14
|
+
export async function syncAllCommand(config: BeflyOptions, options: SyncOptions = {}) {
|
|
15
|
+
try {
|
|
16
|
+
const startTime = Date.now();
|
|
17
|
+
|
|
18
|
+
// 0. 检查项目结构
|
|
19
|
+
Logger.debug('🔍 正在检查项目结构...');
|
|
20
|
+
const checkResult = await checkApp();
|
|
21
|
+
if (!checkResult) {
|
|
22
|
+
Logger.error('项目结构检查失败,程序退出');
|
|
23
|
+
throw new Error('项目结构检查失败');
|
|
24
|
+
}
|
|
25
|
+
Logger.debug(`✓ 项目结构检查完成\n`);
|
|
26
|
+
|
|
27
|
+
Logger.debug('开始执行同步任务...\n');
|
|
28
|
+
|
|
29
|
+
// 1. 同步数据库表结构
|
|
30
|
+
Logger.debug('📦 正在同步数据库...');
|
|
31
|
+
await syncDbCommand(config, { dryRun: false, force: options.force || false });
|
|
32
|
+
Logger.debug(`✓ 数据库同步完成\n`);
|
|
33
|
+
|
|
34
|
+
// 2. 同步接口(并缓存)
|
|
35
|
+
Logger.debug('🔌 正在同步接口...');
|
|
36
|
+
await syncApiCommand(config);
|
|
37
|
+
Logger.debug(`✓ 接口同步完成\n`);
|
|
38
|
+
|
|
39
|
+
// 3. 同步菜单(并缓存)
|
|
40
|
+
Logger.debug('📋 正在同步菜单...');
|
|
41
|
+
await syncMenuCommand(config);
|
|
42
|
+
Logger.debug(`✓ 菜单同步完成\n`);
|
|
43
|
+
|
|
44
|
+
// 4. 同步开发管理员(并缓存角色权限)
|
|
45
|
+
Logger.debug('👤 正在同步开发账号...');
|
|
46
|
+
await syncDevCommand(config);
|
|
47
|
+
Logger.debug(`✓ 开发账号同步完成\n`);
|
|
48
|
+
|
|
49
|
+
// 输出总结
|
|
50
|
+
const totalTimeSeconds = ((Date.now() - startTime) / 1000).toFixed(2);
|
|
51
|
+
Logger.debug('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
52
|
+
Logger.debug(`✅ 同步完成!总耗时: ${totalTimeSeconds} 秒`);
|
|
53
|
+
Logger.debug('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
|
|
54
|
+
} catch (error: any) {
|
|
55
|
+
Logger.error('同步过程中发生错误', error);
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
}
|