aura-security 0.4.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.
Files changed (115) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +446 -0
  3. package/deploy/AWS-DEPLOYMENT.md +358 -0
  4. package/deploy/terraform/main.tf +362 -0
  5. package/deploy/terraform/terraform.tfvars.example +6 -0
  6. package/dist/agents/base.d.ts +44 -0
  7. package/dist/agents/base.js +96 -0
  8. package/dist/agents/index.d.ts +14 -0
  9. package/dist/agents/index.js +17 -0
  10. package/dist/agents/policy/evaluator.d.ts +15 -0
  11. package/dist/agents/policy/evaluator.js +183 -0
  12. package/dist/agents/policy/index.d.ts +12 -0
  13. package/dist/agents/policy/index.js +15 -0
  14. package/dist/agents/policy/validator.d.ts +15 -0
  15. package/dist/agents/policy/validator.js +182 -0
  16. package/dist/agents/scanners/gitleaks.d.ts +14 -0
  17. package/dist/agents/scanners/gitleaks.js +155 -0
  18. package/dist/agents/scanners/grype.d.ts +14 -0
  19. package/dist/agents/scanners/grype.js +109 -0
  20. package/dist/agents/scanners/index.d.ts +15 -0
  21. package/dist/agents/scanners/index.js +27 -0
  22. package/dist/agents/scanners/npm-audit.d.ts +13 -0
  23. package/dist/agents/scanners/npm-audit.js +129 -0
  24. package/dist/agents/scanners/semgrep.d.ts +14 -0
  25. package/dist/agents/scanners/semgrep.js +131 -0
  26. package/dist/agents/scanners/trivy.d.ts +14 -0
  27. package/dist/agents/scanners/trivy.js +122 -0
  28. package/dist/agents/types.d.ts +137 -0
  29. package/dist/agents/types.js +91 -0
  30. package/dist/auditor/index.d.ts +3 -0
  31. package/dist/auditor/index.js +2 -0
  32. package/dist/auditor/pipeline.d.ts +19 -0
  33. package/dist/auditor/pipeline.js +240 -0
  34. package/dist/auditor/validator.d.ts +17 -0
  35. package/dist/auditor/validator.js +58 -0
  36. package/dist/aura/client.d.ts +29 -0
  37. package/dist/aura/client.js +125 -0
  38. package/dist/aura/index.d.ts +4 -0
  39. package/dist/aura/index.js +2 -0
  40. package/dist/aura/server.d.ts +45 -0
  41. package/dist/aura/server.js +343 -0
  42. package/dist/cli.d.ts +17 -0
  43. package/dist/cli.js +1433 -0
  44. package/dist/client/index.d.ts +41 -0
  45. package/dist/client/index.js +170 -0
  46. package/dist/compliance/index.d.ts +40 -0
  47. package/dist/compliance/index.js +292 -0
  48. package/dist/database/index.d.ts +77 -0
  49. package/dist/database/index.js +395 -0
  50. package/dist/index.d.ts +25 -0
  51. package/dist/index.js +762 -0
  52. package/dist/integrations/aura-scanner.d.ts +69 -0
  53. package/dist/integrations/aura-scanner.js +155 -0
  54. package/dist/integrations/aws-scanner.d.ts +63 -0
  55. package/dist/integrations/aws-scanner.js +624 -0
  56. package/dist/integrations/config.d.ts +69 -0
  57. package/dist/integrations/config.js +212 -0
  58. package/dist/integrations/github.d.ts +45 -0
  59. package/dist/integrations/github.js +201 -0
  60. package/dist/integrations/gitlab.d.ts +36 -0
  61. package/dist/integrations/gitlab.js +110 -0
  62. package/dist/integrations/index.d.ts +11 -0
  63. package/dist/integrations/index.js +11 -0
  64. package/dist/integrations/local-scanner.d.ts +146 -0
  65. package/dist/integrations/local-scanner.js +1654 -0
  66. package/dist/integrations/notifications.d.ts +99 -0
  67. package/dist/integrations/notifications.js +305 -0
  68. package/dist/integrations/scanners.d.ts +57 -0
  69. package/dist/integrations/scanners.js +217 -0
  70. package/dist/integrations/slop-scanner.d.ts +69 -0
  71. package/dist/integrations/slop-scanner.js +155 -0
  72. package/dist/integrations/webhook.d.ts +37 -0
  73. package/dist/integrations/webhook.js +256 -0
  74. package/dist/orchestrator/index.d.ts +72 -0
  75. package/dist/orchestrator/index.js +187 -0
  76. package/dist/output/index.d.ts +152 -0
  77. package/dist/output/index.js +399 -0
  78. package/dist/pipeline/index.d.ts +72 -0
  79. package/dist/pipeline/index.js +313 -0
  80. package/dist/sbom/index.d.ts +94 -0
  81. package/dist/sbom/index.js +298 -0
  82. package/dist/schemas/index.d.ts +2 -0
  83. package/dist/schemas/index.js +2 -0
  84. package/dist/schemas/input.schema.d.ts +87 -0
  85. package/dist/schemas/input.schema.js +44 -0
  86. package/dist/schemas/output.schema.d.ts +115 -0
  87. package/dist/schemas/output.schema.js +64 -0
  88. package/dist/serve-visualizer.d.ts +2 -0
  89. package/dist/serve-visualizer.js +78 -0
  90. package/dist/slop/client.d.ts +29 -0
  91. package/dist/slop/client.js +125 -0
  92. package/dist/slop/index.d.ts +4 -0
  93. package/dist/slop/index.js +2 -0
  94. package/dist/slop/server.d.ts +45 -0
  95. package/dist/slop/server.js +343 -0
  96. package/dist/types/events.d.ts +62 -0
  97. package/dist/types/events.js +2 -0
  98. package/dist/types/index.d.ts +1 -0
  99. package/dist/types/index.js +1 -0
  100. package/dist/visualizer/index.d.ts +4 -0
  101. package/dist/visualizer/index.js +181 -0
  102. package/dist/websocket/index.d.ts +88 -0
  103. package/dist/websocket/index.js +195 -0
  104. package/dist/zones/index.d.ts +7 -0
  105. package/dist/zones/index.js +7 -0
  106. package/dist/zones/manager.d.ts +101 -0
  107. package/dist/zones/manager.js +304 -0
  108. package/dist/zones/types.d.ts +78 -0
  109. package/dist/zones/types.js +33 -0
  110. package/package.json +84 -0
  111. package/visualizer/app.js +0 -0
  112. package/visualizer/index-minimal.html +1771 -0
  113. package/visualizer/index.html +2933 -0
  114. package/visualizer/landing.html +1328 -0
  115. package/visualizer/styles.css +0 -0
@@ -0,0 +1,395 @@
1
+ /**
2
+ * SQLite Database for aurasecurity
3
+ *
4
+ * Provides persistent storage for:
5
+ * - Audit history
6
+ * - Configuration settings
7
+ * - Scan results
8
+ * - Notification history
9
+ */
10
+ import Database from 'better-sqlite3';
11
+ import { join } from 'path';
12
+ import { existsSync, mkdirSync } from 'fs';
13
+ // ============ DEFAULT SETTINGS ============
14
+ const DEFAULT_SETTINGS = {
15
+ // AWS Settings
16
+ 'aws.enabled': 'false',
17
+ 'aws.region': 'us-east-1',
18
+ 'aws.accessKeyId': '',
19
+ 'aws.secretAccessKey': '',
20
+ 'aws.services': 'iam,s3,ec2,lambda,rds',
21
+ // Slack Settings
22
+ 'slack.enabled': 'false',
23
+ 'slack.webhookUrl': '',
24
+ 'slack.channel': '',
25
+ 'slack.notifyOn': 'critical,high',
26
+ // Discord Settings
27
+ 'discord.enabled': 'false',
28
+ 'discord.webhookUrl': '',
29
+ 'discord.notifyOn': 'critical,high',
30
+ // GitHub Settings
31
+ 'github.enabled': 'false',
32
+ 'github.token': '',
33
+ 'github.createCheckRuns': 'true',
34
+ 'github.commentOnPR': 'true',
35
+ // GitLab Settings
36
+ 'gitlab.enabled': 'false',
37
+ 'gitlab.token': '',
38
+ 'gitlab.url': 'https://gitlab.com',
39
+ // Scanner Settings
40
+ 'scanner.gitleaks': 'true',
41
+ 'scanner.trivy': 'true',
42
+ 'scanner.semgrep': 'true',
43
+ 'scanner.npmAudit': 'true',
44
+ // Thresholds
45
+ 'thresholds.failOnCritical': 'true',
46
+ 'thresholds.failOnHigh': 'false',
47
+ 'thresholds.maxCritical': '0',
48
+ 'thresholds.maxHigh': '5',
49
+ // Server Settings
50
+ 'server.port': '3000',
51
+ 'server.visualizerPort': '8080',
52
+ };
53
+ // ============ DATABASE CLASS ============
54
+ export class AuditorDatabase {
55
+ db;
56
+ dbPath;
57
+ constructor(dbPath) {
58
+ // Default to .aura-security directory in user home
59
+ const dataDir = dbPath
60
+ ? join(dbPath, '.aura-security')
61
+ : join(process.env.HOME || process.env.USERPROFILE || '.', '.aura-security');
62
+ if (!existsSync(dataDir)) {
63
+ mkdirSync(dataDir, { recursive: true });
64
+ }
65
+ this.dbPath = join(dataDir, 'auditor.db');
66
+ this.db = new Database(this.dbPath);
67
+ // Enable WAL mode for better concurrent access
68
+ this.db.pragma('journal_mode = WAL');
69
+ // Initialize tables
70
+ this.initTables();
71
+ console.log(`[DB] SQLite database initialized at: ${this.dbPath}`);
72
+ }
73
+ initTables() {
74
+ // Audits table
75
+ this.db.exec(`
76
+ CREATE TABLE IF NOT EXISTS audits (
77
+ id TEXT PRIMARY KEY,
78
+ type TEXT NOT NULL,
79
+ timestamp TEXT NOT NULL,
80
+ target TEXT NOT NULL,
81
+ critical INTEGER DEFAULT 0,
82
+ high INTEGER DEFAULT 0,
83
+ medium INTEGER DEFAULT 0,
84
+ low INTEGER DEFAULT 0,
85
+ data TEXT NOT NULL
86
+ )
87
+ `);
88
+ // Settings table
89
+ this.db.exec(`
90
+ CREATE TABLE IF NOT EXISTS settings (
91
+ key TEXT PRIMARY KEY,
92
+ value TEXT NOT NULL,
93
+ updated_at TEXT NOT NULL
94
+ )
95
+ `);
96
+ // Notifications table
97
+ this.db.exec(`
98
+ CREATE TABLE IF NOT EXISTS notifications (
99
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
100
+ type TEXT NOT NULL,
101
+ audit_id TEXT NOT NULL,
102
+ status TEXT NOT NULL,
103
+ message TEXT NOT NULL,
104
+ timestamp TEXT NOT NULL,
105
+ error TEXT,
106
+ FOREIGN KEY (audit_id) REFERENCES audits(id)
107
+ )
108
+ `);
109
+ // Create indexes
110
+ this.db.exec(`
111
+ CREATE INDEX IF NOT EXISTS idx_audits_timestamp ON audits(timestamp DESC);
112
+ CREATE INDEX IF NOT EXISTS idx_audits_type ON audits(type);
113
+ CREATE INDEX IF NOT EXISTS idx_notifications_audit ON notifications(audit_id);
114
+ `);
115
+ // Initialize default settings
116
+ const insertSetting = this.db.prepare(`
117
+ INSERT OR IGNORE INTO settings (key, value, updated_at) VALUES (?, ?, ?)
118
+ `);
119
+ const now = new Date().toISOString();
120
+ for (const [key, value] of Object.entries(DEFAULT_SETTINGS)) {
121
+ insertSetting.run(key, value, now);
122
+ }
123
+ }
124
+ // ============ AUDIT METHODS ============
125
+ saveAudit(type, target, result) {
126
+ const id = `${type}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
127
+ const timestamp = new Date().toISOString();
128
+ // Extract summary counts based on type
129
+ let critical = 0, high = 0, medium = 0, low = 0;
130
+ if (type === 'code') {
131
+ const r = result;
132
+ critical = r.secrets.filter(s => s.severity === 'critical').length +
133
+ r.packages.filter(p => p.severity === 'critical').length;
134
+ high = r.secrets.filter(s => s.severity === 'high').length +
135
+ r.packages.filter(p => p.severity === 'high').length;
136
+ medium = r.secrets.filter(s => s.severity === 'medium').length +
137
+ r.packages.filter(p => p.severity === 'medium').length;
138
+ low = r.secrets.filter(s => s.severity === 'low').length +
139
+ r.packages.filter(p => p.severity === 'low').length;
140
+ }
141
+ else if (type === 'aws') {
142
+ const r = result;
143
+ critical = r.summary.critical;
144
+ high = r.summary.high;
145
+ medium = r.summary.medium;
146
+ low = r.summary.low;
147
+ }
148
+ else if (type === 'audit') {
149
+ const r = result;
150
+ for (const event of r.events) {
151
+ if (event.payload?.severity === 'critical')
152
+ critical++;
153
+ else if (event.payload?.severity === 'high')
154
+ high++;
155
+ else if (event.payload?.severity === 'medium')
156
+ medium++;
157
+ else if (event.payload?.severity === 'low')
158
+ low++;
159
+ }
160
+ }
161
+ const stmt = this.db.prepare(`
162
+ INSERT INTO audits (id, type, timestamp, target, critical, high, medium, low, data)
163
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
164
+ `);
165
+ stmt.run(id, type, timestamp, target, critical, high, medium, low, JSON.stringify(result));
166
+ console.log(`[DB] Saved audit: ${id} (${type})`);
167
+ return id;
168
+ }
169
+ getAudit(id) {
170
+ const stmt = this.db.prepare(`
171
+ SELECT id, type, timestamp, target, critical, high, medium, low, data
172
+ FROM audits WHERE id = ?
173
+ `);
174
+ const row = stmt.get(id);
175
+ if (!row)
176
+ return null;
177
+ return {
178
+ id: row.id,
179
+ type: row.type,
180
+ timestamp: row.timestamp,
181
+ target: row.target,
182
+ summary: {
183
+ critical: row.critical,
184
+ high: row.high,
185
+ medium: row.medium,
186
+ low: row.low,
187
+ },
188
+ data: row.data,
189
+ };
190
+ }
191
+ getAudits(limit = 50, offset = 0, type) {
192
+ let query = `
193
+ SELECT id, type, timestamp, target, critical, high, medium, low, data
194
+ FROM audits
195
+ `;
196
+ const params = [];
197
+ if (type) {
198
+ query += ' WHERE type = ?';
199
+ params.push(type);
200
+ }
201
+ query += ' ORDER BY timestamp DESC LIMIT ? OFFSET ?';
202
+ params.push(limit, offset);
203
+ const stmt = this.db.prepare(query);
204
+ const rows = stmt.all(...params);
205
+ return rows.map(row => ({
206
+ id: row.id,
207
+ type: row.type,
208
+ timestamp: row.timestamp,
209
+ target: row.target,
210
+ summary: {
211
+ critical: row.critical,
212
+ high: row.high,
213
+ medium: row.medium,
214
+ low: row.low,
215
+ },
216
+ data: row.data,
217
+ }));
218
+ }
219
+ getAuditCount(type) {
220
+ let query = 'SELECT COUNT(*) as count FROM audits';
221
+ const params = [];
222
+ if (type) {
223
+ query += ' WHERE type = ?';
224
+ params.push(type);
225
+ }
226
+ const stmt = this.db.prepare(query);
227
+ const row = stmt.get(...params);
228
+ return row.count;
229
+ }
230
+ deleteAudit(id) {
231
+ const stmt = this.db.prepare('DELETE FROM audits WHERE id = ?');
232
+ const result = stmt.run(id);
233
+ return result.changes > 0;
234
+ }
235
+ // ============ SETTINGS METHODS ============
236
+ getSetting(key) {
237
+ const stmt = this.db.prepare('SELECT value FROM settings WHERE key = ?');
238
+ const row = stmt.get(key);
239
+ return row ? row.value : null;
240
+ }
241
+ getSettings(prefix) {
242
+ let query = 'SELECT key, value FROM settings';
243
+ const params = [];
244
+ if (prefix) {
245
+ query += ' WHERE key LIKE ?';
246
+ params.push(`${prefix}%`);
247
+ }
248
+ const stmt = this.db.prepare(query);
249
+ const rows = stmt.all(...params);
250
+ const settings = {};
251
+ for (const row of rows) {
252
+ settings[row.key] = row.value;
253
+ }
254
+ return settings;
255
+ }
256
+ getAllSettings() {
257
+ return this.getSettings();
258
+ }
259
+ setSetting(key, value) {
260
+ const stmt = this.db.prepare(`
261
+ INSERT INTO settings (key, value, updated_at) VALUES (?, ?, ?)
262
+ ON CONFLICT(key) DO UPDATE SET value = ?, updated_at = ?
263
+ `);
264
+ const now = new Date().toISOString();
265
+ stmt.run(key, value, now, value, now);
266
+ }
267
+ setSettings(settings) {
268
+ const stmt = this.db.prepare(`
269
+ INSERT INTO settings (key, value, updated_at) VALUES (?, ?, ?)
270
+ ON CONFLICT(key) DO UPDATE SET value = ?, updated_at = ?
271
+ `);
272
+ const now = new Date().toISOString();
273
+ const transaction = this.db.transaction(() => {
274
+ for (const [key, value] of Object.entries(settings)) {
275
+ stmt.run(key, value, now, value, now);
276
+ }
277
+ });
278
+ transaction();
279
+ }
280
+ // ============ NOTIFICATION METHODS ============
281
+ saveNotification(type, auditId, status, message, error) {
282
+ const stmt = this.db.prepare(`
283
+ INSERT INTO notifications (type, audit_id, status, message, timestamp, error)
284
+ VALUES (?, ?, ?, ?, ?, ?)
285
+ `);
286
+ const result = stmt.run(type, auditId, status, message, new Date().toISOString(), error || null);
287
+ return result.lastInsertRowid;
288
+ }
289
+ recordNotification(auditId, channels, success, error) {
290
+ const timestamp = new Date().toISOString();
291
+ const stmt = this.db.prepare(`
292
+ INSERT INTO notifications (type, audit_id, status, message, timestamp, error)
293
+ VALUES (?, ?, ?, ?, ?, ?)
294
+ `);
295
+ stmt.run(channels || 'unknown', auditId, success ? 'sent' : 'failed', success ? `Notification sent via ${channels}` : 'Notification failed', timestamp, error || null);
296
+ }
297
+ getNotifications(auditId, limit = 50) {
298
+ let query = `
299
+ SELECT id, type, audit_id, status, message, timestamp, error
300
+ FROM notifications
301
+ `;
302
+ const params = [];
303
+ if (auditId) {
304
+ query += ' WHERE audit_id = ?';
305
+ params.push(auditId);
306
+ }
307
+ query += ' ORDER BY timestamp DESC LIMIT ?';
308
+ params.push(limit);
309
+ const stmt = this.db.prepare(query);
310
+ const rows = stmt.all(...params);
311
+ return rows.map(row => ({
312
+ id: row.id,
313
+ type: row.type,
314
+ audit_id: row.audit_id,
315
+ status: row.status,
316
+ message: row.message,
317
+ timestamp: row.timestamp,
318
+ error: row.error,
319
+ }));
320
+ }
321
+ // ============ STATS METHODS ============
322
+ getStats() {
323
+ // Total audits
324
+ const totalStmt = this.db.prepare('SELECT COUNT(*) as count FROM audits');
325
+ const totalRow = totalStmt.get();
326
+ // By type
327
+ const typeStmt = this.db.prepare(`
328
+ SELECT type, COUNT(*) as count FROM audits GROUP BY type
329
+ `);
330
+ const typeRows = typeStmt.all();
331
+ const byType = {};
332
+ for (const row of typeRows) {
333
+ byType[row.type] = row.count;
334
+ }
335
+ // By day (last 30 days)
336
+ const dayStmt = this.db.prepare(`
337
+ SELECT DATE(timestamp) as date, COUNT(*) as count
338
+ FROM audits
339
+ WHERE timestamp >= DATE('now', '-30 days')
340
+ GROUP BY DATE(timestamp)
341
+ ORDER BY date DESC
342
+ `);
343
+ const dayRows = dayStmt.all();
344
+ const byDay = dayRows.map(row => ({ date: row.date, count: row.count }));
345
+ // Severity totals
346
+ const sevStmt = this.db.prepare(`
347
+ SELECT
348
+ SUM(critical) as critical,
349
+ SUM(high) as high,
350
+ SUM(medium) as medium,
351
+ SUM(low) as low
352
+ FROM audits
353
+ `);
354
+ const sevRow = sevStmt.get();
355
+ return {
356
+ totalAudits: totalRow.count,
357
+ byType,
358
+ byDay,
359
+ severityCounts: {
360
+ critical: sevRow.critical || 0,
361
+ high: sevRow.high || 0,
362
+ medium: sevRow.medium || 0,
363
+ low: sevRow.low || 0,
364
+ },
365
+ };
366
+ }
367
+ // ============ CLEANUP ============
368
+ close() {
369
+ this.db.close();
370
+ }
371
+ vacuum() {
372
+ this.db.exec('VACUUM');
373
+ }
374
+ deleteOldAudits(daysToKeep = 90) {
375
+ const stmt = this.db.prepare(`
376
+ DELETE FROM audits WHERE timestamp < DATE('now', '-' || ? || ' days')
377
+ `);
378
+ const result = stmt.run(daysToKeep);
379
+ return result.changes;
380
+ }
381
+ }
382
+ // Singleton instance
383
+ let dbInstance = null;
384
+ export function getDatabase(dbPath) {
385
+ if (!dbInstance) {
386
+ dbInstance = new AuditorDatabase(dbPath);
387
+ }
388
+ return dbInstance;
389
+ }
390
+ export function closeDatabase() {
391
+ if (dbInstance) {
392
+ dbInstance.close();
393
+ dbInstance = null;
394
+ }
395
+ }
@@ -0,0 +1,25 @@
1
+ export { AuraServer } from './aura/server.js';
2
+ export { AuraClient } from './aura/client.js';
3
+ export { AuditorPipeline } from './auditor/pipeline.js';
4
+ export { SchemaValidator, ValidationError } from './auditor/validator.js';
5
+ export * from './types/events.js';
6
+ export { AuditClient, createPullRequestEvent, createDeployEvent, createInfraChangeEvent } from './client/index.js';
7
+ export type { AuditClientConfig, AuditRequest, AuditResult, ServerInfo } from './client/index.js';
8
+ export { SecurityPipeline, SecretsDetectionStage, VulnerabilityScanStage, CriticalAssetStage, InfrastructureChangeStage, ProductionDeployStage } from './pipeline/index.js';
9
+ export type { PipelineContext, AnalysisStage, RuleDefinition, RuleResult } from './pipeline/index.js';
10
+ export { WebhookServer, defaultHandlers } from './integrations/webhook.js';
11
+ export { GitHubIntegration } from './integrations/github.js';
12
+ export { GitLabIntegration } from './integrations/gitlab.js';
13
+ export { SnykParser, TrivyParser, SemgrepParser, NpmAuditParser, getParser } from './integrations/scanners.js';
14
+ export { ConfigLoader, configLoader } from './integrations/config.js';
15
+ export type { AuditorConfig, ModuleConfig, IntegrationConfig } from './integrations/config.js';
16
+ export { LocalScanner, quickLocalScan, scanRemoteGit, isGitUrl } from './integrations/local-scanner.js';
17
+ export type { LocalScanConfig, LocalScanResult, SecretFinding, PackageFinding, SastFinding, DiscoveredService, DiscoveredModule, RemoteScanConfig, RemoteScanResult } from './integrations/local-scanner.js';
18
+ export { AWSScanner, scanAWS } from './integrations/aws-scanner.js';
19
+ export type { AWSScanConfig, AWSScanResult, AWSFinding } from './integrations/aws-scanner.js';
20
+ export { AuditorDatabase, getDatabase, closeDatabase } from './database/index.js';
21
+ export type { AuditRecord, SettingsRecord, NotificationRecord } from './database/index.js';
22
+ export { NotificationService, createNotificationFromAudit } from './integrations/notifications.js';
23
+ export type { NotificationConfig, NotificationPayload } from './integrations/notifications.js';
24
+ export { AuditorWebSocket, getWebSocketServer, closeWebSocketServer } from './websocket/index.js';
25
+ export type { WSMessage, AuditStartedPayload, AuditCompletedPayload, FindingPayload } from './websocket/index.js';