@mindbase/express-common 1.0.0 → 1.0.2
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/dist/index.d.mts +363 -0
- package/dist/index.mjs +2468 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +23 -11
- package/bin/mindbase.ts +0 -52
- package/commands/precache.ts +0 -54
- package/core/app.ts +0 -200
- package/core/module/CreateModule.ts +0 -38
- package/core/module/FindPackageRoot.ts +0 -58
- package/core/module/GetModulePath.ts +0 -58
- package/core/state.ts +0 -72
- package/feature/cron/CronManager.ts +0 -63
- package/feature/scanner/FileScanner.ts +0 -288
- package/index.ts +0 -10
- package/ipipfree.ipdb +0 -0
- package/middleware/Cors.ts +0 -17
- package/middleware/IpParser.ts +0 -81
- package/middleware/UaParser.ts +0 -50
- package/routes/Doc.route.ts +0 -118
- package/tests/Cors.test.ts +0 -34
- package/tests/Dayjs.test.ts +0 -24
- package/tests/FileScanner.test.ts +0 -85
- package/tests/GetModulePath.test.ts +0 -32
- package/tests/IpParser.test.ts +0 -72
- package/tests/Logger.test.ts +0 -68
- package/tests/UaParser.test.ts +0 -41
- package/tsconfig.json +0 -9
- package/types/DocTypes.ts +0 -111
- package/types/index.ts +0 -19
- package/utils/ComponentRegistry.ts +0 -34
- package/utils/DatabaseMigration.ts +0 -121
- package/utils/Dayjs.ts +0 -16
- package/utils/DocManager.ts +0 -274
- package/utils/HttpServer.ts +0 -41
- package/utils/InitDatabase.ts +0 -149
- package/utils/InitErrorHandler.ts +0 -71
- package/utils/InitExpress.ts +0 -35
- package/utils/Logger.ts +0 -206
- package/utils/MiddlewareRegistry.ts +0 -14
- package/utils/ProjectInitializer.ts +0 -283
- package/utils/RouteParser.ts +0 -408
- package/utils/RouteRegistry.ts +0 -66
- package/utils/SchemaMigrate.ts +0 -73
- package/utils/SchemaSync.ts +0 -47
- package/utils/TSTypeParser.ts +0 -455
- package/utils/Validate.ts +0 -25
- package/utils/ZodSchemaParser.ts +0 -420
- package/vitest.config.ts +0 -18
- package/zod/Doc.schema.ts +0 -9
package/core/app.ts
DELETED
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
import { Express } from "express";
|
|
2
|
-
import { createState } from "./state";
|
|
3
|
-
import { setBaseDir, scan, addScanPath } from "../feature/scanner/FileScanner";
|
|
4
|
-
import { MindBaseAppOptions } from "../types/Index";
|
|
5
|
-
import initExpress from "../utils/InitExpress";
|
|
6
|
-
import { setupDatabase, handleDatabaseMigration } from "../utils/InitDatabase";
|
|
7
|
-
import { checkAndMigrateDatabase } from "../utils/DatabaseMigration";
|
|
8
|
-
import { registerComponents } from "../utils/ComponentRegistry";
|
|
9
|
-
import { setupErrorHandlers } from "../utils/InitErrorHandler";
|
|
10
|
-
import { handleSchemaSync } from "../utils/SchemaSync";
|
|
11
|
-
import { handleSchemaMigrate } from "../utils/SchemaMigrate";
|
|
12
|
-
import { startServer } from "../utils/HttpServer";
|
|
13
|
-
import logger from "../utils/Logger";
|
|
14
|
-
import { initDocManager } from "../utils/DocManager";
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* MindBase 应用实例
|
|
18
|
-
*/
|
|
19
|
-
export interface MindBaseApp {
|
|
20
|
-
/** 注册插件模块 */
|
|
21
|
-
use(plugin: any): void;
|
|
22
|
-
/** 启动应用(初始化数据库、注册路由、启动 HTTP 服务) */
|
|
23
|
-
startup(): Promise<void>;
|
|
24
|
-
/** 获取 Express 实例 */
|
|
25
|
-
getApp(): Express;
|
|
26
|
-
/** 获取 Drizzle 数据库实例 */
|
|
27
|
-
getDB(): any;
|
|
28
|
-
/** 获取应用配置选项 */
|
|
29
|
-
getOptions(): MindBaseAppOptions;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* 创建 MindBase 应用实例
|
|
34
|
-
* @param options 应用配置选项
|
|
35
|
-
* @returns MindBase 应用实例
|
|
36
|
-
* @example
|
|
37
|
-
* const app = createApp({
|
|
38
|
-
* port: 3000,
|
|
39
|
-
* logLevel: "debug",
|
|
40
|
-
* });
|
|
41
|
-
* app.use(auth);
|
|
42
|
-
* await app.startup();
|
|
43
|
-
*/
|
|
44
|
-
export function createApp(options: MindBaseAppOptions = {}): MindBaseApp {
|
|
45
|
-
logger.startup("初始化", "应用初始化……");
|
|
46
|
-
const stateInstance = createState(options);
|
|
47
|
-
const plugins: any[] = [];
|
|
48
|
-
|
|
49
|
-
// 初始化日志级别
|
|
50
|
-
if (stateInstance.options.logLevel) {
|
|
51
|
-
logger.setLevel(stateInstance.options.logLevel);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const app: MindBaseApp = {
|
|
55
|
-
use: async (plugin) => {
|
|
56
|
-
if (typeof plugin.install === "function") {
|
|
57
|
-
plugins.push(plugin);
|
|
58
|
-
}
|
|
59
|
-
if (typeof plugin.__modulePath === "string") {
|
|
60
|
-
logger.startup("模块", `注册:${plugin.__modulePath}`);
|
|
61
|
-
addScanPath(plugin.__modulePath);
|
|
62
|
-
}
|
|
63
|
-
},
|
|
64
|
-
startup: async () => {
|
|
65
|
-
// migrate 模式:收集 schema + 执行 push(一体化迁移)
|
|
66
|
-
if (stateInstance.options.mode === "migrate") {
|
|
67
|
-
await handleSchemaMigrate();
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// sync 模式:仅收集 schema 路径(兼容旧版本)
|
|
72
|
-
if (stateInstance.options.mode === "sync") {
|
|
73
|
-
await handleSchemaSync();
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// 0. 初始化 Express 基础配置
|
|
78
|
-
initExpress(stateInstance.express, stateInstance.options);
|
|
79
|
-
|
|
80
|
-
// 1. 准备扫描环境
|
|
81
|
-
await prepareScanEnvironment();
|
|
82
|
-
|
|
83
|
-
// 2. 扫描组件
|
|
84
|
-
const scannedResults = await scanComponents();
|
|
85
|
-
|
|
86
|
-
// 3. 初始化数据存储
|
|
87
|
-
await initializeDataStorage(scannedResults);
|
|
88
|
-
|
|
89
|
-
// 4. 执行插件安装 (此时 DB 已就绪)
|
|
90
|
-
await installPlugins();
|
|
91
|
-
|
|
92
|
-
// 5. 注册组件
|
|
93
|
-
registerComponents(stateInstance, scannedResults);
|
|
94
|
-
|
|
95
|
-
// 6. 注册错误处理
|
|
96
|
-
setupErrorHandlers(stateInstance.express, stateInstance.options.logging);
|
|
97
|
-
|
|
98
|
-
// 7. 启动 HTTP 服务
|
|
99
|
-
await startHttpServer();
|
|
100
|
-
|
|
101
|
-
logger.startup("初始化", "✅ 应用启动完成");
|
|
102
|
-
},
|
|
103
|
-
|
|
104
|
-
getApp: () => stateInstance.express,
|
|
105
|
-
getDB: () => stateInstance.db,
|
|
106
|
-
getOptions: () => stateInstance.options,
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
// 准备扫描环境
|
|
110
|
-
async function prepareScanEnvironment() {
|
|
111
|
-
setBaseDir(process.cwd());
|
|
112
|
-
logger.startup("扫描", `基准目录: ${process.cwd()}`);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// 扫描组件
|
|
116
|
-
async function scanComponents() {
|
|
117
|
-
const scannedResults = await scan();
|
|
118
|
-
|
|
119
|
-
// 统计缓存命中情况
|
|
120
|
-
const routeFiles = scannedResults.filter(r => r.type === "route");
|
|
121
|
-
const cacheHits = routeFiles.filter(r => r.cacheHit).length;
|
|
122
|
-
const total = routeFiles.length;
|
|
123
|
-
|
|
124
|
-
if (cacheHits > 0) {
|
|
125
|
-
logger.startup("扫描", `发现 ${scannedResults.length} 个组件文件 (缓存命中: ${cacheHits}/${total})`);
|
|
126
|
-
} else {
|
|
127
|
-
logger.startup("扫描", `发现 ${scannedResults.length} 个组件文件`);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return scannedResults;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// 初始化数据存储
|
|
134
|
-
async function initializeDataStorage(scannedResults) {
|
|
135
|
-
// 初始化数据库与 Schema
|
|
136
|
-
setupDatabase(stateInstance, scannedResults);
|
|
137
|
-
stateInstance.express.set("db", stateInstance.db);
|
|
138
|
-
|
|
139
|
-
// 收集数据库信息
|
|
140
|
-
if (stateInstance.db) {
|
|
141
|
-
const dbPath = stateInstance.options.database?.path || "./data/app.db";
|
|
142
|
-
logger.startup("数据库", `已连接: SQLite (${dbPath})`);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// 数据库迁移已改为独立命令(npm run db:migrate)
|
|
146
|
-
// 不再在启动时自动执行,以提升启动速度
|
|
147
|
-
// await handleDatabaseMigrationStep();
|
|
148
|
-
|
|
149
|
-
// 初始化文档管理器
|
|
150
|
-
const docDbPath = stateInstance.options.database?.path ? stateInstance.options.database.path.replace(/app\.db$/, "doc.db") : "./data/doc.db";
|
|
151
|
-
initDocManager({ path: docDbPath });
|
|
152
|
-
logger.startup("数据库", `文档库已初始化: ${docDbPath}`);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// 处理数据库迁移
|
|
156
|
-
async function handleDatabaseMigrationStep() {
|
|
157
|
-
if (stateInstance.options.autoMigrate !== false) {
|
|
158
|
-
try {
|
|
159
|
-
await checkAndMigrateDatabase(stateInstance);
|
|
160
|
-
// 已在 DatabaseMigration 中打印日志,无需额外处理
|
|
161
|
-
} catch (error) {
|
|
162
|
-
logger.error("❌ 数据库结构检查失败:", error);
|
|
163
|
-
}
|
|
164
|
-
} else {
|
|
165
|
-
// 只提醒,不执行迁移
|
|
166
|
-
try {
|
|
167
|
-
await handleDatabaseMigration(stateInstance.db, stateInstance.schemas);
|
|
168
|
-
} catch (error) {
|
|
169
|
-
logger.error("❌ 数据库结构检查失败:", error);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// 执行插件安装
|
|
175
|
-
async function installPlugins() {
|
|
176
|
-
for (const plugin of plugins) {
|
|
177
|
-
await plugin.install(app);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// 启动 HTTP 服务
|
|
182
|
-
async function startHttpServer() {
|
|
183
|
-
const listenPort = stateInstance.options.port || 3000;
|
|
184
|
-
await startServer(stateInstance.express, listenPort);
|
|
185
|
-
|
|
186
|
-
// 打印服务器启动信息
|
|
187
|
-
const serverUrl = `http://localhost:${listenPort}`;
|
|
188
|
-
logger.startup("服务", `监听端口: ${listenPort}`);
|
|
189
|
-
logger.startup("服务", `访问地址: ${serverUrl}`);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
return app;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// 扩展 Express Application 类型,添加 getDB 方法
|
|
196
|
-
declare module "express" {
|
|
197
|
-
export interface Application {
|
|
198
|
-
getDB(): any;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { findPackageRoot } from "./FindPackageRoot";
|
|
2
|
-
import { getModulePath } from "./GetModulePath";
|
|
3
|
-
import { LightUpApp } from "../../types";
|
|
4
|
-
import logger from "../../utils/Logger";
|
|
5
|
-
|
|
6
|
-
export interface LightUpModule {
|
|
7
|
-
install(app: LightUpApp): Promise<void>;
|
|
8
|
-
__modulePath: string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* 创建一个 LightUp 模块
|
|
13
|
-
* @param install 模块安装函数
|
|
14
|
-
* @param callerPath 调用者的文件路径(通常是 __filename),如果不提供则尝试通过调用栈获取
|
|
15
|
-
* @returns LightUp 模块实例
|
|
16
|
-
* @throws 如果模块创建失败
|
|
17
|
-
*/
|
|
18
|
-
export function createModule(install, callerPath?: string): LightUpModule {
|
|
19
|
-
if (typeof install !== "function") {
|
|
20
|
-
throw new Error("模块安装函数必须是一个函数");
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
try {
|
|
24
|
-
// 优先使用传入的 callerPath,否则通过调用栈获取
|
|
25
|
-
const modulePath = callerPath || getModulePath();
|
|
26
|
-
const packageRoot = findPackageRoot(modulePath);
|
|
27
|
-
|
|
28
|
-
logger.debug(`创建模块:路径=${modulePath},包根目录=${packageRoot}`);
|
|
29
|
-
|
|
30
|
-
return {
|
|
31
|
-
install,
|
|
32
|
-
__modulePath: packageRoot,
|
|
33
|
-
};
|
|
34
|
-
} catch (error) {
|
|
35
|
-
logger.error("模块创建失败:", error);
|
|
36
|
-
throw new Error(`模块创建失败:${error instanceof Error ? error.message : String(error)}`);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import path from "path";
|
|
2
|
-
import fs from "fs";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* 查找包含 package.json 的根目录
|
|
6
|
-
* @param startPath 开始查找的路径
|
|
7
|
-
* @returns 包含 package.json 的目录路径
|
|
8
|
-
* @throws 如果输入路径无效
|
|
9
|
-
*/
|
|
10
|
-
export function findPackageRoot(startPath: string): string {
|
|
11
|
-
// 验证输入路径
|
|
12
|
-
if (!startPath || typeof startPath !== "string") {
|
|
13
|
-
throw new Error("无效的起始路径:路径必须是非空字符串");
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// 确保路径是绝对路径
|
|
17
|
-
let currentPath: string;
|
|
18
|
-
try {
|
|
19
|
-
currentPath = path.isAbsolute(startPath) ? startPath : path.resolve(startPath);
|
|
20
|
-
} catch (e) {
|
|
21
|
-
throw new Error(`无法解析路径:${startPath}`);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// 验证路径是否存在
|
|
25
|
-
try {
|
|
26
|
-
if (!fs.existsSync(currentPath)) {
|
|
27
|
-
throw new Error(`路径不存在:${currentPath}`);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// 如果是文件,从其父目录开始查找
|
|
31
|
-
const stat = fs.statSync(currentPath);
|
|
32
|
-
if (stat.isFile()) {
|
|
33
|
-
currentPath = path.dirname(currentPath);
|
|
34
|
-
}
|
|
35
|
-
} catch (e) {
|
|
36
|
-
throw new Error(`路径验证失败:${e instanceof Error ? e.message : String(e)}`);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// 向上查找 package.json
|
|
40
|
-
while (currentPath !== path.parse(currentPath).root) {
|
|
41
|
-
try {
|
|
42
|
-
const pkgJsonPath = path.join(currentPath, "package.json");
|
|
43
|
-
if (fs.existsSync(pkgJsonPath)) {
|
|
44
|
-
// 验证找到的 package.json 是否是文件
|
|
45
|
-
const pkgStat = fs.statSync(pkgJsonPath);
|
|
46
|
-
if (pkgStat.isFile()) {
|
|
47
|
-
return currentPath;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
} catch (e) {
|
|
51
|
-
// 忽略单个路径的访问错误,继续向上查找
|
|
52
|
-
}
|
|
53
|
-
currentPath = path.dirname(currentPath);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// 如果没有找到 package.json,返回起始路径的父目录
|
|
57
|
-
return path.dirname(startPath);
|
|
58
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import * as path from "path";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* 获取当前模块的路径
|
|
5
|
-
* @returns 当前模块的绝对路径
|
|
6
|
-
* @throws 如果无法确定模块路径
|
|
7
|
-
*/
|
|
8
|
-
export function getModulePath(): string {
|
|
9
|
-
// 从调用栈中提取调用者的路径
|
|
10
|
-
try {
|
|
11
|
-
const error = new Error();
|
|
12
|
-
if (error.stack) {
|
|
13
|
-
console.log("DEBUG STACK:", error.stack);
|
|
14
|
-
const stackLines = error.stack.split("\n");
|
|
15
|
-
|
|
16
|
-
// 跳过内部调用,找到真正的调用者
|
|
17
|
-
// 需要跳过:getModulePath, createModule, ts-node, node:internal
|
|
18
|
-
for (const line of stackLines) {
|
|
19
|
-
// 跳过内部函数和 Node.js/ts-node 的调用
|
|
20
|
-
if (!line.includes("at") ||
|
|
21
|
-
line.includes("getModulePath") ||
|
|
22
|
-
line.includes("createModule") ||
|
|
23
|
-
line.includes("CreateModule.ts") ||
|
|
24
|
-
line.includes("ts-node") ||
|
|
25
|
-
line.includes("node:internal")) {
|
|
26
|
-
continue;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// 提取文件路径
|
|
30
|
-
// 格式可能是:at xxx (/path/to/file.ts:1:2) 或 at /path/to/file.ts:1:2
|
|
31
|
-
const match = line.match(/\(([^:]+\.ts)/) || line.match(/at\s+([^:]+\.ts)/);
|
|
32
|
-
if (match && match[1]) {
|
|
33
|
-
const filePath = match[1];
|
|
34
|
-
console.log("提取到的路径:", filePath);
|
|
35
|
-
return path.resolve(filePath);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
} catch (e) {
|
|
40
|
-
// 忽略提取 stack 时的错误
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
throw new Error("无法确定模块路径:当前环境不支持 __filename 且无法从调用栈中提取路径");
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* 获取当前模块所在的目录
|
|
48
|
-
* @returns 当前模块的目录路径
|
|
49
|
-
* @throws 如果无法确定模块路径
|
|
50
|
-
*/
|
|
51
|
-
export function getModuleDir(): string {
|
|
52
|
-
try {
|
|
53
|
-
const modulePath = getModulePath();
|
|
54
|
-
return path.dirname(modulePath);
|
|
55
|
-
} catch (error) {
|
|
56
|
-
throw new Error(`无法获取模块目录:${error instanceof Error ? error.message : String(error)}`);
|
|
57
|
-
}
|
|
58
|
-
}
|
package/core/state.ts
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import express, { Express } from "express";
|
|
2
|
-
import { LogLevel } from "../types";
|
|
3
|
-
|
|
4
|
-
export interface MindBaseAppOptions {
|
|
5
|
-
/**
|
|
6
|
-
* 启动模式:
|
|
7
|
-
* - normal: 正常启动服务
|
|
8
|
-
* - sync: 同步数据库 Schema(仅收集)
|
|
9
|
-
* - migrate: 执行数据库迁移
|
|
10
|
-
* @default "normal"
|
|
11
|
-
*/
|
|
12
|
-
mode?: "normal" | "sync" | "migrate";
|
|
13
|
-
/** 服务监听端口 @default 3000 */
|
|
14
|
-
port?: number;
|
|
15
|
-
/** 是否启用请求日志 @default true */
|
|
16
|
-
logging?: boolean;
|
|
17
|
-
/** 静态文件目录路径 */
|
|
18
|
-
staticPath?: string;
|
|
19
|
-
/** 是否解析 User-Agent 信息 @default true */
|
|
20
|
-
userAgent?: boolean;
|
|
21
|
-
/** 是否解析 IP 地理位置信息 @default true */
|
|
22
|
-
ip?: boolean;
|
|
23
|
-
/** 是否启用 CORS 跨域 @default true */
|
|
24
|
-
cors?: boolean;
|
|
25
|
-
/** API 路由前缀,如 "/api" */
|
|
26
|
-
apiPrefix?: string;
|
|
27
|
-
/**
|
|
28
|
-
* 日志级别(优先级从低到高):
|
|
29
|
-
* - debug: 调试信息(显示所有)
|
|
30
|
-
* - info: 普通信息(隐藏 debug)
|
|
31
|
-
* - warn: 警告信息(隐藏 debug、info)
|
|
32
|
-
* - error: 错误信息(隐藏 debug、info、warn)
|
|
33
|
-
* - silent: 静默模式(隐藏所有)
|
|
34
|
-
* @default "info"
|
|
35
|
-
*/
|
|
36
|
-
logLevel?: LogLevel;
|
|
37
|
-
/** 是否自动迁移数据库表结构 @default false */
|
|
38
|
-
autoMigrate?: boolean;
|
|
39
|
-
/** 数据库配置 */
|
|
40
|
-
database?: {
|
|
41
|
-
/** SQLite 数据库文件路径 @default "./data/app.db" */
|
|
42
|
-
path?: string;
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
export interface AppState {
|
|
46
|
-
options: MindBaseAppOptions;
|
|
47
|
-
express: Express;
|
|
48
|
-
db?: any; // Drizzle 数据库实例
|
|
49
|
-
schemas?: Record<string, any>; // 合并后的所有 schema
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function createState(options: MindBaseAppOptions = {}): AppState {
|
|
53
|
-
return {
|
|
54
|
-
options: {
|
|
55
|
-
mode: options.mode || (process.env.MIND_BASE_MODE as any) || "normal",
|
|
56
|
-
port: options.port || 3000,
|
|
57
|
-
logging: options.logging !== false,
|
|
58
|
-
staticPath: options.staticPath,
|
|
59
|
-
userAgent: options.userAgent !== false,
|
|
60
|
-
ip: options.ip !== false,
|
|
61
|
-
cors: options.cors !== false,
|
|
62
|
-
apiPrefix: options.apiPrefix,
|
|
63
|
-
logLevel: options.logLevel || "info",
|
|
64
|
-
autoMigrate: options.autoMigrate ?? false,
|
|
65
|
-
database: {
|
|
66
|
-
path: options.database?.path || "./data/app.db",
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
express: express(),
|
|
70
|
-
schemas: {},
|
|
71
|
-
};
|
|
72
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { CronJob } from "cron";
|
|
2
|
-
import { randomUUID } from "crypto";
|
|
3
|
-
|
|
4
|
-
interface CronConfig {
|
|
5
|
-
timezone?: string;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
interface CronJobMap {
|
|
9
|
-
[id: string]: CronJob;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
let jobs: CronJobMap = {};
|
|
13
|
-
let config: CronConfig = {
|
|
14
|
-
timezone: "Asia/Shanghai",
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export function setConfig(newConfig: CronConfig): void {
|
|
18
|
-
config = {
|
|
19
|
-
...config,
|
|
20
|
-
...newConfig,
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function addCron(pattern: string, handler: () => void | Promise<void>, customId?: string): string {
|
|
25
|
-
const id = customId || generateId();
|
|
26
|
-
if (jobs[id]) {
|
|
27
|
-
jobs[id].stop();
|
|
28
|
-
}
|
|
29
|
-
const job = new CronJob(pattern, handler, null, true, config.timezone);
|
|
30
|
-
jobs[id] = job;
|
|
31
|
-
return id;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function stopCron(id: string): boolean {
|
|
35
|
-
const job = jobs[id];
|
|
36
|
-
if (job) {
|
|
37
|
-
job.stop();
|
|
38
|
-
delete jobs[id];
|
|
39
|
-
return true;
|
|
40
|
-
}
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function stopAllCron(): void {
|
|
45
|
-
Object.values(jobs).forEach((job) => {
|
|
46
|
-
job.stop();
|
|
47
|
-
});
|
|
48
|
-
jobs = {};
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function generateId(): string {
|
|
52
|
-
return randomUUID();
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const CronManager = {
|
|
56
|
-
setConfig,
|
|
57
|
-
addCron,
|
|
58
|
-
stopCron,
|
|
59
|
-
stopAllCron,
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
export default CronManager;
|
|
63
|
-
export type { CronConfig };
|