archicore 0.1.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/README.md +530 -0
- package/dist/analyzers/dead-code.d.ts +95 -0
- package/dist/analyzers/dead-code.js +327 -0
- package/dist/analyzers/duplication.d.ts +90 -0
- package/dist/analyzers/duplication.js +344 -0
- package/dist/analyzers/security.d.ts +79 -0
- package/dist/analyzers/security.js +484 -0
- package/dist/architecture/index.d.ts +35 -0
- package/dist/architecture/index.js +249 -0
- package/dist/cli/commands/analyzers.d.ts +6 -0
- package/dist/cli/commands/analyzers.js +431 -0
- package/dist/cli/commands/export.d.ts +6 -0
- package/dist/cli/commands/export.js +78 -0
- package/dist/cli/commands/index.d.ts +8 -0
- package/dist/cli/commands/index.js +8 -0
- package/dist/cli/commands/init.d.ts +26 -0
- package/dist/cli/commands/init.js +140 -0
- package/dist/cli/commands/interactive.d.ts +7 -0
- package/dist/cli/commands/interactive.js +522 -0
- package/dist/cli/commands/projects.d.ts +6 -0
- package/dist/cli/commands/projects.js +249 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.js +7 -0
- package/dist/cli/ui/box.d.ts +17 -0
- package/dist/cli/ui/box.js +62 -0
- package/dist/cli/ui/colors.d.ts +49 -0
- package/dist/cli/ui/colors.js +86 -0
- package/dist/cli/ui/index.d.ts +9 -0
- package/dist/cli/ui/index.js +9 -0
- package/dist/cli/ui/prompt.d.ts +34 -0
- package/dist/cli/ui/prompt.js +122 -0
- package/dist/cli/ui/spinner.d.ts +29 -0
- package/dist/cli/ui/spinner.js +80 -0
- package/dist/cli/ui/table.d.ts +33 -0
- package/dist/cli/ui/table.js +84 -0
- package/dist/cli/utils/config.d.ts +23 -0
- package/dist/cli/utils/config.js +73 -0
- package/dist/cli/utils/index.d.ts +6 -0
- package/dist/cli/utils/index.js +6 -0
- package/dist/cli/utils/session.d.ts +27 -0
- package/dist/cli/utils/session.js +117 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.js +295 -0
- package/dist/code-index/ast-parser.d.ts +16 -0
- package/dist/code-index/ast-parser.js +330 -0
- package/dist/code-index/dependency-graph.d.ts +16 -0
- package/dist/code-index/dependency-graph.js +161 -0
- package/dist/code-index/index.d.ts +44 -0
- package/dist/code-index/index.js +124 -0
- package/dist/code-index/symbol-extractor.d.ts +13 -0
- package/dist/code-index/symbol-extractor.js +150 -0
- package/dist/export/index.d.ts +92 -0
- package/dist/export/index.js +676 -0
- package/dist/github/github-service.d.ts +146 -0
- package/dist/github/github-service.js +609 -0
- package/dist/impact-engine/index.d.ts +25 -0
- package/dist/impact-engine/index.js +284 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.js +149 -0
- package/dist/metrics/index.d.ts +136 -0
- package/dist/metrics/index.js +525 -0
- package/dist/orchestrator/deepseek-optimizer.d.ts +67 -0
- package/dist/orchestrator/deepseek-optimizer.js +320 -0
- package/dist/orchestrator/index.d.ts +34 -0
- package/dist/orchestrator/index.js +305 -0
- package/dist/pr-guardian/index.d.ts +143 -0
- package/dist/pr-guardian/index.js +553 -0
- package/dist/refactoring/index.d.ts +108 -0
- package/dist/refactoring/index.js +580 -0
- package/dist/rules-engine/index.d.ts +129 -0
- package/dist/rules-engine/index.js +482 -0
- package/dist/semantic-memory/embedding-service.d.ts +24 -0
- package/dist/semantic-memory/embedding-service.js +120 -0
- package/dist/semantic-memory/index.d.ts +45 -0
- package/dist/semantic-memory/index.js +206 -0
- package/dist/semantic-memory/vector-store.d.ts +27 -0
- package/dist/semantic-memory/vector-store.js +166 -0
- package/dist/server/index.d.ts +28 -0
- package/dist/server/index.js +141 -0
- package/dist/server/middleware/api-auth.d.ts +43 -0
- package/dist/server/middleware/api-auth.js +256 -0
- package/dist/server/routes/admin.d.ts +5 -0
- package/dist/server/routes/admin.js +123 -0
- package/dist/server/routes/api.d.ts +7 -0
- package/dist/server/routes/api.js +362 -0
- package/dist/server/routes/auth.d.ts +16 -0
- package/dist/server/routes/auth.js +191 -0
- package/dist/server/routes/developer.d.ts +8 -0
- package/dist/server/routes/developer.js +439 -0
- package/dist/server/routes/github.d.ts +7 -0
- package/dist/server/routes/github.js +495 -0
- package/dist/server/routes/upload.d.ts +7 -0
- package/dist/server/routes/upload.js +196 -0
- package/dist/server/services/api-key-service.d.ts +81 -0
- package/dist/server/services/api-key-service.js +281 -0
- package/dist/server/services/auth-service.d.ts +40 -0
- package/dist/server/services/auth-service.js +315 -0
- package/dist/server/services/project-service.d.ts +123 -0
- package/dist/server/services/project-service.js +533 -0
- package/dist/server/services/token-service.d.ts +107 -0
- package/dist/server/services/token-service.js +416 -0
- package/dist/server/services/upload-service.d.ts +93 -0
- package/dist/server/services/upload-service.js +464 -0
- package/dist/types/api.d.ts +188 -0
- package/dist/types/api.js +86 -0
- package/dist/types/github.d.ts +335 -0
- package/dist/types/github.js +5 -0
- package/dist/types/index.d.ts +265 -0
- package/dist/types/index.js +32 -0
- package/dist/types/user.d.ts +69 -0
- package/dist/types/user.js +42 -0
- package/dist/utils/file-utils.d.ts +20 -0
- package/dist/utils/file-utils.js +163 -0
- package/dist/utils/logger.d.ts +17 -0
- package/dist/utils/logger.js +41 -0
- package/dist/watcher/index.d.ts +125 -0
- package/dist/watcher/index.js +397 -0
- package/package.json +71 -0
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ArchiCore API Routes
|
|
3
|
+
*
|
|
4
|
+
* REST API для Architecture Digital Twin
|
|
5
|
+
*/
|
|
6
|
+
import { Router } from 'express';
|
|
7
|
+
import { ProjectService } from '../services/project-service.js';
|
|
8
|
+
import { Logger } from '../../utils/logger.js';
|
|
9
|
+
import { ExportManager } from '../../export/index.js';
|
|
10
|
+
export const apiRouter = Router();
|
|
11
|
+
// Singleton сервиса проектов
|
|
12
|
+
const projectService = new ProjectService();
|
|
13
|
+
/**
|
|
14
|
+
* GET /api/projects
|
|
15
|
+
* Получить список проектов
|
|
16
|
+
*/
|
|
17
|
+
apiRouter.get('/projects', async (_req, res) => {
|
|
18
|
+
try {
|
|
19
|
+
const projects = await projectService.listProjects();
|
|
20
|
+
res.json({ projects });
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
Logger.error('Failed to list projects:', error);
|
|
24
|
+
res.status(500).json({ error: 'Failed to list projects' });
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* POST /api/projects
|
|
29
|
+
* Создать/подключить новый проект
|
|
30
|
+
*/
|
|
31
|
+
apiRouter.post('/projects', async (req, res) => {
|
|
32
|
+
try {
|
|
33
|
+
const { name, path: projectPath } = req.body;
|
|
34
|
+
if (!name || !projectPath) {
|
|
35
|
+
res.status(400).json({ error: 'Name and path are required' });
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const project = await projectService.createProject(name, projectPath);
|
|
39
|
+
res.json({ project });
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
Logger.error('Failed to create project:', error);
|
|
43
|
+
res.status(500).json({ error: 'Failed to create project' });
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
/**
|
|
47
|
+
* GET /api/projects/:id
|
|
48
|
+
* Получить информацию о проекте
|
|
49
|
+
*/
|
|
50
|
+
apiRouter.get('/projects/:id', async (req, res) => {
|
|
51
|
+
try {
|
|
52
|
+
const { id } = req.params;
|
|
53
|
+
const project = await projectService.getProject(id);
|
|
54
|
+
if (!project) {
|
|
55
|
+
res.status(404).json({ error: 'Project not found' });
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
res.json({ project });
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
Logger.error('Failed to get project:', error);
|
|
62
|
+
res.status(500).json({ error: 'Failed to get project' });
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
/**
|
|
66
|
+
* POST /api/projects/:id/index
|
|
67
|
+
* Запустить индексацию проекта
|
|
68
|
+
*/
|
|
69
|
+
apiRouter.post('/projects/:id/index', async (req, res) => {
|
|
70
|
+
try {
|
|
71
|
+
const { id } = req.params;
|
|
72
|
+
const result = await projectService.indexProject(id);
|
|
73
|
+
res.json(result);
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
Logger.error('Failed to index project:', error);
|
|
77
|
+
res.status(500).json({ error: 'Failed to index project' });
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
/**
|
|
81
|
+
* GET /api/projects/:id/architecture
|
|
82
|
+
* Получить архитектурную модель (Digital Twin)
|
|
83
|
+
*/
|
|
84
|
+
apiRouter.get('/projects/:id/architecture', async (req, res) => {
|
|
85
|
+
try {
|
|
86
|
+
const { id } = req.params;
|
|
87
|
+
const architecture = await projectService.getArchitecture(id);
|
|
88
|
+
res.json(architecture);
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
Logger.error('Failed to get architecture:', error);
|
|
92
|
+
res.status(500).json({ error: 'Failed to get architecture' });
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
/**
|
|
96
|
+
* GET /api/projects/:id/graph
|
|
97
|
+
* Получить граф зависимостей для визуализации
|
|
98
|
+
*/
|
|
99
|
+
apiRouter.get('/projects/:id/graph', async (req, res) => {
|
|
100
|
+
try {
|
|
101
|
+
const { id } = req.params;
|
|
102
|
+
const graph = await projectService.getDependencyGraph(id);
|
|
103
|
+
res.json(graph);
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
Logger.error('Failed to get dependency graph:', error);
|
|
107
|
+
res.status(500).json({ error: 'Failed to get dependency graph' });
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
/**
|
|
111
|
+
* POST /api/projects/:id/analyze
|
|
112
|
+
* Анализ влияния изменений
|
|
113
|
+
*/
|
|
114
|
+
apiRouter.post('/projects/:id/analyze', async (req, res) => {
|
|
115
|
+
try {
|
|
116
|
+
const { id } = req.params;
|
|
117
|
+
const { description, files, symbols, type } = req.body;
|
|
118
|
+
if (!description) {
|
|
119
|
+
res.status(400).json({ error: 'Description is required' });
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const impact = await projectService.analyzeImpact(id, {
|
|
123
|
+
description,
|
|
124
|
+
files: files || [],
|
|
125
|
+
symbols: symbols || [],
|
|
126
|
+
type: type || 'modify'
|
|
127
|
+
});
|
|
128
|
+
res.json(impact);
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
Logger.error('Failed to analyze impact:', error);
|
|
132
|
+
res.status(500).json({ error: 'Failed to analyze impact' });
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
/**
|
|
136
|
+
* POST /api/projects/:id/simulate
|
|
137
|
+
* Симуляция изменения (что будет если...)
|
|
138
|
+
*/
|
|
139
|
+
apiRouter.post('/projects/:id/simulate', async (req, res) => {
|
|
140
|
+
try {
|
|
141
|
+
const { id } = req.params;
|
|
142
|
+
const { change } = req.body;
|
|
143
|
+
if (!change) {
|
|
144
|
+
res.status(400).json({ error: 'Change description is required' });
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const simulation = await projectService.simulateChange(id, change);
|
|
148
|
+
res.json(simulation);
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
Logger.error('Failed to simulate change:', error);
|
|
152
|
+
res.status(500).json({ error: 'Failed to simulate change' });
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
/**
|
|
156
|
+
* POST /api/projects/:id/search
|
|
157
|
+
* Семантический поиск по коду
|
|
158
|
+
*/
|
|
159
|
+
apiRouter.post('/projects/:id/search', async (req, res) => {
|
|
160
|
+
try {
|
|
161
|
+
const { id } = req.params;
|
|
162
|
+
const { query, limit = 10 } = req.body;
|
|
163
|
+
if (!query) {
|
|
164
|
+
res.status(400).json({ error: 'Query is required' });
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const results = await projectService.semanticSearch(id, query, limit);
|
|
168
|
+
res.json({ results });
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
Logger.error('Failed to search:', error);
|
|
172
|
+
res.status(500).json({ error: 'Failed to search' });
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
/**
|
|
176
|
+
* POST /api/projects/:id/ask
|
|
177
|
+
* Задать вопрос AI-архитектору
|
|
178
|
+
*/
|
|
179
|
+
apiRouter.post('/projects/:id/ask', async (req, res) => {
|
|
180
|
+
try {
|
|
181
|
+
const { id } = req.params;
|
|
182
|
+
const { question, language } = req.body;
|
|
183
|
+
if (!question) {
|
|
184
|
+
res.status(400).json({ error: 'Question is required' });
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const answer = await projectService.askArchitect(id, question, language || 'en');
|
|
188
|
+
res.json({ answer });
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
Logger.error('Failed to ask architect:', error);
|
|
192
|
+
res.status(500).json({ error: 'Failed to ask architect' });
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
/**
|
|
196
|
+
* GET /api/projects/:id/stats
|
|
197
|
+
* Получить статистику проекта
|
|
198
|
+
*/
|
|
199
|
+
apiRouter.get('/projects/:id/stats', async (req, res) => {
|
|
200
|
+
try {
|
|
201
|
+
const { id } = req.params;
|
|
202
|
+
const stats = await projectService.getStatistics(id);
|
|
203
|
+
res.json(stats);
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
Logger.error('Failed to get stats:', error);
|
|
207
|
+
res.status(500).json({ error: 'Failed to get statistics' });
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
/**
|
|
211
|
+
* DELETE /api/projects/:id
|
|
212
|
+
* Удалить проект
|
|
213
|
+
*/
|
|
214
|
+
apiRouter.delete('/projects/:id', async (req, res) => {
|
|
215
|
+
try {
|
|
216
|
+
const { id } = req.params;
|
|
217
|
+
await projectService.deleteProject(id);
|
|
218
|
+
res.json({ success: true });
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
Logger.error('Failed to delete project:', error);
|
|
222
|
+
res.status(500).json({ error: 'Failed to delete project' });
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
/**
|
|
226
|
+
* GET /api/projects/:id/metrics
|
|
227
|
+
* Получить метрики кода
|
|
228
|
+
*/
|
|
229
|
+
apiRouter.get('/projects/:id/metrics', async (req, res) => {
|
|
230
|
+
try {
|
|
231
|
+
const { id } = req.params;
|
|
232
|
+
const metrics = await projectService.getMetrics(id);
|
|
233
|
+
res.json(metrics);
|
|
234
|
+
}
|
|
235
|
+
catch (error) {
|
|
236
|
+
Logger.error('Failed to get metrics:', error);
|
|
237
|
+
res.status(500).json({ error: 'Failed to get metrics' });
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
/**
|
|
241
|
+
* GET /api/projects/:id/rules
|
|
242
|
+
* Проверить правила архитектуры
|
|
243
|
+
*/
|
|
244
|
+
apiRouter.get('/projects/:id/rules', async (req, res) => {
|
|
245
|
+
try {
|
|
246
|
+
const { id } = req.params;
|
|
247
|
+
const result = await projectService.checkRules(id);
|
|
248
|
+
res.json(result);
|
|
249
|
+
}
|
|
250
|
+
catch (error) {
|
|
251
|
+
Logger.error('Failed to check rules:', error);
|
|
252
|
+
res.status(500).json({ error: 'Failed to check rules' });
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
/**
|
|
256
|
+
* GET /api/projects/:id/dead-code
|
|
257
|
+
* Найти мёртвый код
|
|
258
|
+
*/
|
|
259
|
+
apiRouter.get('/projects/:id/dead-code', async (req, res) => {
|
|
260
|
+
try {
|
|
261
|
+
const { id } = req.params;
|
|
262
|
+
const result = await projectService.findDeadCode(id);
|
|
263
|
+
res.json(result);
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
Logger.error('Failed to find dead code:', error);
|
|
267
|
+
res.status(500).json({ error: 'Failed to find dead code' });
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
/**
|
|
271
|
+
* GET /api/projects/:id/duplication
|
|
272
|
+
* Найти дублирование кода
|
|
273
|
+
*/
|
|
274
|
+
apiRouter.get('/projects/:id/duplication', async (req, res) => {
|
|
275
|
+
try {
|
|
276
|
+
const { id } = req.params;
|
|
277
|
+
const result = await projectService.findDuplication(id);
|
|
278
|
+
res.json(result);
|
|
279
|
+
}
|
|
280
|
+
catch (error) {
|
|
281
|
+
Logger.error('Failed to find duplication:', error);
|
|
282
|
+
res.status(500).json({ error: 'Failed to find duplication' });
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
/**
|
|
286
|
+
* GET /api/projects/:id/security
|
|
287
|
+
* Анализ безопасности
|
|
288
|
+
*/
|
|
289
|
+
apiRouter.get('/projects/:id/security', async (req, res) => {
|
|
290
|
+
try {
|
|
291
|
+
const { id } = req.params;
|
|
292
|
+
const result = await projectService.analyzeSecurity(id);
|
|
293
|
+
res.json(result);
|
|
294
|
+
}
|
|
295
|
+
catch (error) {
|
|
296
|
+
Logger.error('Failed to analyze security:', error);
|
|
297
|
+
res.status(500).json({ error: 'Failed to analyze security' });
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
/**
|
|
301
|
+
* GET /api/projects/:id/refactoring
|
|
302
|
+
* Получить предложения по рефакторингу
|
|
303
|
+
*/
|
|
304
|
+
apiRouter.get('/projects/:id/refactoring', async (req, res) => {
|
|
305
|
+
try {
|
|
306
|
+
const { id } = req.params;
|
|
307
|
+
const result = await projectService.getRefactoringSuggestions(id);
|
|
308
|
+
res.json(result);
|
|
309
|
+
}
|
|
310
|
+
catch (error) {
|
|
311
|
+
Logger.error('Failed to get refactoring suggestions:', error);
|
|
312
|
+
res.status(500).json({ error: 'Failed to get refactoring suggestions' });
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
/**
|
|
316
|
+
* POST /api/projects/:id/export
|
|
317
|
+
* Экспорт данных проекта
|
|
318
|
+
*/
|
|
319
|
+
apiRouter.post('/projects/:id/export', async (req, res) => {
|
|
320
|
+
try {
|
|
321
|
+
const { id } = req.params;
|
|
322
|
+
const options = req.body;
|
|
323
|
+
if (!options.format) {
|
|
324
|
+
res.status(400).json({ error: 'Format is required' });
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
const exportData = await projectService.getExportData(id);
|
|
328
|
+
const exportManager = new ExportManager();
|
|
329
|
+
const result = await exportManager.export(exportData, options);
|
|
330
|
+
// Устанавливаем правильный content-type
|
|
331
|
+
const contentTypes = {
|
|
332
|
+
json: 'application/json',
|
|
333
|
+
html: 'text/html',
|
|
334
|
+
markdown: 'text/markdown',
|
|
335
|
+
csv: 'text/csv',
|
|
336
|
+
graphml: 'application/xml'
|
|
337
|
+
};
|
|
338
|
+
res.setHeader('Content-Type', contentTypes[options.format] || 'text/plain');
|
|
339
|
+
res.setHeader('Content-Disposition', `attachment; filename="archicore-export.${options.format === 'markdown' ? 'md' : options.format}"`);
|
|
340
|
+
res.send(result);
|
|
341
|
+
}
|
|
342
|
+
catch (error) {
|
|
343
|
+
Logger.error('Failed to export:', error);
|
|
344
|
+
res.status(500).json({ error: 'Failed to export' });
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
/**
|
|
348
|
+
* POST /api/projects/:id/full-analysis
|
|
349
|
+
* Полный анализ проекта (все анализаторы)
|
|
350
|
+
*/
|
|
351
|
+
apiRouter.post('/projects/:id/full-analysis', async (req, res) => {
|
|
352
|
+
try {
|
|
353
|
+
const { id } = req.params;
|
|
354
|
+
const result = await projectService.runFullAnalysis(id);
|
|
355
|
+
res.json(result);
|
|
356
|
+
}
|
|
357
|
+
catch (error) {
|
|
358
|
+
Logger.error('Failed to run full analysis:', error);
|
|
359
|
+
res.status(500).json({ error: 'Failed to run full analysis' });
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication API Routes for ArchiCore
|
|
3
|
+
*/
|
|
4
|
+
import { Request, Response, NextFunction } from 'express';
|
|
5
|
+
import { User } from '../../types/user.js';
|
|
6
|
+
export declare const authRouter: import("express-serve-static-core").Router;
|
|
7
|
+
declare global {
|
|
8
|
+
namespace Express {
|
|
9
|
+
interface Request {
|
|
10
|
+
user?: User;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export declare function authMiddleware(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
15
|
+
export declare function adminMiddleware(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
16
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication API Routes for ArchiCore
|
|
3
|
+
*/
|
|
4
|
+
import { Router } from 'express';
|
|
5
|
+
import { AuthService } from '../services/auth-service.js';
|
|
6
|
+
import { Logger } from '../../utils/logger.js';
|
|
7
|
+
export const authRouter = Router();
|
|
8
|
+
const authService = new AuthService();
|
|
9
|
+
// Middleware to check authentication
|
|
10
|
+
export async function authMiddleware(req, res, next) {
|
|
11
|
+
const authHeader = req.headers.authorization;
|
|
12
|
+
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
13
|
+
res.status(401).json({ error: 'No token provided' });
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const token = authHeader.substring(7);
|
|
17
|
+
const user = await authService.validateToken(token);
|
|
18
|
+
if (!user) {
|
|
19
|
+
res.status(401).json({ error: 'Invalid or expired token' });
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
req.user = user;
|
|
23
|
+
next();
|
|
24
|
+
}
|
|
25
|
+
// Middleware to check admin role
|
|
26
|
+
export async function adminMiddleware(req, res, next) {
|
|
27
|
+
if (!req.user || req.user.tier !== 'admin') {
|
|
28
|
+
res.status(403).json({ error: 'Admin access required' });
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
next();
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* POST /api/auth/register
|
|
35
|
+
* Register new user
|
|
36
|
+
*/
|
|
37
|
+
authRouter.post('/register', async (req, res) => {
|
|
38
|
+
try {
|
|
39
|
+
const { email, username, password } = req.body;
|
|
40
|
+
if (!email || !username || !password) {
|
|
41
|
+
res.status(400).json({ success: false, error: 'Email, username, and password are required' });
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (password.length < 8) {
|
|
45
|
+
res.status(400).json({ success: false, error: 'Password must be at least 8 characters' });
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const result = await authService.register(email, username, password);
|
|
49
|
+
res.json(result);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
Logger.error('Registration error:', error);
|
|
53
|
+
res.status(500).json({ success: false, error: 'Registration failed' });
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
/**
|
|
57
|
+
* POST /api/auth/login
|
|
58
|
+
* Login with email/password
|
|
59
|
+
*/
|
|
60
|
+
authRouter.post('/login', async (req, res) => {
|
|
61
|
+
try {
|
|
62
|
+
const { email, password } = req.body;
|
|
63
|
+
if (!email || !password) {
|
|
64
|
+
res.status(400).json({ success: false, error: 'Email and password are required' });
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const result = await authService.login(email, password);
|
|
68
|
+
res.json(result);
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
Logger.error('Login error:', error);
|
|
72
|
+
res.status(500).json({ success: false, error: 'Login failed' });
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
/**
|
|
76
|
+
* POST /api/auth/logout
|
|
77
|
+
* Logout current user
|
|
78
|
+
*/
|
|
79
|
+
authRouter.post('/logout', authMiddleware, async (req, res) => {
|
|
80
|
+
try {
|
|
81
|
+
const token = req.headers.authorization?.substring(7);
|
|
82
|
+
if (token) {
|
|
83
|
+
await authService.logout(token);
|
|
84
|
+
}
|
|
85
|
+
res.json({ success: true });
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
Logger.error('Logout error:', error);
|
|
89
|
+
res.status(500).json({ success: false, error: 'Logout failed' });
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
/**
|
|
93
|
+
* GET /api/auth/me
|
|
94
|
+
* Get current user info
|
|
95
|
+
*/
|
|
96
|
+
authRouter.get('/me', authMiddleware, async (req, res) => {
|
|
97
|
+
try {
|
|
98
|
+
if (!req.user) {
|
|
99
|
+
res.status(401).json({ error: 'Not authenticated' });
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
// Remove sensitive data
|
|
103
|
+
const { passwordHash, ...user } = req.user;
|
|
104
|
+
res.json({ user });
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
Logger.error('Get user error:', error);
|
|
108
|
+
res.status(500).json({ error: 'Failed to get user info' });
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
/**
|
|
112
|
+
* PUT /api/auth/me
|
|
113
|
+
* Update current user profile
|
|
114
|
+
*/
|
|
115
|
+
authRouter.put('/me', authMiddleware, async (req, res) => {
|
|
116
|
+
try {
|
|
117
|
+
const { username, email, avatar } = req.body;
|
|
118
|
+
if (!req.user) {
|
|
119
|
+
res.status(401).json({ error: 'Not authenticated' });
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const updated = await authService.updateUser(req.user.id, { username, email, avatar });
|
|
123
|
+
if (!updated) {
|
|
124
|
+
res.status(400).json({ error: 'Failed to update profile' });
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const user = await authService.getUser(req.user.id);
|
|
128
|
+
if (user) {
|
|
129
|
+
const { passwordHash, ...sanitized } = user;
|
|
130
|
+
res.json({ success: true, user: sanitized });
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
res.status(404).json({ error: 'User not found' });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
Logger.error('Update user error:', error);
|
|
138
|
+
res.status(500).json({ error: 'Failed to update profile' });
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
/**
|
|
142
|
+
* POST /api/auth/oauth/:provider
|
|
143
|
+
* OAuth login (GitHub, Google)
|
|
144
|
+
*/
|
|
145
|
+
authRouter.post('/oauth/:provider', async (req, res) => {
|
|
146
|
+
try {
|
|
147
|
+
const { provider } = req.params;
|
|
148
|
+
const { profile } = req.body;
|
|
149
|
+
if (provider !== 'github' && provider !== 'google') {
|
|
150
|
+
res.status(400).json({ success: false, error: 'Invalid provider' });
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (!profile || !profile.id || !profile.email) {
|
|
154
|
+
res.status(400).json({ success: false, error: 'Invalid profile data' });
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const result = await authService.oauthLogin(provider, profile);
|
|
158
|
+
res.json(result);
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
Logger.error('OAuth error:', error);
|
|
162
|
+
res.status(500).json({ success: false, error: 'OAuth login failed' });
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
/**
|
|
166
|
+
* GET /api/auth/usage
|
|
167
|
+
* Get current user's usage stats
|
|
168
|
+
*/
|
|
169
|
+
authRouter.get('/usage', authMiddleware, async (req, res) => {
|
|
170
|
+
try {
|
|
171
|
+
if (!req.user) {
|
|
172
|
+
res.status(401).json({ error: 'Not authenticated' });
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const user = await authService.getUser(req.user.id);
|
|
176
|
+
if (!user) {
|
|
177
|
+
res.status(404).json({ error: 'User not found' });
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
res.json({
|
|
181
|
+
tier: user.tier,
|
|
182
|
+
usage: user.usage,
|
|
183
|
+
subscription: user.subscription
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
Logger.error('Get usage error:', error);
|
|
188
|
+
res.status(500).json({ error: 'Failed to get usage' });
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Developer API Routes for ArchiCore
|
|
3
|
+
*
|
|
4
|
+
* REST API для разработчиков с токенизированной тарификацией
|
|
5
|
+
* Формат ответов совместим с OpenAI/Anthropic API
|
|
6
|
+
*/
|
|
7
|
+
export declare const developerRouter: import("express-serve-static-core").Router;
|
|
8
|
+
//# sourceMappingURL=developer.d.ts.map
|