befly 2.3.2 → 2.3.3
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/bin/befly.js +109 -0
- package/checks/table.js +71 -86
- package/config/env.js +10 -8
- package/package.json +7 -14
- package/plugins/db.js +2 -2
- package/scripts/syncDb.js +585 -436
- package/scripts/syncDev.js +96 -0
- package/tables/common.json +10 -10
- package/tables/tool.json +3 -3
- package/utils/index.js +80 -133
- package/utils/sqlManager.js +1 -1
- package/utils/validate.js +7 -9
package/bin/befly.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env -S bun run
|
|
2
|
+
// Befly CLI (Bun): 列出并执行 core/scripts 与 tpl/scripts 下的脚本
|
|
3
|
+
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { Glob } from 'bun';
|
|
6
|
+
import { __dirscript as coreScriptsDir, getProjectDir } from '../system.js';
|
|
7
|
+
|
|
8
|
+
// 解析目录(来自 system.js)
|
|
9
|
+
// 核心脚本目录:core/scripts
|
|
10
|
+
// 用户项目(如 tpl)的脚本目录:始终基于当前工作目录
|
|
11
|
+
const tplScriptsDir = getProjectDir('scripts');
|
|
12
|
+
|
|
13
|
+
function safeList(dir) {
|
|
14
|
+
try {
|
|
15
|
+
// 使用 Bun.Glob 查找当前目录下的所有 .js 文件(不递归)
|
|
16
|
+
const glob = new Glob('*.js');
|
|
17
|
+
const files = Array.from(glob.scanSync({ cwd: dir, absolute: false, onlyFiles: true, dot: false }));
|
|
18
|
+
return files.map((f) => path.basename(f, '.js')).sort();
|
|
19
|
+
} catch {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function buildScriptItems() {
|
|
25
|
+
const coreList = safeList(coreScriptsDir);
|
|
26
|
+
const tplList = safeList(tplScriptsDir);
|
|
27
|
+
const coreSet = new Set(coreList);
|
|
28
|
+
|
|
29
|
+
const items = [];
|
|
30
|
+
for (const name of coreList) {
|
|
31
|
+
items.push({
|
|
32
|
+
name: name,
|
|
33
|
+
source: 'core',
|
|
34
|
+
duplicate: tplList.includes(name),
|
|
35
|
+
path: path.resolve(coreScriptsDir, `${name}.js`)
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
for (const name of tplList) {
|
|
39
|
+
items.push({
|
|
40
|
+
name: name,
|
|
41
|
+
source: 'tpl',
|
|
42
|
+
duplicate: coreSet.has(name),
|
|
43
|
+
path: path.resolve(tplScriptsDir, `${name}.js`)
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
// 排序:名称字典序,core 在前
|
|
47
|
+
items.sort((a, b) => (a.name === b.name ? (a.source === b.source ? 0 : a.source === 'core' ? -1 : 1) : a.name.localeCompare(b.name)));
|
|
48
|
+
return items;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function printAllScripts() {
|
|
52
|
+
const items = buildScriptItems();
|
|
53
|
+
if (items.length === 0) {
|
|
54
|
+
console.log(' • <无>');
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
for (const it of items) {
|
|
58
|
+
if (it.source === 'tpl' && it.duplicate) console.log(` • ${it.name}(重复)`);
|
|
59
|
+
else console.log(` • ${it.name}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function resolveScriptPath(name) {
|
|
64
|
+
const base = name.endsWith('.js') ? name.slice(0, -3) : name;
|
|
65
|
+
const filename = `${base}.js`;
|
|
66
|
+
const corePath = path.resolve(coreScriptsDir, filename);
|
|
67
|
+
const tplPath = path.resolve(tplScriptsDir, filename);
|
|
68
|
+
if (await Bun.file(corePath).exists()) return corePath;
|
|
69
|
+
if (await Bun.file(tplPath).exists()) return tplPath;
|
|
70
|
+
// 回退到列表匹配(防止极端路径或大小写差异)
|
|
71
|
+
const items = buildScriptItems();
|
|
72
|
+
const hit = items.find((it) => it.name.toLowerCase() === base.toLowerCase() && it.source === 'core') || items.find((it) => it.name.toLowerCase() === base.toLowerCase());
|
|
73
|
+
return hit ? hit.path : null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async function runScriptAtPath(targetPath, label, args = []) {
|
|
77
|
+
const bunExe = process.execPath || 'bun';
|
|
78
|
+
const child = Bun.spawn({
|
|
79
|
+
cmd: [bunExe, targetPath, ...args],
|
|
80
|
+
stdio: ['inherit', 'inherit', 'inherit'],
|
|
81
|
+
cwd: process.cwd(),
|
|
82
|
+
env: { ...process.env, LOG_TO_CONSOLE: '1' }
|
|
83
|
+
});
|
|
84
|
+
const code = await child.exited;
|
|
85
|
+
return code ?? 0;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function main() {
|
|
89
|
+
const [, , cmd, ...args] = process.argv;
|
|
90
|
+
// 无参数:打印所有脚本
|
|
91
|
+
if (!cmd) {
|
|
92
|
+
printAllScripts();
|
|
93
|
+
process.exit(0);
|
|
94
|
+
}
|
|
95
|
+
// 按名称执行(将剩余参数透传给脚本)
|
|
96
|
+
const target = await resolveScriptPath(cmd);
|
|
97
|
+
if (!target) {
|
|
98
|
+
console.error(`未找到脚本: ${cmd}`);
|
|
99
|
+
printAllScripts();
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
const code = await runScriptAtPath(target, cmd, args);
|
|
103
|
+
process.exit(code ?? 0);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
main().catch((e) => {
|
|
107
|
+
console.error('Befly CLI 执行失败:', e);
|
|
108
|
+
process.exit(1);
|
|
109
|
+
});
|
package/checks/table.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { Logger } from '../utils/logger.js';
|
|
3
|
-
import {
|
|
3
|
+
import { parseRule } from '../utils/index.js';
|
|
4
4
|
import { __dirtables, getProjectDir } from '../system.js';
|
|
5
5
|
|
|
6
6
|
// 所有校验函数均复用 utils/index.js 导出的实现
|
|
@@ -65,8 +65,9 @@ export const checkTable = async () => {
|
|
|
65
65
|
const lowerCamelCaseRegex = /^[a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)*$/;
|
|
66
66
|
if (!lowerCamelCaseRegex.test(fileBaseName)) {
|
|
67
67
|
Logger.error(`${fileType}表 ${fileName} 文件名必须使用小驼峰命名(例如 testCustomers.json)`);
|
|
68
|
-
//
|
|
69
|
-
|
|
68
|
+
// 命名不合规,按保留字段处理模式:记录错误并计为无效文件,继续下一个文件
|
|
69
|
+
invalidFiles++;
|
|
70
|
+
continue;
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
// 读取并解析 JSON 文件
|
|
@@ -75,126 +76,110 @@ export const checkTable = async () => {
|
|
|
75
76
|
let fileRules = 0;
|
|
76
77
|
|
|
77
78
|
// 检查 table 中的每个验证规则
|
|
78
|
-
for (const [
|
|
79
|
-
fileRules++;
|
|
80
|
-
totalRules++;
|
|
81
|
-
|
|
82
|
-
// 检查是否使用了保留字段
|
|
83
|
-
if (reservedFields.includes(fieldName)) {
|
|
84
|
-
Logger.error(`${fileType}表 ${fileName} 文件包含保留字段 ${fieldName},不能在表定义中使用以下字段: ${reservedFields.join(', ')}`);
|
|
85
|
-
fileValid = false;
|
|
86
|
-
continue;
|
|
87
|
-
}
|
|
88
|
-
|
|
79
|
+
for (const [colKey, rule] of Object.entries(table)) {
|
|
89
80
|
// 验证规则格式
|
|
90
81
|
try {
|
|
91
|
-
|
|
82
|
+
fileRules++;
|
|
83
|
+
totalRules++;
|
|
92
84
|
|
|
93
|
-
|
|
94
|
-
|
|
85
|
+
// 检查是否使用了保留字段
|
|
86
|
+
if (reservedFields.includes(colKey)) {
|
|
87
|
+
Logger.error(`${fileType}表 ${fileName} 文件包含保留字段 ${colKey},不能在表定义中使用以下字段: ${reservedFields.join(', ')}`);
|
|
95
88
|
fileValid = false;
|
|
96
|
-
continue;
|
|
97
89
|
}
|
|
98
90
|
|
|
99
|
-
const
|
|
91
|
+
const allParts = rule.split('⚡');
|
|
92
|
+
|
|
93
|
+
// 必须包含7个部分:显示名⚡类型⚡最小值⚡最大值⚡默认值⚡是否索引⚡正则约束
|
|
94
|
+
if (allParts.length !== 7) {
|
|
95
|
+
Logger.error(`${fileType}表 ${fileName} 文件 ${colKey} 字段规则格式错误,必须包含7个部分,当前包含${allParts.length}个部分`);
|
|
96
|
+
fileValid = false;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const [fieldName, fieldType, fieldMin, fieldMax, fieldDefault, fieldIndex, fieldRegx] = allParts;
|
|
100
100
|
|
|
101
|
-
// 使用新的验证函数进行严格验证
|
|
102
101
|
// 第1个值:名称必须为中文、数字、字母
|
|
103
|
-
if (
|
|
104
|
-
Logger.error(`${fileType}表 ${fileName} 文件 ${
|
|
102
|
+
if (!/^[\u4e00-\u9fa5a-zA-Z0-9 _-]+$/.test(fieldName)) {
|
|
103
|
+
Logger.error(`${fileType}表 ${fileName} 文件 ${colKey} 字段名称 "${fieldName}" 格式错误,必须为中文、数字、字母、下划线、短横线`);
|
|
105
104
|
fileValid = false;
|
|
106
|
-
continue;
|
|
107
105
|
}
|
|
108
106
|
|
|
109
107
|
// 第2个值:字段类型必须为string,number,text,array之一
|
|
110
|
-
if (!
|
|
111
|
-
Logger.error(`${fileType}表 ${fileName} 文件 ${
|
|
108
|
+
if (!['string', 'number', 'text', 'array'].includes(fieldType)) {
|
|
109
|
+
Logger.error(`${fileType}表 ${fileName} 文件 ${colKey} 字段类型 "${fieldType}" 格式错误,必须为string、number、text、array之一`);
|
|
112
110
|
fileValid = false;
|
|
113
|
-
continue;
|
|
114
111
|
}
|
|
115
112
|
|
|
116
|
-
// 第3
|
|
117
|
-
if (!
|
|
118
|
-
Logger.error(`${fileType}表 ${fileName} 文件 ${
|
|
113
|
+
// 第3/4个值:需要是 null 或 数字(并包含最小值<=最大值的约束)
|
|
114
|
+
if (!(fieldMin === 'null' || !Number.isNaN(Number(fieldMin)))) {
|
|
115
|
+
Logger.error(`${fileType}表 ${fileName} 文件 ${colKey} 最小值 "${fieldMin}" 格式错误,必须为null或数字`);
|
|
116
|
+
fileValid = false;
|
|
117
|
+
}
|
|
118
|
+
if (!(fieldMax === 'null' || !Number.isNaN(Number(fieldMax)))) {
|
|
119
|
+
Logger.error(`${fileType}表 ${fileName} 文件 ${colKey} 最大值 "${fieldMax}" 格式错误,必须为null或数字`);
|
|
119
120
|
fileValid = false;
|
|
120
|
-
continue;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
//
|
|
124
|
-
if (
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
Logger.error(`${fileType}表 ${fileName} 文件 ${fieldName} 的 text 类型最小值必须为 null,当前为 "${minStr}"`);
|
|
123
|
+
// 约束:当最小值与最大值均为数字时,要求最小值 <= 最大值
|
|
124
|
+
if (fieldMin !== 'null' && fieldMax !== 'null') {
|
|
125
|
+
if (Number(fieldMin) > Number(fieldMax)) {
|
|
126
|
+
Logger.error(`${fileType}表 ${fileName} 文件 ${colKey} 最小值 "${fieldMin}" 不能大于最大值 "${fieldMax}"`);
|
|
128
127
|
fileValid = false;
|
|
129
|
-
continue;
|
|
130
128
|
}
|
|
131
|
-
|
|
132
|
-
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// 第6个值:是否创建索引必须为0或1
|
|
132
|
+
if (fieldIndex !== '0' && fieldIndex !== '1') {
|
|
133
|
+
Logger.error(`${fileType}表 ${fileName} 文件 ${colKey} 索引标识 "${fieldIndex}" 格式错误,必须为0或1`);
|
|
134
|
+
fileValid = false;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// 第7个值:必须为null或正则表达式
|
|
138
|
+
if (fieldRegx !== 'null') {
|
|
139
|
+
try {
|
|
140
|
+
// 仅尝试构造以校验有效性
|
|
141
|
+
// eslint-disable-next-line no-new
|
|
142
|
+
new RegExp(fieldRegx);
|
|
143
|
+
} catch (_) {
|
|
144
|
+
Logger.error(`${fileType}表 ${fileName} 文件 ${colKey} 正则约束 "${fieldRegx}" 格式错误,必须为null或有效的正则表达式`);
|
|
133
145
|
fileValid = false;
|
|
134
|
-
continue;
|
|
135
146
|
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// 第4个值与类型联动校验 + 默认值规则(精简实现)
|
|
150
|
+
if (fieldType === 'text') {
|
|
151
|
+
// text:min/max 必须为 null,默认值必须为 'null'
|
|
152
|
+
if (fieldMin !== 'null') {
|
|
153
|
+
Logger.error(`${fileType}表 ${fileName} 文件 ${colKey} 的 text 类型最小值必须为 null,当前为 "${fieldMin}"`);
|
|
140
154
|
fileValid = false;
|
|
141
|
-
continue;
|
|
142
155
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
Logger.error(`${fileType}表 ${fileName} 文件 ${fieldName} 最大长度 ${maxStr} 越界,string 类型长度必须在 1..65535 范围内`);
|
|
156
|
+
if (fieldMax !== 'null') {
|
|
157
|
+
Logger.error(`${fileType}表 ${fileName} 文件 ${colKey} 的 text 类型最大长度必须为 null,当前为 "${fieldMax}"`);
|
|
146
158
|
fileValid = false;
|
|
147
|
-
continue;
|
|
148
159
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if (maxStr === 'null' || !validateMinMax(maxStr)) {
|
|
152
|
-
Logger.error(`${fileType}表 ${fileName} 文件 ${fieldName} 最大长度 "${maxStr}" 格式错误,array 类型必须为具体数字`);
|
|
160
|
+
if (fieldDefault !== 'null') {
|
|
161
|
+
Logger.error(`${fileType}表 ${fileName} 文件 ${colKey} 为 text 类型,默认值必须为 null,当前为 "${fieldDefault}"`);
|
|
153
162
|
fileValid = false;
|
|
154
|
-
continue;
|
|
155
163
|
}
|
|
156
|
-
} else {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
Logger.error(`${fileType}表 ${fileName} 文件 ${fieldName} 最大值 "${maxStr}" 格式错误,必须为null或数字`);
|
|
164
|
+
} else if (fieldType === 'string' || fieldType === 'array') {
|
|
165
|
+
if (Number.isNaN(Number(fieldMax))) {
|
|
166
|
+
Logger.error(`${fileType}表 ${fileName} 文件 ${colKey} 为 string,array 类型,最大长度必须为数字,当前为 "${fieldMax}"`);
|
|
160
167
|
fileValid = false;
|
|
161
|
-
continue;
|
|
162
168
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
if (type === 'text') {
|
|
167
|
-
// text 不允许默认值
|
|
168
|
-
if (defaultValue !== 'null') {
|
|
169
|
-
Logger.error(`${fileType}表 ${fileName} 文件 ${fieldName} 为 text 类型,默认值必须为 null,当前为 "${defaultValue}"`);
|
|
169
|
+
const maxVal = parseInt(fieldMax, 10);
|
|
170
|
+
if (maxVal > 65535) {
|
|
171
|
+
Logger.error(`${fileType}表 ${fileName} 文件 ${colKey} 最大长度 ${fieldMax} 越界,string,array 类型长度必须在 1..65535 范围内`);
|
|
170
172
|
fileValid = false;
|
|
171
|
-
continue;
|
|
172
173
|
}
|
|
173
|
-
} else {
|
|
174
|
-
if (
|
|
175
|
-
Logger.error(`${fileType}表 ${fileName} 文件 ${
|
|
174
|
+
} else if (fieldType === 'number') {
|
|
175
|
+
if (Number.isNaN(Number(fieldDefault))) {
|
|
176
|
+
Logger.error(`${fileType}表 ${fileName} 文件 ${colKey} 为 number 类型,默认值必须为数字,当前为 "${fieldDefault}"`);
|
|
176
177
|
fileValid = false;
|
|
177
|
-
continue;
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
|
-
|
|
181
|
-
// 第6个值:是否创建索引必须为0或1
|
|
182
|
-
if (!validateIndex(isIndexStr)) {
|
|
183
|
-
Logger.error(`${fileType}表 ${fileName} 文件 ${fieldName} 索引标识 "${isIndexStr}" 格式错误,必须为0或1`);
|
|
184
|
-
fileValid = false;
|
|
185
|
-
continue;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// 第7个值:必须为null或正则表达式
|
|
189
|
-
if (!validateRegex(regexConstraint)) {
|
|
190
|
-
Logger.error(`${fileType}表 ${fileName} 文件 ${fieldName} 正则约束 "${regexConstraint}" 格式错误,必须为null或有效的正则表达式`);
|
|
191
|
-
fileValid = false;
|
|
192
|
-
continue;
|
|
193
|
-
}
|
|
194
180
|
} catch (error) {
|
|
195
|
-
Logger.error(`${fileType}表 ${fileName} 文件 ${
|
|
181
|
+
Logger.error(`${fileType}表 ${fileName} 文件 ${colKey} 验证规则解析失败: ${error.message}`);
|
|
196
182
|
fileValid = false;
|
|
197
|
-
continue;
|
|
198
183
|
}
|
|
199
184
|
}
|
|
200
185
|
|
package/config/env.js
CHANGED
|
@@ -24,14 +24,16 @@ export const Env = {
|
|
|
24
24
|
// 时区
|
|
25
25
|
TZ: process.env.TZ,
|
|
26
26
|
// 数据库配置
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
DB_ENABLE: Number(process.env.DB_ENABLE),
|
|
28
|
+
// 通用数据库连接参数
|
|
29
|
+
DB_TYPE: process.env.DB_TYPE, // sqlite | mysql | postgresql
|
|
30
|
+
DB_HOST: process.env.DB_HOST,
|
|
31
|
+
DB_PORT: Number(process.env.DB_PORT),
|
|
32
|
+
DB_USER: process.env.DB_USER,
|
|
33
|
+
DB_PASS: process.env.DB_PASS,
|
|
34
|
+
DB_NAME: process.env.DB_NAME,
|
|
35
|
+
DB_DEBUG: Number(process.env.DB_DEBUG),
|
|
36
|
+
DB_POOL_MAX: Number(process.env.DB_POOL_MAX),
|
|
35
37
|
// Redis配置
|
|
36
38
|
REDIS_URL: process.env.REDIS_URL,
|
|
37
39
|
REDIS_ENABLE: Number(process.env.REDIS_ENABLE),
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "befly",
|
|
3
|
-
"version": "2.3.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.3.3",
|
|
4
|
+
"description": "Befly - 为 Bun 专属打造的 API 接口框架核心引擎",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
7
7
|
"publishConfig": {
|
|
@@ -12,11 +12,10 @@
|
|
|
12
12
|
"exports": {
|
|
13
13
|
".": "./main.js"
|
|
14
14
|
},
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"rb": "bun run ../release.js --minor",
|
|
18
|
-
"rc": "bun run ../release.js --patch"
|
|
15
|
+
"bin": {
|
|
16
|
+
"befly": "./bin/befly.js"
|
|
19
17
|
},
|
|
18
|
+
"scripts": {},
|
|
20
19
|
"keywords": [
|
|
21
20
|
"bun",
|
|
22
21
|
"api",
|
|
@@ -31,6 +30,7 @@
|
|
|
31
30
|
"homepage": "https://chensuiyi.me",
|
|
32
31
|
"license": "Apache-2.0",
|
|
33
32
|
"files": [
|
|
33
|
+
"bin/",
|
|
34
34
|
"apis/",
|
|
35
35
|
"checks/",
|
|
36
36
|
"config/",
|
|
@@ -51,12 +51,5 @@
|
|
|
51
51
|
"system.js",
|
|
52
52
|
"package.json",
|
|
53
53
|
"README.md"
|
|
54
|
-
]
|
|
55
|
-
"simple-git-hooks": {
|
|
56
|
-
"pre-commit": "bunx --bun lint-staged"
|
|
57
|
-
},
|
|
58
|
-
"lint-staged": {
|
|
59
|
-
"*.{js,css,scss,less,ts,jsx,vue,html,json,md,yaml}": "bunx --bun prettier --write --cache --ignore-unknown"
|
|
60
|
-
},
|
|
61
|
-
"gitHead": "1dc5f118a723969456559e758e2ba889f4601224"
|
|
54
|
+
]
|
|
62
55
|
}
|
package/plugins/db.js
CHANGED
|
@@ -11,7 +11,7 @@ export default {
|
|
|
11
11
|
let sql = null;
|
|
12
12
|
|
|
13
13
|
try {
|
|
14
|
-
if (Env.
|
|
14
|
+
if (Env.DB_ENABLE === 1) {
|
|
15
15
|
// 创建 Bun SQL 客户端(内置连接池),并确保连接验证成功后再继续
|
|
16
16
|
sql = await createSqlClient();
|
|
17
17
|
|
|
@@ -20,7 +20,7 @@ export default {
|
|
|
20
20
|
|
|
21
21
|
return dbManager;
|
|
22
22
|
} else {
|
|
23
|
-
Logger.warn(
|
|
23
|
+
Logger.warn(`数据库未启用(DB_ENABLE≠1),跳过初始化`);
|
|
24
24
|
return {};
|
|
25
25
|
}
|
|
26
26
|
} catch (error) {
|