blockmine 1.23.0 → 1.23.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.
Files changed (29) hide show
  1. package/.claude/agents/code-architect.md +34 -0
  2. package/.claude/agents/code-explorer.md +51 -0
  3. package/.claude/agents/code-reviewer.md +46 -0
  4. package/.claude/commands/feature-dev.md +125 -0
  5. package/.claude/settings.json +1 -1
  6. package/.claude/settings.local.json +3 -1
  7. package/.claude/skills/frontend-design/SKILL.md +42 -0
  8. package/CHANGELOG.md +31 -16
  9. package/backend/prisma/migrations/20251116111851_add_execution_trace/migration.sql +22 -22
  10. package/backend/prisma/migrations/20251120154914_add_panel_api_keys/migration.sql +21 -21
  11. package/backend/prisma/migrations/20251121110241_add_proxy_table/migration.sql +45 -45
  12. package/backend/prisma/migrations/migration_lock.toml +2 -2
  13. package/backend/src/api/routes/auth.js +669 -669
  14. package/backend/src/api/routes/bots.js +2451 -2451
  15. package/backend/src/api/routes/panel.js +66 -66
  16. package/backend/src/api/routes/panelApiKeys.js +179 -179
  17. package/backend/src/api/routes/plugins.js +376 -376
  18. package/backend/src/api/routes/system.js +174 -174
  19. package/backend/src/core/EventGraphManager.js +194 -194
  20. package/backend/src/core/GraphExecutionEngine.js +28 -1
  21. package/backend/src/core/node-registries/actions.js +2 -2
  22. package/backend/src/core/nodes/actions/http_request.js +23 -4
  23. package/backend/src/core/nodes/actions/send_message.js +2 -12
  24. package/backend/src/core/nodes/data/string_literal.js +2 -13
  25. package/backend/src/core/services/BotLifecycleService.js +835 -835
  26. package/frontend/dist/assets/{index-B1serztM.js → index-DqzDkFsP.js} +185 -185
  27. package/frontend/dist/index.html +1 -1
  28. package/package.json +2 -1
  29. package/CLAUDE.md +0 -284
@@ -1,67 +1,67 @@
1
- const express = require('express');
2
- const fs = require('fs/promises');
3
- const path = require('path');
4
- const os = require('os');
5
- const { authenticate, authenticateUniversal, authorize } = require('../middleware/auth');
6
- const config = require('../../config');
7
-
8
- const router = express.Router();
9
-
10
- const DATA_DIR = path.join(os.homedir(), '.blockmine');
11
- const CONFIG_PATH = path.join(DATA_DIR, 'config.json');
12
-
13
- /**
14
- * @route GET /api/panel/settings
15
- * @desc Получить текущие глобальные настройки
16
- * @access Private (Admin only)
17
- */
18
- router.get('/settings', authenticateUniversal, authorize('panel:settings:view'), (req, res) => {
19
- const { server, telemetry } = config;
20
- res.json({
21
- server: {
22
- allowExternalAccess: server.allowExternalAccess
23
- },
24
- telemetry: {
25
- enabled: telemetry?.enabled ?? true
26
- }
27
- });
28
- });
29
-
30
- /**
31
- * @route PUT /api/panel/settings
32
- * @desc Обновить глобальные настройки
33
- * @access Private (Admin only)
34
- */
35
- router.put('/settings', authenticateUniversal, authorize('panel:settings:edit'), async (req, res) => {
36
- const { allowExternalAccess, telemetryEnabled } = req.body;
37
-
38
- try {
39
- const currentConfig = JSON.parse(await fs.readFile(CONFIG_PATH, 'utf-8'));
40
-
41
- if (typeof allowExternalAccess === 'boolean') {
42
- currentConfig.server.allowExternalAccess = allowExternalAccess;
43
- currentConfig.server.host = allowExternalAccess ? '0.0.0.0' : '127.0.0.1';
44
- console.log(`[Config Update] Внешний доступ ${allowExternalAccess ? 'ВКЛЮЧЕН' : 'ВЫКЛЮЧЕН'}. Хост изменен на ${currentConfig.server.host}`);
45
- }
46
-
47
- if (typeof telemetryEnabled === 'boolean') {
48
- if (!currentConfig.telemetry) {
49
- currentConfig.telemetry = {};
50
- }
51
- currentConfig.telemetry.enabled = telemetryEnabled;
52
- }
53
-
54
- await fs.writeFile(CONFIG_PATH, JSON.stringify(currentConfig, null, 2), 'utf-8');
55
-
56
- res.json({
57
- message: 'Настройки сохранены. Для применения требуется перезапуск панели.',
58
- requiresRestart: true
59
- });
60
-
61
- } catch (error) {
62
- console.error("Ошибка обновления файла конфигурации:", error);
63
- res.status(500).json({ error: 'Не удалось сохранить настройки.' });
64
- }
65
- });
66
-
1
+ const express = require('express');
2
+ const fs = require('fs/promises');
3
+ const path = require('path');
4
+ const os = require('os');
5
+ const { authenticate, authenticateUniversal, authorize } = require('../middleware/auth');
6
+ const config = require('../../config');
7
+
8
+ const router = express.Router();
9
+
10
+ const DATA_DIR = path.join(os.homedir(), '.blockmine');
11
+ const CONFIG_PATH = path.join(DATA_DIR, 'config.json');
12
+
13
+ /**
14
+ * @route GET /api/panel/settings
15
+ * @desc Получить текущие глобальные настройки
16
+ * @access Private (Admin only)
17
+ */
18
+ router.get('/settings', authenticateUniversal, authorize('panel:settings:view'), (req, res) => {
19
+ const { server, telemetry } = config;
20
+ res.json({
21
+ server: {
22
+ allowExternalAccess: server.allowExternalAccess
23
+ },
24
+ telemetry: {
25
+ enabled: telemetry?.enabled ?? true
26
+ }
27
+ });
28
+ });
29
+
30
+ /**
31
+ * @route PUT /api/panel/settings
32
+ * @desc Обновить глобальные настройки
33
+ * @access Private (Admin only)
34
+ */
35
+ router.put('/settings', authenticateUniversal, authorize('panel:settings:edit'), async (req, res) => {
36
+ const { allowExternalAccess, telemetryEnabled } = req.body;
37
+
38
+ try {
39
+ const currentConfig = JSON.parse(await fs.readFile(CONFIG_PATH, 'utf-8'));
40
+
41
+ if (typeof allowExternalAccess === 'boolean') {
42
+ currentConfig.server.allowExternalAccess = allowExternalAccess;
43
+ currentConfig.server.host = allowExternalAccess ? '0.0.0.0' : '127.0.0.1';
44
+ console.log(`[Config Update] Внешний доступ ${allowExternalAccess ? 'ВКЛЮЧЕН' : 'ВЫКЛЮЧЕН'}. Хост изменен на ${currentConfig.server.host}`);
45
+ }
46
+
47
+ if (typeof telemetryEnabled === 'boolean') {
48
+ if (!currentConfig.telemetry) {
49
+ currentConfig.telemetry = {};
50
+ }
51
+ currentConfig.telemetry.enabled = telemetryEnabled;
52
+ }
53
+
54
+ await fs.writeFile(CONFIG_PATH, JSON.stringify(currentConfig, null, 2), 'utf-8');
55
+
56
+ res.json({
57
+ message: 'Настройки сохранены. Для применения требуется перезапуск панели.',
58
+ requiresRestart: true
59
+ });
60
+
61
+ } catch (error) {
62
+ console.error("Ошибка обновления файла конфигурации:", error);
63
+ res.status(500).json({ error: 'Не удалось сохранить настройки.' });
64
+ }
65
+ });
66
+
67
67
  module.exports = router;
@@ -1,179 +1,179 @@
1
- const express = require('express');
2
- const router = express.Router();
3
- const bcrypt = require('bcryptjs');
4
- const crypto = require('crypto');
5
- const prisma = require('../../lib/prisma');
6
- const { authenticate, authenticateUniversal } = require('../middleware/auth');
7
-
8
- /**
9
- * Генерация случайного API ключа
10
- */
11
- function generateApiKey() {
12
- return 'pk_' + crypto.randomBytes(32).toString('hex');
13
- }
14
-
15
- /**
16
- * GET /api/panel/api-keys
17
- * Получить список API ключей пользователя
18
- */
19
- router.get('/', authenticateUniversal, async (req, res) => {
20
- try {
21
- const keys = await prisma.panelApiKey.findMany({
22
- where: {
23
- userId: req.user.userId
24
- },
25
- select: {
26
- id: true,
27
- name: true,
28
- prefix: true,
29
- customScopes: true,
30
- lastUsedAt: true,
31
- expiresAt: true,
32
- isActive: true,
33
- createdAt: true
34
- },
35
- orderBy: {
36
- createdAt: 'desc'
37
- }
38
- });
39
-
40
- res.json({
41
- success: true,
42
- keys: keys.map(key => ({
43
- ...key,
44
- customScopes: key.customScopes ? JSON.parse(key.customScopes) : null
45
- }))
46
- });
47
- } catch (error) {
48
- console.error('Ошибка при получении списка API ключей:', error);
49
- res.status(500).json({ error: 'Не удалось получить список API ключей' });
50
- }
51
- });
52
-
53
- /**
54
- * POST /api/panel/api-keys
55
- * Создать новый API ключ
56
- */
57
- router.post('/', authenticateUniversal, async (req, res) => {
58
- try {
59
- const { name, customScopes, expiresAt } = req.body;
60
-
61
- if (!name || typeof name !== 'string' || name.trim().length === 0) {
62
- return res.status(400).json({ error: 'Имя ключа обязательно' });
63
- }
64
-
65
- const apiKey = generateApiKey();
66
- const keyHash = await bcrypt.hash(apiKey, 10);
67
- const prefix = apiKey.substring(0, 10);
68
-
69
- const newKey = await prisma.panelApiKey.create({
70
- data: {
71
- userId: req.user.userId,
72
- name: name.trim(),
73
- keyHash,
74
- prefix,
75
- customScopes: customScopes ? JSON.stringify(customScopes) : null,
76
- expiresAt: expiresAt ? new Date(expiresAt) : null
77
- }
78
- });
79
-
80
- res.json({
81
- success: true,
82
- message: 'API ключ успешно создан',
83
- key: {
84
- id: newKey.id,
85
- name: newKey.name,
86
- prefix: newKey.prefix,
87
- customScopes: newKey.customScopes ? JSON.parse(newKey.customScopes) : null,
88
- expiresAt: newKey.expiresAt,
89
- createdAt: newKey.createdAt,
90
- apiKey
91
- }
92
- });
93
- } catch (error) {
94
- console.error('Ошибка при создании API ключа:', error);
95
- res.status(500).json({ error: 'Не удалось создать API ключ' });
96
- }
97
- });
98
-
99
- /**
100
- * PATCH /api/panel/api-keys/:id
101
- * Обновить API ключ (название, статус, срок действия)
102
- */
103
- router.patch('/:id', authenticateUniversal, async (req, res) => {
104
- try {
105
- const keyId = parseInt(req.params.id);
106
- const { name, isActive, expiresAt } = req.body;
107
-
108
- const existingKey = await prisma.panelApiKey.findFirst({
109
- where: {
110
- id: keyId,
111
- userId: req.user.userId
112
- }
113
- });
114
-
115
- if (!existingKey) {
116
- return res.status(404).json({ error: 'API ключ не найден' });
117
- }
118
-
119
- const updateData = {};
120
- if (name !== undefined) updateData.name = name;
121
- if (isActive !== undefined) updateData.isActive = isActive;
122
- if (expiresAt !== undefined) updateData.expiresAt = expiresAt ? new Date(expiresAt) : null;
123
-
124
- const updatedKey = await prisma.panelApiKey.update({
125
- where: { id: keyId },
126
- data: updateData
127
- });
128
-
129
- res.json({
130
- success: true,
131
- message: 'API ключ успешно обновлён',
132
- key: {
133
- id: updatedKey.id,
134
- name: updatedKey.name,
135
- prefix: updatedKey.prefix,
136
- isActive: updatedKey.isActive,
137
- expiresAt: updatedKey.expiresAt
138
- }
139
- });
140
- } catch (error) {
141
- console.error('Ошибка при обновлении API ключа:', error);
142
- res.status(500).json({ error: 'Не удалось обновить API ключ' });
143
- }
144
- });
145
-
146
- /**
147
- * DELETE /api/panel/api-keys/:id
148
- * Удалить (отозвать) API ключ
149
- */
150
- router.delete('/:id', authenticateUniversal, async (req, res) => {
151
- try {
152
- const keyId = parseInt(req.params.id);
153
-
154
- const existingKey = await prisma.panelApiKey.findFirst({
155
- where: {
156
- id: keyId,
157
- userId: req.user.userId
158
- }
159
- });
160
-
161
- if (!existingKey) {
162
- return res.status(404).json({ error: 'API ключ не найден' });
163
- }
164
-
165
- await prisma.panelApiKey.delete({
166
- where: { id: keyId }
167
- });
168
-
169
- res.json({
170
- success: true,
171
- message: 'API ключ успешно удалён'
172
- });
173
- } catch (error) {
174
- console.error('Ошибка при удалении API ключа:', error);
175
- res.status(500).json({ error: 'Не удалось удалить API ключ' });
176
- }
177
- });
178
-
179
- module.exports = router;
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const bcrypt = require('bcryptjs');
4
+ const crypto = require('crypto');
5
+ const prisma = require('../../lib/prisma');
6
+ const { authenticate, authenticateUniversal } = require('../middleware/auth');
7
+
8
+ /**
9
+ * Генерация случайного API ключа
10
+ */
11
+ function generateApiKey() {
12
+ return 'pk_' + crypto.randomBytes(32).toString('hex');
13
+ }
14
+
15
+ /**
16
+ * GET /api/panel/api-keys
17
+ * Получить список API ключей пользователя
18
+ */
19
+ router.get('/', authenticateUniversal, async (req, res) => {
20
+ try {
21
+ const keys = await prisma.panelApiKey.findMany({
22
+ where: {
23
+ userId: req.user.userId
24
+ },
25
+ select: {
26
+ id: true,
27
+ name: true,
28
+ prefix: true,
29
+ customScopes: true,
30
+ lastUsedAt: true,
31
+ expiresAt: true,
32
+ isActive: true,
33
+ createdAt: true
34
+ },
35
+ orderBy: {
36
+ createdAt: 'desc'
37
+ }
38
+ });
39
+
40
+ res.json({
41
+ success: true,
42
+ keys: keys.map(key => ({
43
+ ...key,
44
+ customScopes: key.customScopes ? JSON.parse(key.customScopes) : null
45
+ }))
46
+ });
47
+ } catch (error) {
48
+ console.error('Ошибка при получении списка API ключей:', error);
49
+ res.status(500).json({ error: 'Не удалось получить список API ключей' });
50
+ }
51
+ });
52
+
53
+ /**
54
+ * POST /api/panel/api-keys
55
+ * Создать новый API ключ
56
+ */
57
+ router.post('/', authenticateUniversal, async (req, res) => {
58
+ try {
59
+ const { name, customScopes, expiresAt } = req.body;
60
+
61
+ if (!name || typeof name !== 'string' || name.trim().length === 0) {
62
+ return res.status(400).json({ error: 'Имя ключа обязательно' });
63
+ }
64
+
65
+ const apiKey = generateApiKey();
66
+ const keyHash = await bcrypt.hash(apiKey, 10);
67
+ const prefix = apiKey.substring(0, 10);
68
+
69
+ const newKey = await prisma.panelApiKey.create({
70
+ data: {
71
+ userId: req.user.userId,
72
+ name: name.trim(),
73
+ keyHash,
74
+ prefix,
75
+ customScopes: customScopes ? JSON.stringify(customScopes) : null,
76
+ expiresAt: expiresAt ? new Date(expiresAt) : null
77
+ }
78
+ });
79
+
80
+ res.json({
81
+ success: true,
82
+ message: 'API ключ успешно создан',
83
+ key: {
84
+ id: newKey.id,
85
+ name: newKey.name,
86
+ prefix: newKey.prefix,
87
+ customScopes: newKey.customScopes ? JSON.parse(newKey.customScopes) : null,
88
+ expiresAt: newKey.expiresAt,
89
+ createdAt: newKey.createdAt,
90
+ apiKey
91
+ }
92
+ });
93
+ } catch (error) {
94
+ console.error('Ошибка при создании API ключа:', error);
95
+ res.status(500).json({ error: 'Не удалось создать API ключ' });
96
+ }
97
+ });
98
+
99
+ /**
100
+ * PATCH /api/panel/api-keys/:id
101
+ * Обновить API ключ (название, статус, срок действия)
102
+ */
103
+ router.patch('/:id', authenticateUniversal, async (req, res) => {
104
+ try {
105
+ const keyId = parseInt(req.params.id);
106
+ const { name, isActive, expiresAt } = req.body;
107
+
108
+ const existingKey = await prisma.panelApiKey.findFirst({
109
+ where: {
110
+ id: keyId,
111
+ userId: req.user.userId
112
+ }
113
+ });
114
+
115
+ if (!existingKey) {
116
+ return res.status(404).json({ error: 'API ключ не найден' });
117
+ }
118
+
119
+ const updateData = {};
120
+ if (name !== undefined) updateData.name = name;
121
+ if (isActive !== undefined) updateData.isActive = isActive;
122
+ if (expiresAt !== undefined) updateData.expiresAt = expiresAt ? new Date(expiresAt) : null;
123
+
124
+ const updatedKey = await prisma.panelApiKey.update({
125
+ where: { id: keyId },
126
+ data: updateData
127
+ });
128
+
129
+ res.json({
130
+ success: true,
131
+ message: 'API ключ успешно обновлён',
132
+ key: {
133
+ id: updatedKey.id,
134
+ name: updatedKey.name,
135
+ prefix: updatedKey.prefix,
136
+ isActive: updatedKey.isActive,
137
+ expiresAt: updatedKey.expiresAt
138
+ }
139
+ });
140
+ } catch (error) {
141
+ console.error('Ошибка при обновлении API ключа:', error);
142
+ res.status(500).json({ error: 'Не удалось обновить API ключ' });
143
+ }
144
+ });
145
+
146
+ /**
147
+ * DELETE /api/panel/api-keys/:id
148
+ * Удалить (отозвать) API ключ
149
+ */
150
+ router.delete('/:id', authenticateUniversal, async (req, res) => {
151
+ try {
152
+ const keyId = parseInt(req.params.id);
153
+
154
+ const existingKey = await prisma.panelApiKey.findFirst({
155
+ where: {
156
+ id: keyId,
157
+ userId: req.user.userId
158
+ }
159
+ });
160
+
161
+ if (!existingKey) {
162
+ return res.status(404).json({ error: 'API ключ не найден' });
163
+ }
164
+
165
+ await prisma.panelApiKey.delete({
166
+ where: { id: keyId }
167
+ });
168
+
169
+ res.json({
170
+ success: true,
171
+ message: 'API ключ успешно удалён'
172
+ });
173
+ } catch (error) {
174
+ console.error('Ошибка при удалении API ключа:', error);
175
+ res.status(500).json({ error: 'Не удалось удалить API ключ' });
176
+ }
177
+ });
178
+
179
+ module.exports = router;