markpdfdown 0.1.8-beta.6 → 0.2.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/dist/main/index.js +398 -14
- package/dist/preload/index.js +20 -1
- package/dist/renderer/assets/{index-yTU2skrN.css → index-B_JfRqwM.css} +54 -0
- package/dist/renderer/assets/{index-iEK8qT5k.js → index-wHB9i2kW.js} +623 -320
- package/dist/renderer/index.html +2 -2
- package/package.json +10 -3
- package/dist/app/app.js +0 -49
- package/dist/app/controllers/completionController.js +0 -19
- package/dist/app/controllers/modelController.js +0 -53
- package/dist/app/controllers/providerController.js +0 -120
- package/dist/app/dal/modelDal.js +0 -44
- package/dist/app/dal/providerDal.js +0 -78
- package/dist/app/db/index.js +0 -56
- package/dist/app/db/migration.js +0 -157
- package/dist/app/logic/llm/AnthropicClient.js +0 -219
- package/dist/app/logic/llm/AzureOpenAIClient.js +0 -239
- package/dist/app/logic/llm/GeminiClient.js +0 -212
- package/dist/app/logic/llm/LLMClient.js +0 -80
- package/dist/app/logic/llm/OpenAIClient.js +0 -235
- package/dist/app/logic/llm/example-advanced.js +0 -232
- package/dist/app/logic/llm/index.js +0 -14
- package/dist/app/logic/model.js +0 -27
- package/dist/app/middleware/logger.js +0 -23
- package/dist/app/routes/routes.js +0 -16
- package/dist/app/types/Provider.js +0 -1
- package/dist/server/controllers/FileController.js +0 -64
- package/dist/server/controllers/TaskController.js +0 -57
- package/dist/server/controllers/completionController.js +0 -64
- package/dist/server/controllers/modelController.js +0 -74
- package/dist/server/controllers/providerController.js +0 -120
- package/dist/server/dal/TaskDal.js +0 -67
- package/dist/server/dal/modelDal.js +0 -44
- package/dist/server/dal/providerDal.js +0 -83
- package/dist/server/db/index.js +0 -57
- package/dist/server/db/migration.js +0 -157
- package/dist/server/index.js +0 -49
- package/dist/server/logic/File.js +0 -34
- package/dist/server/logic/Task.js +0 -21
- package/dist/server/logic/llm/AnthropicClient.js +0 -220
- package/dist/server/logic/llm/AzureOpenAIClient.js +0 -239
- package/dist/server/logic/llm/GeminiClient.js +0 -213
- package/dist/server/logic/llm/LLMClient.js +0 -83
- package/dist/server/logic/llm/OllamaClient.js +0 -220
- package/dist/server/logic/llm/OpenAIClient.js +0 -235
- package/dist/server/logic/llm/example-advanced.js +0 -231
- package/dist/server/logic/llm/index.js +0 -15
- package/dist/server/logic/model.js +0 -59
- package/dist/server/middleware/logger.js +0 -23
- package/dist/server/routes/routes.js +0 -30
- package/dist/server/types/Provider.js +0 -1
- package/dist/server/types/Task.js +0 -1
package/dist/renderer/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>MarkPDFdown</title>
|
|
8
|
-
<script type="module" crossorigin src="./assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
8
|
+
<script type="module" crossorigin src="./assets/index-wHB9i2kW.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="./assets/index-B_JfRqwM.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "markpdfdown",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "A high-quality PDF to Markdown tool based on large language model visual recognition.",
|
|
5
5
|
"author": "MarkPDFdown",
|
|
6
6
|
"main": "dist/main/index.js",
|
|
@@ -80,7 +80,8 @@
|
|
|
80
80
|
"mac": {
|
|
81
81
|
"category": "public.app-category.productivity",
|
|
82
82
|
"target": [
|
|
83
|
-
"dmg"
|
|
83
|
+
"dmg",
|
|
84
|
+
"zip"
|
|
84
85
|
],
|
|
85
86
|
"artifactName": "${productName}-${version}-${arch}.${ext}",
|
|
86
87
|
"icon": "public/icons/mac/icon.icns",
|
|
@@ -112,6 +113,11 @@
|
|
|
112
113
|
"electronDownload": {
|
|
113
114
|
"mirror": "https://github.com/electron/electron/releases/download/"
|
|
114
115
|
},
|
|
116
|
+
"publish": {
|
|
117
|
+
"provider": "github",
|
|
118
|
+
"owner": "MarkPDFdown",
|
|
119
|
+
"repo": "markpdfdown-desktop"
|
|
120
|
+
},
|
|
115
121
|
"asar": true
|
|
116
122
|
},
|
|
117
123
|
"lint-staged": {
|
|
@@ -130,13 +136,14 @@
|
|
|
130
136
|
"dependencies": {
|
|
131
137
|
"@ant-design/icons": "^5.6.1",
|
|
132
138
|
"@prisma/client": "^6.5.0",
|
|
133
|
-
"prisma": "^6.5.0",
|
|
134
139
|
"@types/sharp": "^0.31.1",
|
|
135
140
|
"antd": "^5.24.4",
|
|
136
141
|
"electron-is-dev": "^3.0.1",
|
|
142
|
+
"electron-updater": "^6.7.3",
|
|
137
143
|
"katex": "^0.16.21",
|
|
138
144
|
"pdf-lib": "^1.17.1",
|
|
139
145
|
"pdf-to-png-converter": "^3.11.0",
|
|
146
|
+
"prisma": "^6.5.0",
|
|
140
147
|
"prismjs": "^1.30.0",
|
|
141
148
|
"react": "^18.2.0",
|
|
142
149
|
"react-dom": "^18.2.0",
|
package/dist/app/app.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import express from 'express';
|
|
2
|
-
import cors from 'cors';
|
|
3
|
-
import bodyParser from 'body-parser';
|
|
4
|
-
import { requestLogger, errorLogger } from './middleware/logger.js';
|
|
5
|
-
import { initDatabase, disconnect } from './db/index.js';
|
|
6
|
-
// 初始化Express应用
|
|
7
|
-
const app = express();
|
|
8
|
-
// 中间件配置
|
|
9
|
-
app.use(cors());
|
|
10
|
-
app.use(bodyParser.json());
|
|
11
|
-
app.use(bodyParser.urlencoded({ extended: true }));
|
|
12
|
-
app.use(requestLogger);
|
|
13
|
-
// 导入路由
|
|
14
|
-
import routes from './routes/routes.js';
|
|
15
|
-
// 使用路由
|
|
16
|
-
app.use('/api', routes);
|
|
17
|
-
// 健康检查
|
|
18
|
-
app.get('/health', (_req, res) => {
|
|
19
|
-
res.status(200).json({ status: 'ok' });
|
|
20
|
-
});
|
|
21
|
-
// 错误日志中间件
|
|
22
|
-
app.use(errorLogger);
|
|
23
|
-
// 错误处理中间件
|
|
24
|
-
app.use((err, _req, res, _next) => {
|
|
25
|
-
res.status(500).json({
|
|
26
|
-
message: 'Internal Server Error',
|
|
27
|
-
error: process.env.NODE_ENV === 'development' ? err.message : undefined
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
// 优雅关闭
|
|
31
|
-
process.on('SIGINT', async () => {
|
|
32
|
-
await disconnect();
|
|
33
|
-
console.log('Backend server has been shut down');
|
|
34
|
-
process.exit(0);
|
|
35
|
-
});
|
|
36
|
-
let server = null;
|
|
37
|
-
export { app };
|
|
38
|
-
export const start = async () => {
|
|
39
|
-
// 确保不会重复启动服务器
|
|
40
|
-
if (server) {
|
|
41
|
-
return server;
|
|
42
|
-
}
|
|
43
|
-
// 在启动服务器前初始化数据库
|
|
44
|
-
await initDatabase();
|
|
45
|
-
// 启动服务器并监听随机端口
|
|
46
|
-
server = app.listen(0, 'localhost');
|
|
47
|
-
return server;
|
|
48
|
-
};
|
|
49
|
-
export const getServer = () => server;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import model from '../logic/model.js';
|
|
2
|
-
// 补全请求
|
|
3
|
-
const completion = async (req, res, next) => {
|
|
4
|
-
// 验证请求
|
|
5
|
-
if (!req.body.providerId || !req.body.modelId || !req.body.messages) {
|
|
6
|
-
return res.status(400).json({ message: 'providerId, modelId, messages 为必填项' });
|
|
7
|
-
}
|
|
8
|
-
try {
|
|
9
|
-
const { providerId, modelId, messages, options } = req.body;
|
|
10
|
-
const completion = await model.completion(providerId, modelId, messages, options);
|
|
11
|
-
res.json(completion);
|
|
12
|
-
}
|
|
13
|
-
catch (error) {
|
|
14
|
-
next(error);
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
export default {
|
|
18
|
-
completion
|
|
19
|
-
};
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import modelDal from '../dal/modelDal.js';
|
|
2
|
-
// 获取指定服务商的模型列表
|
|
3
|
-
const getModelsByProviderId = async (req, res, next) => {
|
|
4
|
-
try {
|
|
5
|
-
const { provider } = req.params;
|
|
6
|
-
const models = await modelDal.findByProviderId(Number(provider));
|
|
7
|
-
res.json(models);
|
|
8
|
-
}
|
|
9
|
-
catch (error) {
|
|
10
|
-
next(error);
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
|
-
// 创建模型
|
|
14
|
-
const createModel = async (req, res, next) => {
|
|
15
|
-
try {
|
|
16
|
-
const { id, provider, name } = req.body;
|
|
17
|
-
// 验证请求
|
|
18
|
-
if (!provider || !name || !id) {
|
|
19
|
-
return res.status(400).json({ message: '模型ID、服务商ID、名称和为必填项' });
|
|
20
|
-
}
|
|
21
|
-
// 创建模型
|
|
22
|
-
const newModel = await modelDal.create({
|
|
23
|
-
id,
|
|
24
|
-
provider: Number(provider),
|
|
25
|
-
name,
|
|
26
|
-
});
|
|
27
|
-
res.status(201).json(newModel);
|
|
28
|
-
}
|
|
29
|
-
catch (error) {
|
|
30
|
-
next(error);
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
// 删除模型
|
|
34
|
-
const deleteModel = async (req, res, next) => {
|
|
35
|
-
try {
|
|
36
|
-
const { id, provider } = req.params;
|
|
37
|
-
// 验证请求
|
|
38
|
-
if (!id || !provider) {
|
|
39
|
-
return res.status(400).json({ message: '模型ID和服务商ID为必填项' });
|
|
40
|
-
}
|
|
41
|
-
// 删除模型
|
|
42
|
-
await modelDal.remove(id, Number(provider));
|
|
43
|
-
res.status(204).json({ message: '模型删除成功' });
|
|
44
|
-
}
|
|
45
|
-
catch (error) {
|
|
46
|
-
next(error);
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
export default {
|
|
50
|
-
getModelsByProviderId,
|
|
51
|
-
createModel,
|
|
52
|
-
deleteModel
|
|
53
|
-
};
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import providerDal from '../dal/providerDal.js';
|
|
2
|
-
// 获取所有服务商
|
|
3
|
-
const getAllProviders = async (_req, res, next) => {
|
|
4
|
-
try {
|
|
5
|
-
const providers = await providerDal.findAll();
|
|
6
|
-
res.json(providers);
|
|
7
|
-
}
|
|
8
|
-
catch (error) {
|
|
9
|
-
next(error);
|
|
10
|
-
}
|
|
11
|
-
};
|
|
12
|
-
// 根据ID获取服务商
|
|
13
|
-
const getProviderById = async (req, res, next) => {
|
|
14
|
-
try {
|
|
15
|
-
const { id } = req.params;
|
|
16
|
-
const provider = await providerDal.findById(Number(id));
|
|
17
|
-
if (!provider) {
|
|
18
|
-
return res.status(404).json({ message: '服务商不存在' });
|
|
19
|
-
}
|
|
20
|
-
res.json(provider);
|
|
21
|
-
}
|
|
22
|
-
catch (error) {
|
|
23
|
-
next(error);
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
// 创建服务商
|
|
27
|
-
const createProvider = async (req, res, next) => {
|
|
28
|
-
try {
|
|
29
|
-
const { name, type } = req.body;
|
|
30
|
-
// 验证请求
|
|
31
|
-
if (!name || !type) {
|
|
32
|
-
return res.status(400).json({ message: '名称和协议类型为必填项' });
|
|
33
|
-
}
|
|
34
|
-
// 创建服务商
|
|
35
|
-
const newProvider = await providerDal.create({
|
|
36
|
-
name,
|
|
37
|
-
type,
|
|
38
|
-
api_key: '',
|
|
39
|
-
base_url: '',
|
|
40
|
-
suffix: '',
|
|
41
|
-
status: 1 // 默认启用
|
|
42
|
-
});
|
|
43
|
-
res.status(201).json(newProvider);
|
|
44
|
-
}
|
|
45
|
-
catch (error) {
|
|
46
|
-
next(error);
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
// 更新服务商
|
|
50
|
-
const updateProvider = async (req, res, next) => {
|
|
51
|
-
try {
|
|
52
|
-
const { id } = req.params;
|
|
53
|
-
const { api_key, base_url, suffix } = req.body;
|
|
54
|
-
// 验证服务商存在
|
|
55
|
-
const existingProvider = await providerDal.findById(Number(id));
|
|
56
|
-
if (!existingProvider) {
|
|
57
|
-
return res.status(404).json({ message: '服务商不存在' });
|
|
58
|
-
}
|
|
59
|
-
// 准备更新数据
|
|
60
|
-
const updateData = {};
|
|
61
|
-
if (api_key !== undefined)
|
|
62
|
-
updateData.api_key = api_key;
|
|
63
|
-
if (base_url !== undefined)
|
|
64
|
-
updateData.base_url = base_url;
|
|
65
|
-
if (suffix !== undefined)
|
|
66
|
-
updateData.suffix = suffix;
|
|
67
|
-
// 更新服务商
|
|
68
|
-
const updatedProvider = await providerDal.update(Number(id), updateData);
|
|
69
|
-
res.json(updatedProvider);
|
|
70
|
-
}
|
|
71
|
-
catch (error) {
|
|
72
|
-
next(error);
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
// 删除服务商
|
|
76
|
-
const deleteProvider = async (req, res, next) => {
|
|
77
|
-
try {
|
|
78
|
-
const { id } = req.params;
|
|
79
|
-
// 验证服务商存在
|
|
80
|
-
const existingProvider = await providerDal.findById(Number(id));
|
|
81
|
-
if (!existingProvider) {
|
|
82
|
-
return res.status(404).json({ message: '服务商不存在' });
|
|
83
|
-
}
|
|
84
|
-
// 删除服务商
|
|
85
|
-
await providerDal.remove(Number(id));
|
|
86
|
-
res.status(204).send();
|
|
87
|
-
}
|
|
88
|
-
catch (error) {
|
|
89
|
-
next(error);
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
// 更新服务商状态
|
|
93
|
-
const updateProviderStatus = async (req, res, next) => {
|
|
94
|
-
try {
|
|
95
|
-
const { id } = req.params;
|
|
96
|
-
const { status } = req.body;
|
|
97
|
-
if (status === undefined) {
|
|
98
|
-
return res.status(400).json({ message: '状态值不合法' });
|
|
99
|
-
}
|
|
100
|
-
// 验证服务商存在
|
|
101
|
-
const existingProvider = await providerDal.findById(Number(id));
|
|
102
|
-
if (!existingProvider) {
|
|
103
|
-
return res.status(404).json({ message: '服务商不存在' });
|
|
104
|
-
}
|
|
105
|
-
// 更新服务商状态
|
|
106
|
-
const updatedProvider = await providerDal.updateStatus(Number(id), Number(status));
|
|
107
|
-
res.json(updatedProvider);
|
|
108
|
-
}
|
|
109
|
-
catch (error) {
|
|
110
|
-
next(error);
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
export default {
|
|
114
|
-
getAllProviders,
|
|
115
|
-
getProviderById,
|
|
116
|
-
createProvider,
|
|
117
|
-
updateProvider,
|
|
118
|
-
deleteProvider,
|
|
119
|
-
updateProviderStatus
|
|
120
|
-
};
|
package/dist/app/dal/modelDal.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { prisma } from "../db/index.js";
|
|
2
|
-
// 查找所有模型
|
|
3
|
-
const findAll = async () => {
|
|
4
|
-
return await prisma.model.findMany({
|
|
5
|
-
orderBy: [{ createdAt: "desc" }],
|
|
6
|
-
});
|
|
7
|
-
};
|
|
8
|
-
// 根据服务商ID查找模型
|
|
9
|
-
const findByProviderId = async (provider) => {
|
|
10
|
-
return await prisma.model.findMany({
|
|
11
|
-
where: { provider },
|
|
12
|
-
orderBy: [{ createdAt: "desc" }],
|
|
13
|
-
});
|
|
14
|
-
};
|
|
15
|
-
// 创建模型
|
|
16
|
-
const create = async (modelData) => {
|
|
17
|
-
return await prisma.model.create({
|
|
18
|
-
data: modelData,
|
|
19
|
-
});
|
|
20
|
-
};
|
|
21
|
-
// 删除模型 根据id和provider删除
|
|
22
|
-
const remove = async (id, provider) => {
|
|
23
|
-
return await prisma.model.delete({
|
|
24
|
-
where: {
|
|
25
|
-
id_provider: {
|
|
26
|
-
id: id,
|
|
27
|
-
provider: provider
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
};
|
|
32
|
-
// 批量删除指定服务商的模型
|
|
33
|
-
const removeByProviderId = async (provider) => {
|
|
34
|
-
return await prisma.model.deleteMany({
|
|
35
|
-
where: { provider },
|
|
36
|
-
});
|
|
37
|
-
};
|
|
38
|
-
export default {
|
|
39
|
-
findAll,
|
|
40
|
-
findByProviderId,
|
|
41
|
-
create,
|
|
42
|
-
remove,
|
|
43
|
-
removeByProviderId,
|
|
44
|
-
};
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { prisma } from "../db/index.js";
|
|
2
|
-
// 查找所有提供商
|
|
3
|
-
const findAll = async () => {
|
|
4
|
-
return await prisma.provider.findMany({
|
|
5
|
-
select: {
|
|
6
|
-
id: true,
|
|
7
|
-
name: true,
|
|
8
|
-
type: true,
|
|
9
|
-
api_key: true,
|
|
10
|
-
base_url: true,
|
|
11
|
-
suffix: true,
|
|
12
|
-
status: true,
|
|
13
|
-
createdAt: true,
|
|
14
|
-
updatedAt: true,
|
|
15
|
-
},
|
|
16
|
-
orderBy: [{ createdAt: "desc" }],
|
|
17
|
-
});
|
|
18
|
-
};
|
|
19
|
-
// 根据ID查找提供商
|
|
20
|
-
const findById = async (id) => {
|
|
21
|
-
return await prisma.provider.findUnique({
|
|
22
|
-
where: { id },
|
|
23
|
-
select: {
|
|
24
|
-
id: true,
|
|
25
|
-
name: true,
|
|
26
|
-
type: true,
|
|
27
|
-
api_key: true,
|
|
28
|
-
base_url: true,
|
|
29
|
-
suffix: true,
|
|
30
|
-
status: true,
|
|
31
|
-
createdAt: true,
|
|
32
|
-
updatedAt: true,
|
|
33
|
-
},
|
|
34
|
-
});
|
|
35
|
-
};
|
|
36
|
-
// 创建提供商
|
|
37
|
-
const create = async (providerData) => {
|
|
38
|
-
// 设置默认值
|
|
39
|
-
const data = {
|
|
40
|
-
name: providerData.name || '',
|
|
41
|
-
type: providerData.type || '',
|
|
42
|
-
api_key: providerData.api_key || '',
|
|
43
|
-
base_url: providerData.base_url || '',
|
|
44
|
-
suffix: providerData.suffix || '',
|
|
45
|
-
status: providerData.status || 0
|
|
46
|
-
};
|
|
47
|
-
return await prisma.provider.create({
|
|
48
|
-
data
|
|
49
|
-
});
|
|
50
|
-
};
|
|
51
|
-
// 更新提供商
|
|
52
|
-
const update = async (id, updateData) => {
|
|
53
|
-
return await prisma.provider.update({
|
|
54
|
-
where: { id },
|
|
55
|
-
data: updateData,
|
|
56
|
-
});
|
|
57
|
-
};
|
|
58
|
-
// 删除提供商
|
|
59
|
-
const remove = async (id) => {
|
|
60
|
-
return await prisma.provider.delete({
|
|
61
|
-
where: { id },
|
|
62
|
-
});
|
|
63
|
-
};
|
|
64
|
-
// 更新提供商状态
|
|
65
|
-
const updateStatus = async (id, status) => {
|
|
66
|
-
return await prisma.provider.update({
|
|
67
|
-
where: { id },
|
|
68
|
-
data: { status },
|
|
69
|
-
});
|
|
70
|
-
};
|
|
71
|
-
export default {
|
|
72
|
-
findAll,
|
|
73
|
-
findById,
|
|
74
|
-
create,
|
|
75
|
-
update,
|
|
76
|
-
remove,
|
|
77
|
-
updateStatus,
|
|
78
|
-
};
|
package/dist/app/db/index.js
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import pkg from '@prisma/client';
|
|
2
|
-
const { PrismaClient } = pkg;
|
|
3
|
-
import { runMigrations } from './migration.js';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
import { app } from 'electron';
|
|
6
|
-
import fs from 'fs';
|
|
7
|
-
// 设置和获取数据库URL
|
|
8
|
-
function getDatabaseUrl() {
|
|
9
|
-
// 否则,为打包应用生成一个默认路径
|
|
10
|
-
if (app) {
|
|
11
|
-
const userDataPath = app.getPath('userData');
|
|
12
|
-
const dbDir = path.join(userDataPath, 'db');
|
|
13
|
-
if (!fs.existsSync(dbDir)) {
|
|
14
|
-
fs.mkdirSync(dbDir, { recursive: true });
|
|
15
|
-
}
|
|
16
|
-
console.log('Using userData database path:', `file:${path.join(dbDir, 'app.db')}`);
|
|
17
|
-
return `file:${path.join(dbDir, 'app.db')}`;
|
|
18
|
-
}
|
|
19
|
-
// 开发环境回退路径
|
|
20
|
-
console.log('Using default development database path:', 'file:./dev.db');
|
|
21
|
-
return 'file:./dev.db';
|
|
22
|
-
}
|
|
23
|
-
// 获取数据库URL
|
|
24
|
-
const dbUrl = getDatabaseUrl();
|
|
25
|
-
// 创建Prisma实例,使用环境变量中的数据库URL
|
|
26
|
-
const prisma = new PrismaClient({
|
|
27
|
-
datasources: {
|
|
28
|
-
db: {
|
|
29
|
-
url: dbUrl
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
// 初始化数据库,包括运行迁移
|
|
34
|
-
const initDatabase = async () => {
|
|
35
|
-
try {
|
|
36
|
-
console.log(`Initializing database(url:${dbUrl})...`);
|
|
37
|
-
// 验证数据库连接
|
|
38
|
-
await prisma.$queryRaw `SELECT 1`;
|
|
39
|
-
console.log('Database connection established successfully.');
|
|
40
|
-
// 运行迁移,传递现有的prisma实例
|
|
41
|
-
await runMigrations(prisma);
|
|
42
|
-
return true;
|
|
43
|
-
}
|
|
44
|
-
catch (error) {
|
|
45
|
-
console.error('Database initialization error:', error);
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
/**
|
|
50
|
-
* 关闭数据库连接
|
|
51
|
-
*/
|
|
52
|
-
const disconnect = async () => {
|
|
53
|
-
await prisma.$disconnect();
|
|
54
|
-
console.log('Database connection has been closed');
|
|
55
|
-
};
|
|
56
|
-
export { prisma, disconnect, initDatabase };
|
package/dist/app/db/migration.js
DELETED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import fs from 'fs';
|
|
3
|
-
import isDev from 'electron-is-dev';
|
|
4
|
-
import { app } from 'electron';
|
|
5
|
-
// 获取迁移文件目录
|
|
6
|
-
const getMigrationsDir = () => {
|
|
7
|
-
// 在开发环境使用项目目录
|
|
8
|
-
if (isDev) {
|
|
9
|
-
return path.join(process.cwd(), 'app', 'db', 'migrations');
|
|
10
|
-
}
|
|
11
|
-
// 在打包环境中,确保使用正确的路径
|
|
12
|
-
// 使用app.getAppPath()获取应用根目录
|
|
13
|
-
if (app) {
|
|
14
|
-
return path.join(app.getAppPath(), 'app', 'db', 'migrations');
|
|
15
|
-
}
|
|
16
|
-
// 回退到__dirname相对路径
|
|
17
|
-
return path.join(__dirname, 'migrations');
|
|
18
|
-
};
|
|
19
|
-
// 创建 _prisma_migrations 表的SQL
|
|
20
|
-
const createMigrationsTableSQL = `
|
|
21
|
-
CREATE TABLE IF NOT EXISTS _prisma_migrations (
|
|
22
|
-
id VARCHAR(36) PRIMARY KEY NOT NULL,
|
|
23
|
-
checksum VARCHAR(64) NOT NULL,
|
|
24
|
-
finished_at DATETIME,
|
|
25
|
-
migration_name VARCHAR(255) NOT NULL,
|
|
26
|
-
logs TEXT,
|
|
27
|
-
rolled_back_at DATETIME,
|
|
28
|
-
started_at DATETIME NOT NULL DEFAULT current_timestamp,
|
|
29
|
-
applied_steps_count INTEGER UNSIGNED NOT NULL DEFAULT 0
|
|
30
|
-
);
|
|
31
|
-
`;
|
|
32
|
-
// 检查迁移是否已应用
|
|
33
|
-
const isMigrationApplied = async (prisma, migrationName) => {
|
|
34
|
-
try {
|
|
35
|
-
// 检查 _prisma_migrations 表是否存在
|
|
36
|
-
const tableExists = await prisma.$queryRaw `
|
|
37
|
-
SELECT name FROM sqlite_master
|
|
38
|
-
WHERE type='table' AND name='_prisma_migrations';
|
|
39
|
-
`;
|
|
40
|
-
if (!tableExists || tableExists.length === 0) {
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
// 检查特定迁移是否已应用
|
|
44
|
-
const migration = await prisma.$queryRaw `
|
|
45
|
-
SELECT * FROM _prisma_migrations
|
|
46
|
-
WHERE migration_name = ${migrationName}
|
|
47
|
-
AND finished_at IS NOT NULL;
|
|
48
|
-
`;
|
|
49
|
-
return migration && migration.length > 0;
|
|
50
|
-
}
|
|
51
|
-
catch (error) {
|
|
52
|
-
console.error('Error checking migration status:', error);
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
// 记录已应用的迁移
|
|
57
|
-
const recordMigration = async (prisma, migrationName, checksum) => {
|
|
58
|
-
const id = generateUUID();
|
|
59
|
-
const now = new Date().toISOString();
|
|
60
|
-
try {
|
|
61
|
-
await prisma.$executeRaw `
|
|
62
|
-
INSERT INTO _prisma_migrations (
|
|
63
|
-
id, checksum, migration_name, started_at, finished_at, applied_steps_count
|
|
64
|
-
) VALUES (
|
|
65
|
-
${id}, ${checksum}, ${migrationName}, ${now}, ${now}, 1
|
|
66
|
-
);
|
|
67
|
-
`;
|
|
68
|
-
console.log(`Recorded migration: ${migrationName}`);
|
|
69
|
-
}
|
|
70
|
-
catch (error) {
|
|
71
|
-
console.error(`Failed to record migration ${migrationName}:`, error);
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
// 生成UUID
|
|
75
|
-
const generateUUID = () => {
|
|
76
|
-
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
77
|
-
const r = Math.random() * 16 | 0;
|
|
78
|
-
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
|
79
|
-
return v.toString(16);
|
|
80
|
-
});
|
|
81
|
-
};
|
|
82
|
-
// 计算迁移文件的checksum
|
|
83
|
-
const calculateChecksum = async (content) => {
|
|
84
|
-
// 使用ESM方式导入crypto
|
|
85
|
-
const crypto = await import('crypto');
|
|
86
|
-
return crypto.default.createHash('sha256').update(content).digest('hex');
|
|
87
|
-
};
|
|
88
|
-
// 应用单个迁移
|
|
89
|
-
const applyMigration = async (prisma, migrationDir, migrationName) => {
|
|
90
|
-
const sqlFilePath = path.join(migrationDir, migrationName, 'migration.sql');
|
|
91
|
-
try {
|
|
92
|
-
if (!fs.existsSync(sqlFilePath)) {
|
|
93
|
-
console.error(`Migration SQL file not found: ${sqlFilePath}`);
|
|
94
|
-
return false;
|
|
95
|
-
}
|
|
96
|
-
const sqlContent = fs.readFileSync(sqlFilePath, 'utf8');
|
|
97
|
-
const sqlStatements = sqlContent.split(';').filter(stmt => stmt.trim());
|
|
98
|
-
// 应用每条SQL语句
|
|
99
|
-
for (const statement of sqlStatements) {
|
|
100
|
-
if (statement.trim()) {
|
|
101
|
-
await prisma.$executeRawUnsafe(statement.trim());
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
// 记录迁移
|
|
105
|
-
const checksum = await calculateChecksum(sqlContent);
|
|
106
|
-
await recordMigration(prisma, migrationName, checksum);
|
|
107
|
-
console.log(`Successfully applied migration: ${migrationName}`);
|
|
108
|
-
return true;
|
|
109
|
-
}
|
|
110
|
-
catch (error) {
|
|
111
|
-
console.error(`Failed to apply migration ${migrationName}:`, error);
|
|
112
|
-
return false;
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
// 主要的迁移函数
|
|
116
|
-
const runMigrations = async (prisma = null) => {
|
|
117
|
-
console.log('Running database migrations...');
|
|
118
|
-
try {
|
|
119
|
-
// 确保_prisma_migrations表存在
|
|
120
|
-
await prisma.$executeRawUnsafe(createMigrationsTableSQL);
|
|
121
|
-
const migrationsDir = getMigrationsDir();
|
|
122
|
-
console.log('Migrations directory:', migrationsDir);
|
|
123
|
-
if (!fs.existsSync(migrationsDir)) {
|
|
124
|
-
console.error(`Migrations directory not found: ${migrationsDir}`);
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
127
|
-
// 读取所有迁移目录并按名称排序
|
|
128
|
-
const migrationDirs = fs
|
|
129
|
-
.readdirSync(migrationsDir)
|
|
130
|
-
.filter(dir => {
|
|
131
|
-
const stat = fs.statSync(path.join(migrationsDir, dir));
|
|
132
|
-
return stat.isDirectory() && dir !== 'migration_lock.toml';
|
|
133
|
-
})
|
|
134
|
-
.sort(); // 按名称排序,确保按正确顺序应用
|
|
135
|
-
let migrationsApplied = 0;
|
|
136
|
-
// 应用每个迁移
|
|
137
|
-
for (const migrationName of migrationDirs) {
|
|
138
|
-
const isApplied = await isMigrationApplied(prisma, migrationName);
|
|
139
|
-
if (!isApplied) {
|
|
140
|
-
console.log(`Applying migration: ${migrationName}`);
|
|
141
|
-
const success = await applyMigration(prisma, migrationsDir, migrationName);
|
|
142
|
-
if (success)
|
|
143
|
-
migrationsApplied++;
|
|
144
|
-
}
|
|
145
|
-
else {
|
|
146
|
-
console.log(`Migration already applied: ${migrationName}`);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
console.log(`Database migration complete. Applied ${migrationsApplied} migrations.`);
|
|
150
|
-
return migrationsApplied > 0;
|
|
151
|
-
}
|
|
152
|
-
catch (error) {
|
|
153
|
-
console.error('Migration error:', error);
|
|
154
|
-
return false;
|
|
155
|
-
}
|
|
156
|
-
};
|
|
157
|
-
export { runMigrations };
|