chanjs 2.3.0 → 2.5.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/App.js CHANGED
@@ -2,18 +2,18 @@ import express from "express";
2
2
  import fs from "fs";
3
3
  import path from "path";
4
4
 
5
- import AppContext from "./base/Context.js";
5
+ // 引入基础组件
6
6
  import Controller from "./base/Controller.js";
7
- import DatabaseManager from "./base/Database.js";
8
-
9
7
  import Service from "./base/Service.js";
8
+ import DatabaseManager from "./base/Database.js";
10
9
 
10
+ // 引入配置和工具
11
11
  import { Paths } from "./config/index.js";
12
12
  import { getChildrenId, filterBody, filterImgFromStr, CODE as commonCode, sendMail, genRegEmailHtml, genResetPasswordEmail, pages, getHtmlFilesSync } from "./common/index.js";
13
- import { db, loadConfig, loadController, loaderSort, prefixDbConfig, formatDateFields, request, delImg, getIp, setToken, getToken, verifyToken, generateToken, getFileTree, readFileContent, saveFileContent, isPathSafe, arrToObj, htmlDecode } from "./helper/index.js";
13
+ import { loadConfig, loadController, loaderSort, formatDateFields, request, delImg, getIp, setToken, getToken, verifyToken, generateToken, getFileTree, readFileContent, saveFileContent, isPathSafe, arrToObj, htmlDecode } from "./helper/index.js";
14
14
  import { Cors, setBody, setCookie, setFavicon, setHeader, setStatic, setTemplate, waf } from "./middleware/index.js";
15
- import { errorResponse, notFoundResponse, parseDatabaseError } from "./utils/error-handler.js";
16
- import { error as responseError, fail, success } from "./utils/response.js";
15
+ import { errorResponse, notFoundResponse, parseDatabaseError, error as responseError, fail, success, checkKeywords } from "./utils/index.js";
16
+ import { importFile, importjs } from "./global/import.js";
17
17
 
18
18
  import "./global/index.js";
19
19
 
@@ -22,14 +22,14 @@ import "./global/index.js";
22
22
  * @class Chan
23
23
  * @description 管理应用程序的路由、中间件、数据库连接和服务
24
24
  * @example
25
- * const app = new Chan({ port: 3000, env: "production" });
25
+ * const app = new Chan();
26
26
  * await app.start();
27
27
  */
28
28
  class Chan {
29
+
30
+ // 静态属性:提供全局访问的辅助函数和工具
29
31
  static helper = {
30
32
  loadController,
31
- db,
32
- prefixDbConfig,
33
33
  loaderSort,
34
34
  loadConfig,
35
35
  formatDateFields,
@@ -47,6 +47,8 @@ class Chan {
47
47
  arrToObj,
48
48
  htmlDecode,
49
49
  };
50
+
51
+ // 静态属性:提供全局访问的常用业务函数和工具
50
52
  static common = {
51
53
  success,
52
54
  fail,
@@ -61,31 +63,35 @@ class Chan {
61
63
  filterBody,
62
64
  filterImgFromStr,
63
65
  };
66
+
67
+ // 静态属性:提供全局访问的配置
64
68
  static config = {};
69
+ // 静态属性:提供全局访问的数据库
70
+ static db = {};
71
+ // 静态属性:提供全局访问的服务类
65
72
  static Service = Service;
73
+ // 静态属性:提供全局访问的控制器类
66
74
  static Controller = Controller;
75
+ // 静态属性:提供全局访问的路径配置
67
76
  static paths = Paths;
77
+ // 静态属性:提供全局访问的导入函数
78
+ static importFile = importFile;
79
+ static importjs = importjs;
80
+ // 静态属性:提供全局访问的工具函数
81
+ static utils = {
82
+ checkKeywords,
83
+ };
68
84
 
69
85
  /**
70
86
  * 构造函数
71
87
  * @constructor
72
- * @param {Object} options - 应用配置选项
73
- * @param {number} [options.port=3000] - 服务器端口
74
- * @param {string} [options.env] - 运行环境
75
88
  * @description 初始化 Express 应用和核心组件
76
89
  */
77
- constructor(options = {}) {
90
+ constructor() {
78
91
  this.app = express();
79
- this.context = new AppContext();
92
+ // 数据库连接管理
80
93
  this.dbManager = new DatabaseManager();
81
-
82
- this.options = {
83
- port: options.port || 3000,
84
- env: options.env || process.env.NODE_ENV || "development",
85
- ...options,
86
- };
87
-
88
- this._isStarted = false;
94
+ // 应用路由
89
95
  this.router = express.Router();
90
96
  }
91
97
 
@@ -97,63 +103,52 @@ class Chan {
97
103
  * @returns {Promise<void>}
98
104
  */
99
105
  async start() {
100
- if (this._isStarted) {
101
- console.warn("App already started");
102
- return;
103
- }
104
-
105
- global.appContext = this.context;
106
- global.Chan = Chan;
107
-
108
- await this.initConfig();
109
- await this.initDB();
110
- await this.initExtend();
111
- await this.initMiddleware();
112
-
113
- this._applyConfig();
114
-
106
+ //加载配置
107
+ await this.config();
108
+ //加载数据库
109
+ await this.loadDB();
110
+ //加载扩展方法
111
+ await this.loadExtend();
112
+ //加载中间件
113
+ await this.loadAppMiddleware();
114
+ //设置app
115
+ this.setApp();
116
+ //加载路由
115
117
  await this.loadRouter();
116
118
  await this.loadCommonRouter();
117
-
118
- this._applyRoutes();
119
- this._applyErrorHandling();
120
-
121
- await this._listen();
122
-
123
- this._isStarted = true;
119
+ this.useRouter();
120
+ //404 500 处理
121
+ this.setErrorHandler();
124
122
  }
125
123
 
126
124
  /**
127
- * 初始化配置
125
+ * 加载配置
128
126
  * @async
129
127
  * @returns {Promise<void>}
130
- * @description 加载应用配置并设置到上下文
128
+ * @description 加载应用配置并设置到全局变量
131
129
  */
132
- async initConfig() {
130
+ async config() {
133
131
  let config = await loadConfig();
134
132
  Chan.config = config;
135
- this.context.set("config", config);
136
133
  }
137
134
 
138
135
  /**
139
- * 初始化数据库
136
+ * 加载数据库
140
137
  * @async
141
138
  * @returns {Promise<void>}
142
139
  * @description 根据配置初始化所有数据库连接
143
140
  */
144
- async initDB() {
141
+ async loadDB() {
145
142
  const dbList = Chan.config?.db || [];
146
- const connections = this.dbManager.getConnections();
147
143
 
148
144
  for (const [index, item] of dbList.entries()) {
149
145
  const key = item.key || String(index);
150
146
  try {
151
- const dbConfig = prefixDbConfig(key) || item;
147
+ const dbConfig = item;
152
148
  if (!dbConfig) throw new Error("未找到配置");
153
149
 
154
150
  const connection = this.dbManager.add(key, dbConfig, { isDefault: index === 0 });
155
- this.context.set(`db:${key}`, connection);
156
-
151
+
157
152
  if (index === 0) {
158
153
  Chan.db = connection;
159
154
  }
@@ -163,17 +158,17 @@ class Chan {
163
158
  }
164
159
 
165
160
  console.log(
166
- `[DB] 初始化完成,已加载 ${dbList.length} 个数据库,成功 ${Object.keys(connections).length} 个`,
161
+ `[DB] 初始化完成,已加载 ${dbList.length} 个数据库`,
167
162
  );
168
163
  }
169
164
 
170
165
  /**
171
- * 初始化扩展模块
166
+ * 加载扩展模块
172
167
  * @async
173
168
  * @returns {Promise<void>}
174
169
  * @description 加载 common、helper、extend 目录下的扩展模块
175
170
  */
176
- async initExtend() {
171
+ async loadExtend() {
177
172
  const extensions = [
178
173
  { _path: Paths.commonPath, key: "common" },
179
174
  { _path: Paths.helperPath, key: "helper" },
@@ -198,7 +193,7 @@ class Chan {
198
193
  const files = fs.readdirSync(_path).filter((file) => file.endsWith(".js"));
199
194
  for (const file of files) {
200
195
  const filePath = path.join(_path, file);
201
- let helperModule = await importFile(filePath);
196
+ let helperModule = await Chan.importFile(filePath);
202
197
  Object.assign(Chan[key], helperModule);
203
198
  }
204
199
  }
@@ -210,10 +205,21 @@ class Chan {
210
205
  * @returns {Promise<void>}
211
206
  * @description 配置并注册所有应用中间件
212
207
  */
213
- async initMiddleware() {
208
+ async loadAppMiddleware() {
214
209
  const config = Chan.config;
215
- const { views = [], env = "development", APP_NAME = "ChanCMS", APP_VERSION = "1.0.0", cookieKey, BODY_LIMIT = "10mb", statics = [], cors = {}, PROXY = "false", waf: wafConfig = { enabled: false } } = config;
216
-
210
+ const {
211
+ views = [],
212
+ env = "development",
213
+ APP_NAME = "ChanCMS",
214
+ APP_VERSION = "1.0.0",
215
+ cookieKey,
216
+ BODY_LIMIT = "10mb",
217
+ statics = [],
218
+ cors = {},
219
+ PROXY = "false",
220
+ waf: wafConfig = { enabled: false }
221
+ } = config;
222
+
217
223
  await waf(this.app, wafConfig);
218
224
  setFavicon(this.app);
219
225
  setStatic(this.app, statics);
@@ -229,9 +235,8 @@ class Chan {
229
235
  * @private
230
236
  * @description 设置 Express 应用配置
231
237
  */
232
- _applyConfig() {
238
+ setApp() {
233
239
  this.app.set("trust proxy", Chan.config.PROXY === "true");
234
- this.app.set("env", this.options.env);
235
240
  this.app.disable("x-powered-by");
236
241
  }
237
242
 
@@ -240,20 +245,22 @@ class Chan {
240
245
  * @private
241
246
  * @description 将所有路由应用到 Express 应用
242
247
  */
243
- _applyRoutes() {
248
+ useRouter() {
244
249
  this.app.use(this.router);
245
250
  }
246
251
 
247
252
  /**
248
- * 应用错误处理
253
+ * 应用错误处理404 500
249
254
  * @private
250
255
  * @description 配置全局错误处理中间件
251
256
  */
252
- _applyErrorHandling() {
257
+ setErrorHandler() {
258
+ //404
253
259
  this.app.use((req, res) => {
254
260
  res.status(404).json(notFoundResponse(req));
255
261
  });
256
262
 
263
+ // 500
257
264
  this.app.use((err, req, res, next) => {
258
265
  if (res.headersSent) return next(err);
259
266
 
@@ -326,23 +333,7 @@ class Chan {
326
333
  return { message: stackLines[0] || '未知错误', file: errorLine };
327
334
  }
328
335
 
329
- /**
330
- * 启动服务器监听
331
- * @async
332
- * @private
333
- * @returns {Promise<void>}
334
- * @description 启动 HTTP 服务器监听指定端口
335
- */
336
- async _listen() {
337
- return new Promise((resolve, reject) => {
338
- const server = this.app.listen(this.options.port, () => {
339
- console.log(`Server running on port ${this.options.port}`);
340
- resolve(server);
341
- });
342
-
343
- server.on("error", reject);
344
- });
345
- }
336
+
346
337
 
347
338
  /**
348
339
  * 加载模块路由
@@ -355,7 +346,7 @@ class Chan {
355
346
  if (fs.existsSync(configPath)) {
356
347
  const dirs = loaderSort(Chan.config.modules);
357
348
  for (const item of dirs) {
358
- let router = await importFile(`app/modules/${item}/router.js`);
349
+ let router = await Chan.importFile(`app/modules/${item}/router.js`);
359
350
  router(this.app, this.router, Chan.config);
360
351
  }
361
352
  }
@@ -368,7 +359,7 @@ class Chan {
368
359
  * @description 加载 app/router.js 中的公共路由
369
360
  */
370
361
  async loadCommonRouter() {
371
- let router = await importFile("app/router.js");
362
+ let router = await Chan.importFile("app/router.js");
372
363
  if (router) {
373
364
  router(this.app, this.router, Chan.config);
374
365
  }
@@ -379,9 +370,14 @@ class Chan {
379
370
  * @param {Function} [cb] - 回调函数
380
371
  * @description 在启动前执行回调,传递端口号
381
372
  */
382
- ready(cb) {
383
- cb?.(this.options.port);
373
+ run(cb) {
374
+ this.app.listen(Chan.config.PORT, () => {
375
+ console.log(`Server running on port ${Chan.config.PORT}`);
376
+ cb?.(Chan.config.PORT);
377
+ });
384
378
  }
385
379
  }
386
380
 
381
+ global.Chan = Chan;
382
+
387
383
  export default Chan;
@@ -1,92 +1,21 @@
1
- import { success, fail, error as responseError } from "../utils/response.js";
1
+ import { success, fail } from "../utils/response.js";
2
2
 
3
3
  /**
4
4
  * 控制器基类
5
5
  * 提供统一的响应格式和常用方法
6
6
  */
7
7
  export default class Controller {
8
- /**
9
- * 构造函数
10
- * @param {Object} context - 应用上下文实例
11
- */
12
- constructor(context = null) {
13
- if (context) {
14
- this.context = context;
15
- } else if (global.appContext) {
16
- this.context = global.appContext;
17
- } else {
18
- this.context = { get: () => null, set: () => null };
19
- }
20
- }
21
-
22
- /**
23
- * 标准化返回结果
24
- * @private
25
- * @param {*} result - 原始结果
26
- * @param {string} defaultMsg - 默认消息
27
- * @returns {Object} 标准化的结果对象
28
- */
29
- _normalizeResult(result, defaultMsg = "操作成功") {
30
- if (result === null || result === undefined) {
31
- return { success: false, code: 5001, msg: "Service 返回空值", data: {} };
32
- }
33
-
34
- if (typeof result === 'object' && 'success' in result) {
35
- return result;
36
- }
37
-
38
- if (typeof result === 'object' || Array.isArray(result)) {
39
- return { success: true, code: 200, msg: defaultMsg, data: result };
40
- }
41
-
42
- return { success: true, code: 200, msg: defaultMsg, data: result };
43
- }
8
+ constructor() {}
44
9
 
45
10
  /**
46
11
  * 返回成功响应
47
- * @param {*} options - 响应选项或数据
12
+ * @param {Object} options - 响应选项
48
13
  * @param {*} options.data - 响应数据
49
14
  * @param {string} options.msg - 响应消息,默认"操作成功"
50
15
  * @returns {Object} 标准成功响应
51
16
  */
52
- success(options, msg = "操作成功") {
53
- let data, message = msg, extra = {};
54
-
55
- if (options === null || options === undefined) {
56
- data = undefined;
57
- } else if (typeof options === 'object' && options !== null && !Array.isArray(options)) {
58
- if ('data' in options) {
59
- data = options.data;
60
- message = options.msg || msg;
61
- extra = { ...options };
62
- delete extra.data;
63
- delete extra.msg;
64
- } else if ('success' in options && 'code' in options) {
65
- return options;
66
- } else {
67
- data = options;
68
- }
69
- } else {
70
- data = options;
71
- }
72
-
73
- if (data instanceof Error) {
74
- return this.error({ err: data });
75
- }
76
-
77
- const normalized = this._normalizeResult(data, message);
78
-
79
- if (!normalized.success) {
80
- return this.fail({ msg: normalized.msg, data: normalized.data, code: normalized.code });
81
- }
82
-
83
- return {
84
- success: true,
85
- code: 200,
86
- msg: normalized.msg,
87
- data: normalized.data,
88
- ...extra
89
- };
17
+ success({ data, msg = "操作成功" } = {}) {
18
+ return success({ data, msg });
90
19
  }
91
20
 
92
21
  /**
@@ -100,38 +29,4 @@ export default class Controller {
100
29
  fail({ msg = "操作失败", data = {}, code = 201 } = {}) {
101
30
  return fail({ msg, data, code });
102
31
  }
103
-
104
- /**
105
- * 返回错误响应
106
- * @param {Object} options - 响应选项
107
- * @param {Error} options.err - 错误对象
108
- * @param {*} options.data - 响应数据
109
- * @param {number} options.code - 错误码,默认500
110
- * @returns {Object} 标准错误响应
111
- */
112
- error({ err, data = {}, code = 500 } = {}) {
113
- return responseError({ err, data, code });
114
- }
115
-
116
- /**
117
- * 返回分页响应
118
- * @param {Array} list - 数据列表
119
- * @param {number} total - 总记录数
120
- * @param {number} current - 当前页码
121
- * @param {number} pageSize - 每页大小
122
- * @returns {Object} 标准分页响应
123
- */
124
- paginate(list, total, current, pageSize) {
125
- return success({
126
- data: {
127
- list,
128
- pagination: {
129
- total,
130
- current,
131
- pageSize,
132
- totalPages: Math.ceil(total / pageSize),
133
- },
134
- },
135
- });
136
- }
137
32
  }