blockmine 1.22.0 → 1.23.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/.claude/settings.json +5 -1
- package/.claude/settings.local.json +10 -1
- package/CHANGELOG.md +27 -3
- package/CLAUDE.md +284 -0
- package/README.md +302 -152
- package/backend/package-lock.json +681 -9
- package/backend/package.json +8 -0
- package/backend/prisma/migrations/20251116111851_add_execution_trace/migration.sql +22 -0
- package/backend/prisma/migrations/20251120154914_add_panel_api_keys/migration.sql +21 -0
- package/backend/prisma/migrations/20251121110241_add_proxy_table/migration.sql +45 -0
- package/backend/prisma/migrations/migration_lock.toml +2 -2
- package/backend/prisma/schema.prisma +70 -1
- package/backend/src/__tests__/services/BotLifecycleService.test.js +9 -4
- package/backend/src/ai/plugin-assistant-system-prompt.md +788 -0
- package/backend/src/api/middleware/auth.js +27 -0
- package/backend/src/api/middleware/botAccess.js +7 -3
- package/backend/src/api/middleware/panelApiAuth.js +135 -0
- package/backend/src/api/routes/aiAssistant.js +995 -0
- package/backend/src/api/routes/auth.js +669 -633
- package/backend/src/api/routes/botCommands.js +107 -0
- package/backend/src/api/routes/botGroups.js +165 -0
- package/backend/src/api/routes/botHistory.js +108 -0
- package/backend/src/api/routes/botPermissions.js +99 -0
- package/backend/src/api/routes/botStatus.js +36 -0
- package/backend/src/api/routes/botUsers.js +162 -0
- package/backend/src/api/routes/bots.js +2451 -2402
- package/backend/src/api/routes/eventGraphs.js +4 -1
- package/backend/src/api/routes/logs.js +13 -3
- package/backend/src/api/routes/panel.js +66 -66
- package/backend/src/api/routes/panelApiKeys.js +179 -0
- package/backend/src/api/routes/pluginIde.js +1715 -135
- package/backend/src/api/routes/plugins.js +376 -219
- package/backend/src/api/routes/proxies.js +130 -0
- package/backend/src/api/routes/search.js +4 -0
- package/backend/src/api/routes/servers.js +20 -3
- package/backend/src/api/routes/settings.js +5 -0
- package/backend/src/api/routes/system.js +174 -174
- package/backend/src/api/routes/traces.js +131 -0
- package/backend/src/config/debug.config.js +36 -0
- package/backend/src/core/BotHistoryStore.js +180 -0
- package/backend/src/core/BotManager.js +14 -4
- package/backend/src/core/BotProcess.js +1517 -1092
- package/backend/src/core/EventGraphManager.js +37 -123
- package/backend/src/core/GraphExecutionEngine.js +977 -321
- package/backend/src/core/MessageQueue.js +12 -6
- package/backend/src/core/PluginLoader.js +99 -5
- package/backend/src/core/PluginManager.js +74 -13
- package/backend/src/core/TaskScheduler.js +1 -1
- package/backend/src/core/commands/whois.js +1 -1
- package/backend/src/core/node-registries/actions.js +70 -0
- package/backend/src/core/node-registries/arrays.js +18 -0
- package/backend/src/core/node-registries/data.js +1 -1
- package/backend/src/core/node-registries/events.js +14 -0
- package/backend/src/core/node-registries/logic.js +17 -0
- package/backend/src/core/node-registries/strings.js +34 -0
- package/backend/src/core/node-registries/type.js +25 -0
- package/backend/src/core/nodes/actions/bot_look_at.js +1 -1
- package/backend/src/core/nodes/actions/create_command.js +189 -0
- package/backend/src/core/nodes/actions/delete_command.js +92 -0
- package/backend/src/core/nodes/actions/update_command.js +133 -0
- package/backend/src/core/nodes/arrays/join.js +28 -0
- package/backend/src/core/nodes/data/cast.js +2 -1
- package/backend/src/core/nodes/logic/not.js +22 -0
- package/backend/src/core/nodes/strings/starts_with.js +1 -1
- package/backend/src/core/nodes/strings/to_lower.js +22 -0
- package/backend/src/core/nodes/strings/to_upper.js +22 -0
- package/backend/src/core/nodes/type/to_string.js +32 -0
- package/backend/src/core/services/BotLifecycleService.js +255 -16
- package/backend/src/core/services/CommandExecutionService.js +430 -351
- package/backend/src/core/services/DebugSessionManager.js +347 -0
- package/backend/src/core/services/GraphCollaborationManager.js +501 -0
- package/backend/src/core/services/MinecraftBotManager.js +259 -0
- package/backend/src/core/services/MinecraftViewerService.js +216 -0
- package/backend/src/core/services/TraceCollectorService.js +545 -0
- package/backend/src/core/system/RuntimeCommandRegistry.js +116 -0
- package/backend/src/core/system/Transport.js +0 -4
- package/backend/src/core/validation/nodeSchemas.js +6 -6
- package/backend/src/real-time/botApi/handlers/graphHandlers.js +2 -2
- package/backend/src/real-time/botApi/handlers/graphWebSocketHandlers.js +1 -1
- package/backend/src/real-time/botApi/utils.js +11 -0
- package/backend/src/real-time/panelNamespace.js +387 -0
- package/backend/src/real-time/presence.js +7 -2
- package/backend/src/real-time/socketHandler.js +395 -4
- package/backend/src/server.js +18 -0
- package/frontend/dist/assets/index-B1serztM.js +11210 -0
- package/frontend/dist/assets/index-t6K1u4OV.css +32 -0
- package/frontend/dist/index.html +2 -2
- package/frontend/package-lock.json +9437 -0
- package/frontend/package.json +8 -0
- package/package.json +2 -2
- package/screen/console.png +0 -0
- package/screen/dashboard.png +0 -0
- package/screen/graph_collabe.png +0 -0
- package/screen/graph_live_debug.png +0 -0
- package/screen/management_command.png +0 -0
- package/screen/node_debug_trace.png +0 -0
- package/screen/plugin_/320/276/320/261/320/267/320/276/321/200.png +0 -0
- package/screen/websocket.png +0 -0
- package/screen//320/275/320/260/321/201/321/202/321/200/320/276/320/271/320/272/320/270_/320/276/321/202/320/264/320/265/320/273/321/214/320/275/321/213/321/205_/320/272/320/276/320/274/320/260/320/275/320/264_/320/272/320/260/320/266/320/264/321/203_/320/272/320/276/320/274/320/260/320/275/320/273/320/264/321/203_/320/274/320/276/320/266/320/275/320/276_/320/275/320/260/321/201/321/202/321/200/320/260/320/270/320/262/320/260/321/202/321/214.png +0 -0
- package/screen//320/277/320/273/320/260/320/275/320/270/321/200/320/276/320/262/321/211/320/270/320/272_/320/274/320/276/320/266/320/275/320/276_/320/267/320/260/320/264/320/260/320/262/320/260/321/202/321/214_/320/264/320/265/320/271/321/201/321/202/320/262/320/270/321/217_/320/277/320/276_/320/262/321/200/320/265/320/274/320/265/320/275/320/270.png +0 -0
- package/frontend/dist/assets/index-CfTo92bP.css +0 -1
- package/frontend/dist/assets/index-CiFD5X9Z.js +0 -8344
|
@@ -1,220 +1,377 @@
|
|
|
1
|
-
const express = require('express');
|
|
2
|
-
const {
|
|
3
|
-
const { PrismaClient } = require('@prisma/client');
|
|
4
|
-
const router = express.Router();
|
|
5
|
-
const { pluginManager } = require('../../core/services');
|
|
6
|
-
|
|
7
|
-
const prisma = new PrismaClient();
|
|
8
|
-
const OFFICIAL_CATALOG_URL = "https://raw.githubusercontent.com/blockmineJS/official-plugins-list/main/index.json";
|
|
9
|
-
|
|
10
|
-
const getCacheBustedUrl = (url) => `${url}?t=${new Date().getTime()}`;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
router.get('/catalog', async (req, res) => {
|
|
14
|
-
try {
|
|
15
|
-
const response = await fetch(getCacheBustedUrl(OFFICIAL_CATALOG_URL));
|
|
16
|
-
|
|
17
|
-
if (!response.ok) {
|
|
18
|
-
const errorText = await response.text();
|
|
19
|
-
console.error(`[API Error] Failed to fetch catalog from GitHub. Status: ${response.status}, Response: ${errorText}`);
|
|
20
|
-
throw new Error(`GitHub returned status ${response.status}`);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
res.json(await response.json());
|
|
24
|
-
} catch (error) {
|
|
25
|
-
console.error(`[API Error] Could not fetch catalog URL. Reason: ${error.message}`);
|
|
26
|
-
res.status(500).json({ error: 'Не удалось загрузить каталог плагинов.' });
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
router.post('/check-updates/:botId',
|
|
31
|
-
try {
|
|
32
|
-
const botId = parseInt(req.params.botId);
|
|
33
|
-
|
|
34
|
-
const catalogResponse = await fetch(getCacheBustedUrl(OFFICIAL_CATALOG_URL));
|
|
35
|
-
if (!catalogResponse.ok) throw new Error('Не удалось загрузить каталог для проверки обновлений.');
|
|
36
|
-
const catalog = await catalogResponse.json();
|
|
37
|
-
|
|
38
|
-
const updates = await pluginManager.checkForUpdates(botId, catalog);
|
|
39
|
-
res.json(updates);
|
|
40
|
-
} catch (error) {
|
|
41
|
-
console.error("[API Error] /check-updates:", error);
|
|
42
|
-
res.status(500).json({ error: 'Не удалось проверить обновления.' });
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
router.post('/update/:pluginId',
|
|
47
|
-
try {
|
|
48
|
-
const pluginId = parseInt(req.params.pluginId);
|
|
49
|
-
const { targetTag } = req.body; // Получаем тег из тела запроса (если указан)
|
|
50
|
-
const updatedPlugin = await pluginManager.updatePlugin(pluginId, targetTag);
|
|
51
|
-
res.json(updatedPlugin);
|
|
52
|
-
} catch (error) {
|
|
53
|
-
res.status(500).json({ error: error.message });
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
router.post('/:id/clear-data',
|
|
58
|
-
try {
|
|
59
|
-
const pluginId = parseInt(req.params.id);
|
|
60
|
-
await pluginManager.clearPluginData(pluginId);
|
|
61
|
-
res.status(200).json({ message: 'Данные плагина успешно очищены.' });
|
|
62
|
-
} catch (error) {
|
|
63
|
-
console.error(`[API Error] /plugins/:id/clear-data:`, error);
|
|
64
|
-
res.status(500).json({ error: error.message || 'Не удалось очистить данные плагина.' });
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
router.
|
|
69
|
-
try {
|
|
70
|
-
const pluginId = parseInt(req.params.id);
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
})
|
|
219
|
-
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const { authenticateUniversal, authorize } = require('../middleware/auth');
|
|
3
|
+
const { PrismaClient } = require('@prisma/client');
|
|
4
|
+
const router = express.Router();
|
|
5
|
+
const { pluginManager } = require('../../core/services');
|
|
6
|
+
|
|
7
|
+
const prisma = new PrismaClient();
|
|
8
|
+
const OFFICIAL_CATALOG_URL = "https://raw.githubusercontent.com/blockmineJS/official-plugins-list/main/index.json";
|
|
9
|
+
|
|
10
|
+
const getCacheBustedUrl = (url) => `${url}?t=${new Date().getTime()}`;
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
router.get('/catalog', async (req, res) => {
|
|
14
|
+
try {
|
|
15
|
+
const response = await fetch(getCacheBustedUrl(OFFICIAL_CATALOG_URL));
|
|
16
|
+
|
|
17
|
+
if (!response.ok) {
|
|
18
|
+
const errorText = await response.text();
|
|
19
|
+
console.error(`[API Error] Failed to fetch catalog from GitHub. Status: ${response.status}, Response: ${errorText}`);
|
|
20
|
+
throw new Error(`GitHub returned status ${response.status}`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
res.json(await response.json());
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.error(`[API Error] Could not fetch catalog URL. Reason: ${error.message}`);
|
|
26
|
+
res.status(500).json({ error: 'Не удалось загрузить каталог плагинов.' });
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
router.post('/check-updates/:botId', authenticateUniversal, authorize('plugin:update'), async (req, res) => {
|
|
31
|
+
try {
|
|
32
|
+
const botId = parseInt(req.params.botId);
|
|
33
|
+
|
|
34
|
+
const catalogResponse = await fetch(getCacheBustedUrl(OFFICIAL_CATALOG_URL));
|
|
35
|
+
if (!catalogResponse.ok) throw new Error('Не удалось загрузить каталог для проверки обновлений.');
|
|
36
|
+
const catalog = await catalogResponse.json();
|
|
37
|
+
|
|
38
|
+
const updates = await pluginManager.checkForUpdates(botId, catalog);
|
|
39
|
+
res.json(updates);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.error("[API Error] /check-updates:", error);
|
|
42
|
+
res.status(500).json({ error: 'Не удалось проверить обновления.' });
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
router.post('/update/:pluginId', authenticateUniversal, authorize('plugin:update'), async (req, res) => {
|
|
47
|
+
try {
|
|
48
|
+
const pluginId = parseInt(req.params.pluginId);
|
|
49
|
+
const { targetTag } = req.body; // Получаем тег из тела запроса (если указан)
|
|
50
|
+
const updatedPlugin = await pluginManager.updatePlugin(pluginId, targetTag);
|
|
51
|
+
res.json(updatedPlugin);
|
|
52
|
+
} catch (error) {
|
|
53
|
+
res.status(500).json({ error: error.message });
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
router.post('/:id/clear-data', authenticateUniversal, authorize('plugin:settings:edit'), async (req, res) => {
|
|
58
|
+
try {
|
|
59
|
+
const pluginId = parseInt(req.params.id);
|
|
60
|
+
await pluginManager.clearPluginData(pluginId);
|
|
61
|
+
res.status(200).json({ message: 'Данные плагина успешно очищены.' });
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.error(`[API Error] /plugins/:id/clear-data:`, error);
|
|
64
|
+
res.status(500).json({ error: error.message || 'Не удалось очистить данные плагина.' });
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
router.post('/:id/reload', authenticateUniversal, authorize('plugin:settings:edit'), async (req, res) => {
|
|
69
|
+
try {
|
|
70
|
+
const pluginId = parseInt(req.params.id);
|
|
71
|
+
const updatedPlugin = await pluginManager.reloadLocalPlugin(pluginId);
|
|
72
|
+
res.status(200).json({
|
|
73
|
+
message: 'Плагин перезагружен, настройки сброшены.',
|
|
74
|
+
plugin: updatedPlugin
|
|
75
|
+
});
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.error(`[API Error] /plugins/:id/reload:`, error);
|
|
78
|
+
res.status(500).json({ error: error.message || 'Не удалось перезагрузить плагин.' });
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
router.get('/:id/info', authenticateUniversal, authorize('plugin:list'), async (req, res) => {
|
|
83
|
+
try {
|
|
84
|
+
const pluginId = parseInt(req.params.id);
|
|
85
|
+
|
|
86
|
+
const plugin = await prisma.installedPlugin.findUnique({
|
|
87
|
+
where: { id: pluginId },
|
|
88
|
+
select: {
|
|
89
|
+
id: true,
|
|
90
|
+
name: true,
|
|
91
|
+
version: true,
|
|
92
|
+
description: true,
|
|
93
|
+
sourceType: true,
|
|
94
|
+
sourceUri: true,
|
|
95
|
+
isEnabled: true,
|
|
96
|
+
manifest: true,
|
|
97
|
+
settings: true,
|
|
98
|
+
createdAt: true,
|
|
99
|
+
commands: {
|
|
100
|
+
select: {
|
|
101
|
+
id: true,
|
|
102
|
+
name: true,
|
|
103
|
+
description: true,
|
|
104
|
+
isEnabled: true,
|
|
105
|
+
isVisual: true,
|
|
106
|
+
owner: true
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
eventGraphs: {
|
|
110
|
+
select: {
|
|
111
|
+
id: true,
|
|
112
|
+
name: true,
|
|
113
|
+
isEnabled: true,
|
|
114
|
+
createdAt: true,
|
|
115
|
+
updatedAt: true
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
if (!plugin) {
|
|
122
|
+
return res.status(404).json({ error: 'Плагин не найден.' });
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
res.json(plugin);
|
|
126
|
+
} catch (error) {
|
|
127
|
+
console.error(`[API Error] /plugins/:id/info:`, error);
|
|
128
|
+
res.status(500).json({ error: 'Не удалось получить информацию о плагине.' });
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
router.get('/bot/:botId', authenticateUniversal, authorize('plugin:list'), async (req, res) => {
|
|
133
|
+
try {
|
|
134
|
+
const botId = parseInt(req.params.botId);
|
|
135
|
+
|
|
136
|
+
const plugins = await prisma.installedPlugin.findMany({
|
|
137
|
+
where: { botId },
|
|
138
|
+
select: {
|
|
139
|
+
id: true,
|
|
140
|
+
name: true,
|
|
141
|
+
version: true,
|
|
142
|
+
description: true,
|
|
143
|
+
sourceType: true,
|
|
144
|
+
sourceUri: true,
|
|
145
|
+
isEnabled: true,
|
|
146
|
+
manifest: true,
|
|
147
|
+
settings: true,
|
|
148
|
+
createdAt: true,
|
|
149
|
+
commands: {
|
|
150
|
+
select: {
|
|
151
|
+
id: true,
|
|
152
|
+
name: true,
|
|
153
|
+
description: true,
|
|
154
|
+
isEnabled: true,
|
|
155
|
+
isVisual: true,
|
|
156
|
+
owner: true
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
eventGraphs: {
|
|
160
|
+
select: {
|
|
161
|
+
id: true,
|
|
162
|
+
name: true,
|
|
163
|
+
isEnabled: true,
|
|
164
|
+
createdAt: true,
|
|
165
|
+
updatedAt: true
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
orderBy: { name: 'asc' }
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
res.json(plugins);
|
|
173
|
+
} catch (error) {
|
|
174
|
+
console.error(`[API Error] /plugins/bot/:botId:`, error);
|
|
175
|
+
res.status(500).json({ error: 'Не удалось получить список плагинов.' });
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
router.get('/catalog/:name', async (req, res) => {
|
|
180
|
+
try {
|
|
181
|
+
const pluginName = req.params.name;
|
|
182
|
+
|
|
183
|
+
const catalogResponse = await fetch(getCacheBustedUrl(OFFICIAL_CATALOG_URL));
|
|
184
|
+
if (!catalogResponse.ok) throw new Error(`Failed to fetch catalog, status: ${catalogResponse.status}`);
|
|
185
|
+
|
|
186
|
+
const catalog = await catalogResponse.json();
|
|
187
|
+
const pluginInfo = catalog.find(p => p.name === pluginName);
|
|
188
|
+
|
|
189
|
+
if (!pluginInfo) {
|
|
190
|
+
return res.status(404).json({ error: 'Плагин с таким именем не найден в каталоге.' });
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
let readmeContent = pluginInfo.description || 'Описание для этого плагина не предоставлено.';
|
|
194
|
+
|
|
195
|
+
try {
|
|
196
|
+
const urlParts = new URL(pluginInfo.repoUrl);
|
|
197
|
+
const pathParts = urlParts.pathname.split('/').filter(p => p);
|
|
198
|
+
|
|
199
|
+
if (pathParts.length >= 2) {
|
|
200
|
+
const owner = pathParts[0];
|
|
201
|
+
const repo = pathParts[1].replace('.git', '');
|
|
202
|
+
|
|
203
|
+
const readmeUrls = [
|
|
204
|
+
`https://raw.githubusercontent.com/${owner}/${repo}/main/README.md`,
|
|
205
|
+
`https://raw.githubusercontent.com/${owner}/${repo}/master/README.md`,
|
|
206
|
+
`https://raw.githubusercontent.com/${owner}/${repo}/main/readme.md`,
|
|
207
|
+
`https://raw.githubusercontent.com/${owner}/${repo}/master/readme.md`,
|
|
208
|
+
];
|
|
209
|
+
|
|
210
|
+
for (const url of readmeUrls) {
|
|
211
|
+
const readmeResponse = await fetch(getCacheBustedUrl(url));
|
|
212
|
+
if (readmeResponse.ok) {
|
|
213
|
+
readmeContent = await readmeResponse.text();
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
} catch (readmeError) {
|
|
219
|
+
console.error(`[API] Не удалось загрузить README для ${pluginName}:`, readmeError.message);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const finalPluginData = {
|
|
223
|
+
...pluginInfo,
|
|
224
|
+
fullDescription: readmeContent
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
res.json(finalPluginData);
|
|
228
|
+
} catch (error) {
|
|
229
|
+
console.error(`[API Error] /catalog/:name :`, error);
|
|
230
|
+
res.status(500).json({ error: 'Не удалось загрузить данные плагина.' });
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
router.get('/bot/:botId/:pluginName/store', authenticateUniversal, authorize('plugin:list'), async (req, res) => {
|
|
235
|
+
try {
|
|
236
|
+
const botId = parseInt(req.params.botId);
|
|
237
|
+
const pluginName = req.params.pluginName;
|
|
238
|
+
|
|
239
|
+
const storeData = await prisma.pluginDataStore.findMany({
|
|
240
|
+
where: {
|
|
241
|
+
botId,
|
|
242
|
+
pluginName
|
|
243
|
+
},
|
|
244
|
+
select: {
|
|
245
|
+
key: true,
|
|
246
|
+
value: true,
|
|
247
|
+
createdAt: true,
|
|
248
|
+
updatedAt: true
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
const result = {};
|
|
253
|
+
storeData.forEach(item => {
|
|
254
|
+
try {
|
|
255
|
+
result[item.key] = JSON.parse(item.value);
|
|
256
|
+
} catch (e) {
|
|
257
|
+
result[item.key] = item.value;
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
res.json(result);
|
|
262
|
+
} catch (error) {
|
|
263
|
+
console.error(`[API Error] GET /plugins/bot/:botId/:pluginName/store:`, error);
|
|
264
|
+
res.status(500).json({ error: 'Не удалось получить данные store плагина.' });
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
router.get('/bot/:botId/:pluginName/store/:key', authenticateUniversal, authorize('plugin:list'), async (req, res) => {
|
|
269
|
+
try {
|
|
270
|
+
const botId = parseInt(req.params.botId);
|
|
271
|
+
const pluginName = req.params.pluginName;
|
|
272
|
+
const key = req.params.key;
|
|
273
|
+
|
|
274
|
+
const storeItem = await prisma.pluginDataStore.findUnique({
|
|
275
|
+
where: {
|
|
276
|
+
pluginName_botId_key: {
|
|
277
|
+
pluginName,
|
|
278
|
+
botId,
|
|
279
|
+
key
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
select: {
|
|
283
|
+
value: true,
|
|
284
|
+
createdAt: true,
|
|
285
|
+
updatedAt: true
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
if (!storeItem) {
|
|
290
|
+
return res.status(404).json({ error: 'Ключ не найден в store.' });
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
let parsedValue;
|
|
294
|
+
try {
|
|
295
|
+
parsedValue = JSON.parse(storeItem.value);
|
|
296
|
+
} catch (e) {
|
|
297
|
+
parsedValue = storeItem.value;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
res.json({
|
|
301
|
+
key,
|
|
302
|
+
value: parsedValue,
|
|
303
|
+
createdAt: storeItem.createdAt,
|
|
304
|
+
updatedAt: storeItem.updatedAt
|
|
305
|
+
});
|
|
306
|
+
} catch (error) {
|
|
307
|
+
console.error(`[API Error] GET /plugins/bot/:botId/:pluginName/store/:key:`, error);
|
|
308
|
+
res.status(500).json({ error: 'Не удалось получить значение из store.' });
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
router.put('/bot/:botId/:pluginName/store/:key', authenticateUniversal, authorize('plugin:settings:edit'), async (req, res) => {
|
|
313
|
+
try {
|
|
314
|
+
const botId = parseInt(req.params.botId);
|
|
315
|
+
const pluginName = req.params.pluginName;
|
|
316
|
+
const key = req.params.key;
|
|
317
|
+
const { value } = req.body;
|
|
318
|
+
|
|
319
|
+
const stringValue = typeof value === 'string' ? value : JSON.stringify(value);
|
|
320
|
+
|
|
321
|
+
const storeItem = await prisma.pluginDataStore.upsert({
|
|
322
|
+
where: {
|
|
323
|
+
pluginName_botId_key: {
|
|
324
|
+
pluginName,
|
|
325
|
+
botId,
|
|
326
|
+
key
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
update: {
|
|
330
|
+
value: stringValue
|
|
331
|
+
},
|
|
332
|
+
create: {
|
|
333
|
+
pluginName,
|
|
334
|
+
botId,
|
|
335
|
+
key,
|
|
336
|
+
value: stringValue
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
res.json({
|
|
341
|
+
key,
|
|
342
|
+
value: value,
|
|
343
|
+
updatedAt: storeItem.updatedAt
|
|
344
|
+
});
|
|
345
|
+
} catch (error) {
|
|
346
|
+
console.error(`[API Error] PUT /plugins/bot/:botId/:pluginName/store/:key:`, error);
|
|
347
|
+
res.status(500).json({ error: 'Не удалось сохранить значение в store.' });
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
router.delete('/bot/:botId/:pluginName/store/:key', authenticateUniversal, authorize('plugin:settings:edit'), async (req, res) => {
|
|
352
|
+
try {
|
|
353
|
+
const botId = parseInt(req.params.botId);
|
|
354
|
+
const pluginName = req.params.pluginName;
|
|
355
|
+
const key = req.params.key;
|
|
356
|
+
|
|
357
|
+
await prisma.pluginDataStore.delete({
|
|
358
|
+
where: {
|
|
359
|
+
pluginName_botId_key: {
|
|
360
|
+
pluginName,
|
|
361
|
+
botId,
|
|
362
|
+
key
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
res.json({ message: 'Значение удалено из store.' });
|
|
368
|
+
} catch (error) {
|
|
369
|
+
if (error.code === 'P2025') {
|
|
370
|
+
return res.status(404).json({ error: 'Ключ не найден в store.' });
|
|
371
|
+
}
|
|
372
|
+
console.error(`[API Error] DELETE /plugins/bot/:botId/:pluginName/store/:key:`, error);
|
|
373
|
+
res.status(500).json({ error: 'Не удалось удалить значение из store.' });
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
|
|
220
377
|
module.exports = router;
|