archicore 0.3.1 → 0.3.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 (42) hide show
  1. package/README.md +48 -4
  2. package/dist/cli/commands/interactive.js +83 -23
  3. package/dist/cli/commands/projects.js +3 -3
  4. package/dist/cli/ui/prompt.d.ts +4 -0
  5. package/dist/cli/ui/prompt.js +22 -0
  6. package/dist/cli/utils/config.js +2 -2
  7. package/dist/cli/utils/upload-utils.js +65 -18
  8. package/dist/code-index/ast-parser.d.ts +4 -0
  9. package/dist/code-index/ast-parser.js +42 -0
  10. package/dist/code-index/index.d.ts +21 -1
  11. package/dist/code-index/index.js +45 -1
  12. package/dist/code-index/source-map-extractor.d.ts +71 -0
  13. package/dist/code-index/source-map-extractor.js +194 -0
  14. package/dist/gitlab/gitlab-service.d.ts +162 -0
  15. package/dist/gitlab/gitlab-service.js +652 -0
  16. package/dist/gitlab/index.d.ts +8 -0
  17. package/dist/gitlab/index.js +8 -0
  18. package/dist/server/config/passport.d.ts +14 -0
  19. package/dist/server/config/passport.js +86 -0
  20. package/dist/server/index.js +52 -10
  21. package/dist/server/middleware/api-auth.d.ts +2 -2
  22. package/dist/server/middleware/api-auth.js +21 -2
  23. package/dist/server/middleware/csrf.d.ts +23 -0
  24. package/dist/server/middleware/csrf.js +96 -0
  25. package/dist/server/routes/auth.d.ts +2 -2
  26. package/dist/server/routes/auth.js +204 -5
  27. package/dist/server/routes/device-auth.js +2 -2
  28. package/dist/server/routes/gitlab.d.ts +12 -0
  29. package/dist/server/routes/gitlab.js +528 -0
  30. package/dist/server/routes/oauth.d.ts +6 -0
  31. package/dist/server/routes/oauth.js +198 -0
  32. package/dist/server/services/audit-service.d.ts +1 -1
  33. package/dist/server/services/auth-service.d.ts +13 -1
  34. package/dist/server/services/auth-service.js +108 -7
  35. package/dist/server/services/email-service.d.ts +63 -0
  36. package/dist/server/services/email-service.js +586 -0
  37. package/dist/server/utils/disposable-email-domains.d.ts +14 -0
  38. package/dist/server/utils/disposable-email-domains.js +192 -0
  39. package/dist/types/api.d.ts +98 -0
  40. package/dist/types/gitlab.d.ts +245 -0
  41. package/dist/types/gitlab.js +11 -0
  42. package/package.json +1 -1
@@ -10,20 +10,64 @@
10
10
  import { ASTParser } from './ast-parser.js';
11
11
  import { SymbolExtractor } from './symbol-extractor.js';
12
12
  import { DependencyGraphBuilder } from './dependency-graph.js';
13
+ import { SourceMapExtractor } from './source-map-extractor.js';
13
14
  import { Logger } from '../utils/logger.js';
14
15
  export class CodeIndex {
15
16
  astParser;
16
17
  symbolExtractor;
17
18
  graphBuilder;
19
+ sourceMapExtractor;
18
20
  rootDir;
19
21
  asts = new Map();
20
22
  symbols = new Map();
21
23
  graph = null;
24
+ virtualFiles = [];
22
25
  constructor(rootDir) {
23
26
  this.rootDir = rootDir || process.cwd();
24
27
  this.astParser = new ASTParser();
25
28
  this.symbolExtractor = new SymbolExtractor();
26
29
  this.graphBuilder = new DependencyGraphBuilder();
30
+ this.sourceMapExtractor = new SourceMapExtractor();
31
+ }
32
+ /**
33
+ * Проверяет, является ли проект bundled (содержит source maps)
34
+ */
35
+ async isBundledProject() {
36
+ return this.sourceMapExtractor.isBundledProject(this.rootDir);
37
+ }
38
+ /**
39
+ * Извлекает исходный код из source maps (для bundled проектов)
40
+ */
41
+ async extractFromSourceMaps() {
42
+ const result = await this.sourceMapExtractor.extractFromProject(this.rootDir);
43
+ this.virtualFiles = result.files;
44
+ return result;
45
+ }
46
+ /**
47
+ * Парсит виртуальные файлы из source maps
48
+ */
49
+ parseVirtualFiles(files, progressCallback) {
50
+ const asts = new Map();
51
+ const totalFiles = files.length;
52
+ Logger.progress(`Parsing ${totalFiles} virtual files from source maps...`);
53
+ for (let i = 0; i < totalFiles; i++) {
54
+ const file = files[i];
55
+ if (progressCallback) {
56
+ progressCallback(i + 1, totalFiles, file.path);
57
+ }
58
+ const ast = this.astParser.parseContent(file.content, file.path);
59
+ if (ast) {
60
+ asts.set(file.path, ast);
61
+ }
62
+ }
63
+ Logger.success(`Parsed ${asts.size} virtual files successfully`);
64
+ return asts;
65
+ }
66
+ /**
67
+ * Получает виртуальные файлы (для передачи на сервер)
68
+ */
69
+ getVirtualFiles() {
70
+ return this.virtualFiles;
27
71
  }
28
72
  async indexProject(rootDir) {
29
73
  const dir = rootDir || this.rootDir;
@@ -120,5 +164,5 @@ export class CodeIndex {
120
164
  return counts;
121
165
  }
122
166
  }
123
- export { ASTParser, SymbolExtractor, DependencyGraphBuilder };
167
+ export { ASTParser, SymbolExtractor, DependencyGraphBuilder, SourceMapExtractor };
124
168
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Source Map Extractor
3
+ *
4
+ * Извлекает оригинальный исходный код из source map файлов.
5
+ * Позволяет индексировать bundled/minified проекты.
6
+ */
7
+ export interface VirtualFile {
8
+ /** Виртуальный путь файла (восстановленный из source map) */
9
+ path: string;
10
+ /** Содержимое файла */
11
+ content: string;
12
+ /** Оригинальный source map файл */
13
+ sourceMapPath: string;
14
+ }
15
+ export interface SourceMapData {
16
+ version: number;
17
+ file?: string;
18
+ sourceRoot?: string;
19
+ sources: string[];
20
+ sourcesContent?: (string | null)[];
21
+ names?: string[];
22
+ mappings: string;
23
+ }
24
+ export interface ExtractionResult {
25
+ /** Извлечённые виртуальные файлы */
26
+ files: VirtualFile[];
27
+ /** Статистика извлечения */
28
+ stats: {
29
+ sourceMapCount: number;
30
+ totalSources: number;
31
+ extractedFiles: number;
32
+ skippedFiles: number;
33
+ };
34
+ }
35
+ export declare class SourceMapExtractor {
36
+ private processedMaps;
37
+ /**
38
+ * Проверяет, является ли проект bundled (содержит source maps)
39
+ */
40
+ isBundledProject(projectPath: string): Promise<boolean>;
41
+ /**
42
+ * Находит все .map файлы в проекте
43
+ */
44
+ findSourceMaps(projectPath: string): Promise<string[]>;
45
+ /**
46
+ * Извлекает все исходные файлы из source maps проекта
47
+ */
48
+ extractFromProject(projectPath: string): Promise<ExtractionResult>;
49
+ /**
50
+ * Извлекает исходные файлы из одного source map
51
+ */
52
+ extractFromSourceMap(mapPath: string): Promise<VirtualFile[]>;
53
+ /**
54
+ * Нормализует путь из source map
55
+ * webpack://project/./src/file.vue → src/file.vue
56
+ */
57
+ private normalizePath;
58
+ /**
59
+ * Проверяет, нужно ли пропустить этот источник
60
+ */
61
+ private shouldSkipSource;
62
+ /**
63
+ * Проверяет, является ли файл исходным кодом
64
+ */
65
+ private isSourceFile;
66
+ /**
67
+ * Очищает кэш обработанных map файлов
68
+ */
69
+ clearCache(): void;
70
+ }
71
+ //# sourceMappingURL=source-map-extractor.d.ts.map
@@ -0,0 +1,194 @@
1
+ /**
2
+ * Source Map Extractor
3
+ *
4
+ * Извлекает оригинальный исходный код из source map файлов.
5
+ * Позволяет индексировать bundled/minified проекты.
6
+ */
7
+ import * as fs from 'fs';
8
+ import * as path from 'path';
9
+ import { Logger } from '../utils/logger.js';
10
+ export class SourceMapExtractor {
11
+ processedMaps = new Set();
12
+ /**
13
+ * Проверяет, является ли проект bundled (содержит source maps)
14
+ */
15
+ async isBundledProject(projectPath) {
16
+ const mapFiles = await this.findSourceMaps(projectPath);
17
+ return mapFiles.length > 0;
18
+ }
19
+ /**
20
+ * Находит все .map файлы в проекте
21
+ */
22
+ async findSourceMaps(projectPath) {
23
+ const mapFiles = [];
24
+ const scanDir = async (dir, depth = 0) => {
25
+ // Ограничиваем глубину сканирования
26
+ if (depth > 5)
27
+ return;
28
+ try {
29
+ const entries = await fs.promises.readdir(dir, { withFileTypes: true });
30
+ for (const entry of entries) {
31
+ const fullPath = path.join(dir, entry.name);
32
+ if (entry.isDirectory()) {
33
+ // Пропускаем node_modules и скрытые папки
34
+ if (entry.name === 'node_modules' || entry.name.startsWith('.')) {
35
+ continue;
36
+ }
37
+ await scanDir(fullPath, depth + 1);
38
+ }
39
+ else if (entry.isFile() && entry.name.endsWith('.js.map')) {
40
+ mapFiles.push(fullPath);
41
+ }
42
+ }
43
+ }
44
+ catch {
45
+ // Игнорируем ошибки доступа
46
+ }
47
+ };
48
+ await scanDir(projectPath);
49
+ return mapFiles;
50
+ }
51
+ /**
52
+ * Извлекает все исходные файлы из source maps проекта
53
+ */
54
+ async extractFromProject(projectPath) {
55
+ const mapFiles = await this.findSourceMaps(projectPath);
56
+ const allFiles = [];
57
+ const seenPaths = new Set();
58
+ let totalSources = 0;
59
+ let skippedFiles = 0;
60
+ Logger.info(`Found ${mapFiles.length} source map files`);
61
+ for (const mapFile of mapFiles) {
62
+ try {
63
+ const extracted = await this.extractFromSourceMap(mapFile);
64
+ totalSources += extracted.length;
65
+ for (const file of extracted) {
66
+ // Дедупликация по пути
67
+ if (seenPaths.has(file.path)) {
68
+ skippedFiles++;
69
+ continue;
70
+ }
71
+ seenPaths.add(file.path);
72
+ allFiles.push(file);
73
+ }
74
+ }
75
+ catch (error) {
76
+ Logger.warn(`Failed to extract from ${mapFile}: ${error}`);
77
+ }
78
+ }
79
+ Logger.success(`Extracted ${allFiles.length} source files from ${mapFiles.length} source maps`);
80
+ return {
81
+ files: allFiles,
82
+ stats: {
83
+ sourceMapCount: mapFiles.length,
84
+ totalSources,
85
+ extractedFiles: allFiles.length,
86
+ skippedFiles
87
+ }
88
+ };
89
+ }
90
+ /**
91
+ * Извлекает исходные файлы из одного source map
92
+ */
93
+ async extractFromSourceMap(mapPath) {
94
+ if (this.processedMaps.has(mapPath)) {
95
+ return [];
96
+ }
97
+ this.processedMaps.add(mapPath);
98
+ const content = await fs.promises.readFile(mapPath, 'utf-8');
99
+ const sourceMap = JSON.parse(content);
100
+ if (!sourceMap.sources || !sourceMap.sourcesContent) {
101
+ Logger.debug(`Source map ${mapPath} has no embedded sources`);
102
+ return [];
103
+ }
104
+ const files = [];
105
+ for (let i = 0; i < sourceMap.sources.length; i++) {
106
+ const sourcePath = sourceMap.sources[i];
107
+ const sourceContent = sourceMap.sourcesContent[i];
108
+ // Пропускаем null/пустые источники
109
+ if (!sourceContent) {
110
+ continue;
111
+ }
112
+ // Пропускаем node_modules и внешние зависимости
113
+ if (this.shouldSkipSource(sourcePath)) {
114
+ continue;
115
+ }
116
+ // Нормализуем путь
117
+ const normalizedPath = this.normalizePath(sourcePath, sourceMap.sourceRoot);
118
+ // Проверяем, что это исходный код (не ассеты)
119
+ if (!this.isSourceFile(normalizedPath)) {
120
+ continue;
121
+ }
122
+ files.push({
123
+ path: normalizedPath,
124
+ content: sourceContent,
125
+ sourceMapPath: mapPath
126
+ });
127
+ }
128
+ return files;
129
+ }
130
+ /**
131
+ * Нормализует путь из source map
132
+ * webpack://project/./src/file.vue → src/file.vue
133
+ */
134
+ normalizePath(sourcePath, sourceRoot) {
135
+ let normalized = sourcePath;
136
+ // Убираем webpack:// префикс
137
+ if (normalized.startsWith('webpack://')) {
138
+ // webpack://project-name/./src/file.ts → ./src/file.ts
139
+ normalized = normalized.replace(/^webpack:\/\/[^/]+\//, '');
140
+ }
141
+ // Убираем ./ префикс
142
+ if (normalized.startsWith('./')) {
143
+ normalized = normalized.substring(2);
144
+ }
145
+ // Применяем sourceRoot если есть
146
+ if (sourceRoot && !normalized.startsWith(sourceRoot)) {
147
+ normalized = path.posix.join(sourceRoot, normalized);
148
+ }
149
+ // Убираем query strings (?xxxx)
150
+ normalized = normalized.replace(/\?[a-f0-9]+$/, '');
151
+ // Заменяем обратные слеши на прямые
152
+ normalized = normalized.replace(/\\/g, '/');
153
+ return normalized;
154
+ }
155
+ /**
156
+ * Проверяет, нужно ли пропустить этот источник
157
+ */
158
+ shouldSkipSource(sourcePath) {
159
+ const skipPatterns = [
160
+ 'node_modules/',
161
+ '/node_modules/',
162
+ 'webpack/runtime',
163
+ 'webpack/bootstrap',
164
+ '(webpack)',
165
+ '__webpack',
166
+ 'ignored|',
167
+ '/external ',
168
+ 'polyfill',
169
+ '.css', // CSS в JS обычно не нужен
170
+ ];
171
+ const lowerPath = sourcePath.toLowerCase();
172
+ return skipPatterns.some(pattern => lowerPath.includes(pattern.toLowerCase()));
173
+ }
174
+ /**
175
+ * Проверяет, является ли файл исходным кодом
176
+ */
177
+ isSourceFile(filePath) {
178
+ const sourceExtensions = [
179
+ '.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs',
180
+ '.vue', '.svelte', '.astro',
181
+ '.py', '.rb', '.go', '.rs', '.java', '.kt', '.scala',
182
+ '.php', '.cs', '.swift', '.dart'
183
+ ];
184
+ const ext = path.extname(filePath).toLowerCase();
185
+ return sourceExtensions.includes(ext);
186
+ }
187
+ /**
188
+ * Очищает кэш обработанных map файлов
189
+ */
190
+ clearCache() {
191
+ this.processedMaps.clear();
192
+ }
193
+ }
194
+ //# sourceMappingURL=source-map-extractor.js.map
@@ -0,0 +1,162 @@
1
+ /**
2
+ * GitLab Integration Service
3
+ *
4
+ * Manages GitLab connections with support for:
5
+ * - Multiple GitLab instances (self-hosted + gitlab.com)
6
+ * - Personal Access Token (PAT) authentication
7
+ * - Private repositories access
8
+ * - Branch listing and selection
9
+ * - Webhooks for auto-analysis
10
+ * - Merge Request analysis
11
+ */
12
+ import { GitLabInstance, GitLabProject, GitLabBranch, ConnectedGitLabRepository, GitLabMergeRequest, GitLabMRChange, ConnectGitLabRepositoryOptions, GitLabServiceConfig } from '../types/gitlab.js';
13
+ export declare class GitLabService {
14
+ private instances;
15
+ private repositories;
16
+ private initialized;
17
+ private dataDir;
18
+ constructor(config?: GitLabServiceConfig);
19
+ private ensureInitialized;
20
+ private loadInstances;
21
+ private saveInstances;
22
+ private loadRepositories;
23
+ private saveRepositories;
24
+ private encrypt;
25
+ private decrypt;
26
+ /**
27
+ * Add a new GitLab instance connection
28
+ */
29
+ addInstance(userId: string, instanceUrl: string, accessToken: string, options?: {
30
+ name?: string;
31
+ rejectUnauthorizedSSL?: boolean;
32
+ }): Promise<GitLabInstance>;
33
+ /**
34
+ * Get instance display name from URL
35
+ */
36
+ private getInstanceName;
37
+ /**
38
+ * Get all GitLab instances for a user
39
+ */
40
+ getInstances(userId: string): Promise<GitLabInstance[]>;
41
+ /**
42
+ * Get a specific instance by ID
43
+ */
44
+ getInstance(instanceId: string): Promise<GitLabInstance | null>;
45
+ /**
46
+ * Remove a GitLab instance connection
47
+ */
48
+ removeInstance(userId: string, instanceId: string): Promise<boolean>;
49
+ /**
50
+ * Make authenticated request to GitLab API
51
+ */
52
+ private gitlabFetch;
53
+ /**
54
+ * Fetch current GitLab user info
55
+ */
56
+ private fetchGitLabUser;
57
+ /**
58
+ * Get token scopes (by testing API endpoints)
59
+ */
60
+ private getTokenScopes;
61
+ /**
62
+ * List all accessible projects from a GitLab instance
63
+ */
64
+ listProjects(userId: string, instanceId: string, options?: {
65
+ search?: string;
66
+ membership?: boolean;
67
+ owned?: boolean;
68
+ page?: number;
69
+ perPage?: number;
70
+ }): Promise<GitLabProject[]>;
71
+ /**
72
+ * Get a specific project by ID
73
+ */
74
+ getProject(userId: string, instanceId: string, projectId: number | string): Promise<GitLabProject>;
75
+ /**
76
+ * List branches for a project
77
+ */
78
+ listBranches(userId: string, instanceId: string, projectId: number | string): Promise<GitLabBranch[]>;
79
+ /**
80
+ * Connect a GitLab repository to ArchiCore
81
+ */
82
+ connectRepository(userId: string, instanceId: string, projectId: number, options?: ConnectGitLabRepositoryOptions): Promise<ConnectedGitLabRepository>;
83
+ /**
84
+ * Get all connected repositories for a user
85
+ */
86
+ getConnectedRepositories(userId: string): Promise<ConnectedGitLabRepository[]>;
87
+ /**
88
+ * Get a specific connected repository
89
+ */
90
+ getConnectedRepository(repoId: string): Promise<ConnectedGitLabRepository | null>;
91
+ /**
92
+ * Disconnect a repository
93
+ */
94
+ disconnectRepository(userId: string, repoId: string): Promise<boolean>;
95
+ /**
96
+ * Update repository's ArchiCore project ID
97
+ */
98
+ updateRepositoryProjectId(repoId: string, projectId: string): Promise<void>;
99
+ /**
100
+ * Update repository status
101
+ */
102
+ updateRepositoryStatus(repoId: string, status: ConnectedGitLabRepository['status'], error?: string): Promise<void>;
103
+ /**
104
+ * Update last analyzed timestamp
105
+ */
106
+ updateLastAnalyzed(repoId: string): Promise<void>;
107
+ /**
108
+ * Download repository archive
109
+ */
110
+ downloadRepository(userId: string, instanceId: string, projectId: number | string, ref?: string): Promise<Buffer>;
111
+ /**
112
+ * Get file content from repository
113
+ */
114
+ getFileContent(userId: string, instanceId: string, projectId: number | string, filePath: string, ref?: string): Promise<string>;
115
+ /**
116
+ * Get merge request details
117
+ */
118
+ getMergeRequest(userId: string, instanceId: string, projectId: number | string, mrIid: number): Promise<GitLabMergeRequest>;
119
+ /**
120
+ * Get merge request changes (diff)
121
+ */
122
+ getMergeRequestChanges(userId: string, instanceId: string, projectId: number | string, mrIid: number): Promise<GitLabMRChange[]>;
123
+ /**
124
+ * Post a comment on merge request
125
+ */
126
+ postMRComment(userId: string, instanceId: string, projectId: number | string, mrIid: number, body: string): Promise<{
127
+ id: number;
128
+ }>;
129
+ /**
130
+ * Create webhook for repository
131
+ */
132
+ createWebhook(userId: string, instanceId: string, projectId: number): Promise<{
133
+ id: number;
134
+ secret: string;
135
+ }>;
136
+ /**
137
+ * Delete webhook
138
+ */
139
+ deleteWebhook(userId: string, instanceId: string, projectId: number, hookId: number): Promise<void>;
140
+ /**
141
+ * Verify webhook token
142
+ */
143
+ verifyWebhookToken(token: string, expectedToken: string): boolean;
144
+ /**
145
+ * Find repository by webhook (for incoming webhooks)
146
+ */
147
+ findRepositoryByWebhook(fullPath: string): Promise<ConnectedGitLabRepository | null>;
148
+ /**
149
+ * Get instance for repository (used in webhook handling)
150
+ */
151
+ getInstanceForRepository(repo: ConnectedGitLabRepository): Promise<GitLabInstance | null>;
152
+ /**
153
+ * Get decrypted webhook secret
154
+ */
155
+ getWebhookSecret(encryptedSecret: string): string;
156
+ /**
157
+ * Disconnect repository by ArchiCore project ID
158
+ */
159
+ disconnectRepositoryByProjectId(projectId: string): Promise<boolean>;
160
+ }
161
+ export default GitLabService;
162
+ //# sourceMappingURL=gitlab-service.d.ts.map