verification-layer 0.16.0 → 0.19.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 +174 -21
- package/dist/ai/cache.d.ts +15 -0
- package/dist/ai/cache.d.ts.map +1 -0
- package/dist/ai/cache.js +75 -0
- package/dist/ai/cache.js.map +1 -0
- package/dist/ai/client.d.ts +11 -0
- package/dist/ai/client.d.ts.map +1 -0
- package/dist/ai/client.js +27 -0
- package/dist/ai/client.js.map +1 -0
- package/dist/ai/config.d.ts +29 -0
- package/dist/ai/config.d.ts.map +1 -0
- package/dist/ai/config.js +29 -0
- package/dist/ai/config.js.map +1 -0
- package/dist/ai/cost-tracker.d.ts +23 -0
- package/dist/ai/cost-tracker.d.ts.map +1 -0
- package/dist/ai/cost-tracker.js +55 -0
- package/dist/ai/cost-tracker.js.map +1 -0
- package/dist/ai/index.d.ts +16 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +13 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/rate-limiter.d.ts +16 -0
- package/dist/ai/rate-limiter.d.ts.map +1 -0
- package/dist/ai/rate-limiter.js +51 -0
- package/dist/ai/rate-limiter.js.map +1 -0
- package/dist/ai/rules/index.d.ts +11 -0
- package/dist/ai/rules/index.d.ts.map +1 -0
- package/dist/ai/rules/index.js +57 -0
- package/dist/ai/rules/index.js.map +1 -0
- package/dist/ai/rules/prompts/audit-logging.d.ts +7 -0
- package/dist/ai/rules/prompts/audit-logging.d.ts.map +1 -0
- package/dist/ai/rules/prompts/audit-logging.js +65 -0
- package/dist/ai/rules/prompts/audit-logging.js.map +1 -0
- package/dist/ai/rules/prompts/data-retention.d.ts +7 -0
- package/dist/ai/rules/prompts/data-retention.d.ts.map +1 -0
- package/dist/ai/rules/prompts/data-retention.js +60 -0
- package/dist/ai/rules/prompts/data-retention.js.map +1 -0
- package/dist/ai/rules/prompts/minimum-access.d.ts +7 -0
- package/dist/ai/rules/prompts/minimum-access.d.ts.map +1 -0
- package/dist/ai/rules/prompts/minimum-access.js +53 -0
- package/dist/ai/rules/prompts/minimum-access.js.map +1 -0
- package/dist/ai/rules/prompts/phi-encryption.d.ts +7 -0
- package/dist/ai/rules/prompts/phi-encryption.d.ts.map +1 -0
- package/dist/ai/rules/prompts/phi-encryption.js +60 -0
- package/dist/ai/rules/prompts/phi-encryption.js.map +1 -0
- package/dist/ai/rules/prompts/rbac-check.d.ts +7 -0
- package/dist/ai/rules/prompts/rbac-check.d.ts.map +1 -0
- package/dist/ai/rules/prompts/rbac-check.js +61 -0
- package/dist/ai/rules/prompts/rbac-check.js.map +1 -0
- package/dist/ai/rules/prompts/session-management.d.ts +7 -0
- package/dist/ai/rules/prompts/session-management.d.ts.map +1 -0
- package/dist/ai/rules/prompts/session-management.js +62 -0
- package/dist/ai/rules/prompts/session-management.js.map +1 -0
- package/dist/ai/rules/rule-runner.d.ts +36 -0
- package/dist/ai/rules/rule-runner.d.ts.map +1 -0
- package/dist/ai/rules/rule-runner.js +117 -0
- package/dist/ai/rules/rule-runner.js.map +1 -0
- package/dist/ai/rules/triage.d.ts +11 -0
- package/dist/ai/rules/triage.d.ts.map +1 -0
- package/dist/ai/rules/triage.js +107 -0
- package/dist/ai/rules/triage.js.map +1 -0
- package/dist/ai/rules/types.d.ts +33 -0
- package/dist/ai/rules/types.d.ts.map +1 -0
- package/dist/ai/rules/types.js +5 -0
- package/dist/ai/rules/types.js.map +1 -0
- package/dist/ai/sanitizer.d.ts +21 -0
- package/dist/ai/sanitizer.d.ts.map +1 -0
- package/dist/ai/sanitizer.js +81 -0
- package/dist/ai/sanitizer.js.map +1 -0
- package/dist/ai/scanner.d.ts +31 -0
- package/dist/ai/scanner.d.ts.map +1 -0
- package/dist/ai/scanner.js +93 -0
- package/dist/ai/scanner.js.map +1 -0
- package/dist/cli.js +97 -0
- package/dist/cli.js.map +1 -1
- package/dist/scan.d.ts.map +1 -1
- package/dist/scan.js +33 -0
- package/dist/scan.js.map +1 -1
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -15,6 +15,7 @@ vlayer is a CLI tool that scans your codebase for HIPAA compliance issues. It's
|
|
|
15
15
|
|
|
16
16
|
**Key capabilities:**
|
|
17
17
|
- Scan for 50+ security vulnerabilities and PHI exposure patterns
|
|
18
|
+
- **AI-powered analysis** with Claude API for complex violations and false positive reduction
|
|
18
19
|
- Auto-fix common issues with one command
|
|
19
20
|
- Generate professional audit reports (HTML, PDF, JSON)
|
|
20
21
|
- Detect your tech stack and provide tailored recommendations
|
|
@@ -50,30 +51,64 @@ node dist/cli.js report /path/to/project -o audit-report.html
|
|
|
50
51
|
|
|
51
52
|
---
|
|
52
53
|
|
|
53
|
-
## 🌐
|
|
54
|
+
## 🌐 VLayer Ecosystem
|
|
54
55
|
|
|
55
|
-
**
|
|
56
|
+
**Dashboard**: [https://app.vlayer.app](https://app.vlayer.app) - Compliance monitoring platform
|
|
57
|
+
**Playground**: [https://play.vlayer.app](https://play.vlayer.app) - Try vlayer in your browser
|
|
58
|
+
**Documentation**: [https://docs.vlayer.app](https://docs.vlayer.app) - Complete guides and API reference
|
|
59
|
+
**Landing Page**: [https://vlayer.app](https://vlayer.app) - Marketing site
|
|
56
60
|
|
|
57
|
-
|
|
61
|
+
Enterprise-grade HIPAA compliance monitoring platform for tracking violations, compliance scores, and generating audit reports.
|
|
58
62
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
-
|
|
63
|
-
-
|
|
64
|
-
-
|
|
65
|
-
|
|
66
|
-
**
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
63
|
+
### Design
|
|
64
|
+
|
|
65
|
+
**Professional Enterprise UI:**
|
|
66
|
+
- 🎨 **Dark Navy Theme** - Professional color palette (#0A1628, #0F172A) with emerald/teal accents
|
|
67
|
+
- 📐 **Fixed Sidebar Navigation** - Icon-based menu with VLayer branding and system status
|
|
68
|
+
- 💎 **Glassmorphism Effects** - Gradient cards with subtle shadows and transparency
|
|
69
|
+
- 🎯 **Circular Progress Gauges** - Animated SVG gauges for compliance scores (0-100)
|
|
70
|
+
- 🏷️ **Status Badges** - Color-coded indicators (Compliant/At Risk/Critical)
|
|
71
|
+
- ⚡ **Smooth Transitions** - Hover effects and state changes with professional animations
|
|
72
|
+
|
|
73
|
+
### Features
|
|
74
|
+
|
|
75
|
+
- 🔐 **Supabase Authentication** - Secure email/password authentication with session management
|
|
76
|
+
- 📊 **Visual Compliance Dashboard** - 4-metric overview with real-time scores and status distribution
|
|
77
|
+
- 📈 **Historical Score Tracking** - Interactive charts showing compliance trends over time
|
|
78
|
+
- 🗂️ **Multi-Project Management** - Monitor unlimited projects with inline progress indicators
|
|
79
|
+
- 🔍 **Detailed Findings View** - Filter by severity with comprehensive issue breakdowns
|
|
80
|
+
- 📋 **Executive Summaries** - Professional reports with grade assignments (A-F)
|
|
81
|
+
- 🎨 **Enterprise Tables** - Sortable project lists with circular scores and status badges
|
|
82
|
+
- 📱 **Responsive Design** - Optimized for desktop, tablet, and mobile devices
|
|
83
|
+
- 👤 **User Management** - User profiles with logout functionality in sidebar
|
|
84
|
+
|
|
85
|
+
### Quick Start
|
|
86
|
+
|
|
87
|
+
1. **Create Account**: Sign up at [app.vlayer.app/signup](https://app.vlayer.app/signup) with your email
|
|
88
|
+
2. **Login**: Access the dashboard at [app.vlayer.app](https://app.vlayer.app)
|
|
89
|
+
3. **Create Project**: Click "+ New Project" and enter your project details
|
|
90
|
+
4. **Run Scan**: Execute a compliance scan on your codebase
|
|
70
91
|
```bash
|
|
71
|
-
|
|
92
|
+
node dist/cli.js scan ./src --format json --output scan.json
|
|
93
|
+
```
|
|
94
|
+
5. **Upload Results**: Send scan data to your project via API
|
|
95
|
+
```bash
|
|
96
|
+
curl -X POST https://app.vlayer.app/api/projects/{projectId}/scans \
|
|
72
97
|
-H "Content-Type: application/json" \
|
|
73
98
|
-d @scan.json
|
|
74
99
|
```
|
|
75
100
|
|
|
76
|
-
|
|
101
|
+
### Demo Data
|
|
102
|
+
|
|
103
|
+
The dashboard includes 4 demo projects with realistic compliance data:
|
|
104
|
+
- **HealthCare Portal** - 92/100 (Grade A - Excellent)
|
|
105
|
+
- **Telemedicine API** - 78/100 (Grade C - Fair)
|
|
106
|
+
- **Insurance Claims System** - 56/100 (Grade F - Critical)
|
|
107
|
+
- **Mobile Health App** - 95/100 (Grade A - Excellent)
|
|
108
|
+
|
|
109
|
+
### API & Documentation
|
|
110
|
+
|
|
111
|
+
See [dashboard/README.md](dashboard/README.md) for complete API documentation and deployment instructions.
|
|
77
112
|
|
|
78
113
|
---
|
|
79
114
|
|
|
@@ -371,6 +406,96 @@ node dist/cli.js audit ./my-app --generate-report --org "Healthcare Inc" --audit
|
|
|
371
406
|
|
|
372
407
|
---
|
|
373
408
|
|
|
409
|
+
### 6. AI-Powered Scanning (Beta)
|
|
410
|
+
|
|
411
|
+
**Reduce false positives and catch complex violations with Claude AI.**
|
|
412
|
+
|
|
413
|
+
vlayer now includes optional AI-powered analysis using Anthropic's Claude API:
|
|
414
|
+
|
|
415
|
+
#### Features
|
|
416
|
+
|
|
417
|
+
- **🤖 LLM-Powered Rules**: 6 specialized AI rules for detecting complex HIPAA violations
|
|
418
|
+
- **🎯 AI Triage**: Automatically classify findings to reduce false positives by 50%+
|
|
419
|
+
- **🔒 PHI Scrubbing**: All code is sanitized before sending to the LLM (HIPAA-safe)
|
|
420
|
+
- **💰 Cost Control**: Budget limits, caching, and rate limiting built-in
|
|
421
|
+
- **📊 Confidence Scores**: AI provides reasoning and confidence for each finding
|
|
422
|
+
|
|
423
|
+
#### Quick Start
|
|
424
|
+
|
|
425
|
+
```bash
|
|
426
|
+
# Set your API key
|
|
427
|
+
export ANTHROPIC_API_KEY="sk-ant-..."
|
|
428
|
+
|
|
429
|
+
# Run AI-powered scan (default: 50¢ budget)
|
|
430
|
+
node dist/cli.js ai-scan ./my-app
|
|
431
|
+
|
|
432
|
+
# Adjust budget
|
|
433
|
+
node dist/cli.js ai-scan ./my-app --budget 100
|
|
434
|
+
|
|
435
|
+
# Run LLM rules only (skip triage)
|
|
436
|
+
node dist/cli.js ai-scan ./my-app --rules-only
|
|
437
|
+
|
|
438
|
+
# Enable AI triage in regular scan
|
|
439
|
+
node dist/cli.js scan ./my-app # AI triage runs automatically if API key is set
|
|
440
|
+
|
|
441
|
+
# Disable AI features
|
|
442
|
+
node dist/cli.js scan ./my-app --no-ai
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
#### AI Rules
|
|
446
|
+
|
|
447
|
+
The AI scanner includes 6 specialized rules:
|
|
448
|
+
|
|
449
|
+
| Rule ID | Name | Detects |
|
|
450
|
+
|---------|------|---------|
|
|
451
|
+
| **HIPAA-PHI-003** | Minimum Necessary Access | APIs returning more PHI than needed (SELECT * violations) |
|
|
452
|
+
| **HIPAA-SEC-001** | PHI Encryption | Unencrypted PHI in transit or at rest |
|
|
453
|
+
| **HIPAA-ACCESS-001** | Role-Based Access Control | Missing auth checks, hardcoded roles, IDOR vulnerabilities |
|
|
454
|
+
| **HIPAA-AUDIT-001** | Audit Logging | PHI operations without proper audit trails |
|
|
455
|
+
| **HIPAA-RETENTION-001** | Data Retention | Improper deletion, missing retention policies |
|
|
456
|
+
| **HIPAA-AUTH-001** | Session Management | Weak session configs, missing timeouts |
|
|
457
|
+
|
|
458
|
+
#### Configuration
|
|
459
|
+
|
|
460
|
+
Add AI settings to `.vlayerrc.json`:
|
|
461
|
+
|
|
462
|
+
```json
|
|
463
|
+
{
|
|
464
|
+
"ai": {
|
|
465
|
+
"enabled": true,
|
|
466
|
+
"enableTriage": true,
|
|
467
|
+
"enableLLMRules": true,
|
|
468
|
+
"filterFalsePositives": true,
|
|
469
|
+
"budgetCents": 50
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
#### Cost & Performance
|
|
475
|
+
|
|
476
|
+
- **Typical scan**: 5-20 API calls, $0.10-$0.50
|
|
477
|
+
- **Caching**: Results cached for 24 hours by file hash
|
|
478
|
+
- **Rate limiting**: Max 20 calls/minute, 50 calls/scan
|
|
479
|
+
- **PHI protection**: All sensitive data scrubbed before API call
|
|
480
|
+
|
|
481
|
+
**Example output:**
|
|
482
|
+
```
|
|
483
|
+
🤖 Starting AI-powered HIPAA scan...
|
|
484
|
+
🔒 Scrubbed 3 PHI patterns from src/api/patients.ts
|
|
485
|
+
📋 Running 6 LLM-powered rules...
|
|
486
|
+
✅ AI scan complete: 12 findings, 48¢
|
|
487
|
+
|
|
488
|
+
AI Scan Summary:
|
|
489
|
+
Files scanned: 8
|
|
490
|
+
AI findings: 12
|
|
491
|
+
AI calls made: 18
|
|
492
|
+
Cost: 48¢
|
|
493
|
+
Critical: 2
|
|
494
|
+
High: 5
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
---
|
|
498
|
+
|
|
374
499
|
## Report Examples
|
|
375
500
|
|
|
376
501
|
### HTML Report
|
|
@@ -496,13 +621,41 @@ Each finding maps to specific HIPAA regulations:
|
|
|
496
621
|
## Roadmap
|
|
497
622
|
|
|
498
623
|
### Recently Completed ✅
|
|
499
|
-
- [x] **Phase
|
|
624
|
+
- [x] **Phase 4E: Authentication & User Management**
|
|
625
|
+
- [x] Supabase Auth integration
|
|
626
|
+
- [x] Email/password authentication flow
|
|
627
|
+
- [x] Login and signup pages with dark theme
|
|
628
|
+
- [x] Protected routes via Next.js middleware
|
|
629
|
+
- [x] User session management
|
|
630
|
+
- [x] User profile display in sidebar
|
|
631
|
+
- [x] Logout functionality
|
|
632
|
+
- [x] Environment variables configured in Vercel
|
|
633
|
+
- [x] **Phase 4D: Custom Domain Configuration**
|
|
634
|
+
- [x] Configured custom domains on vlayer.app
|
|
635
|
+
- [x] Dashboard: app.vlayer.app
|
|
636
|
+
- [x] Playground: play.vlayer.app
|
|
637
|
+
- [x] Documentation: docs.vlayer.app
|
|
638
|
+
- [x] Landing page: vlayer.app
|
|
639
|
+
- [x] Automatic DNS configuration via Vercel
|
|
640
|
+
- [x] SSL/TLS certificates provisioned for all domains
|
|
641
|
+
- [x] Updated all cross-project links
|
|
642
|
+
- [x] **Phase 4C: Dashboard Consolidation**
|
|
643
|
+
- [x] Moved landing page to separate repo ([vlayer-website](https://github.com/Francosimon53/vlayer-website))
|
|
644
|
+
- [x] Dashboard now at root route (/) instead of /dashboard
|
|
645
|
+
- [x] Simplified route structure (/, /projects, /projects/[id])
|
|
646
|
+
- [x] Removed route groups for cleaner app organization
|
|
647
|
+
- [x] Dashboard-focused application architecture
|
|
648
|
+
- [x] **Phase 4A: Web Dashboard (Enterprise Redesign)**
|
|
500
649
|
- [x] Next.js dashboard deployed to Vercel
|
|
650
|
+
- [x] Enterprise-grade dark navy theme with emerald accents
|
|
651
|
+
- [x] Fixed sidebar navigation with VLayer branding
|
|
652
|
+
- [x] Circular progress gauges with animations
|
|
501
653
|
- [x] Multi-project management with REST API
|
|
502
|
-
- [x]
|
|
503
|
-
- [x] Historical score tracking
|
|
504
|
-
- [x]
|
|
505
|
-
- [x]
|
|
654
|
+
- [x] Status badges (Compliant/At Risk/Critical)
|
|
655
|
+
- [x] Historical score tracking with visual charts
|
|
656
|
+
- [x] Demo data with 4 realistic projects
|
|
657
|
+
- [x] Glassmorphism effects and professional shadows
|
|
658
|
+
- [x] Responsive design optimized for all devices
|
|
506
659
|
- [x] **Phase 3B: Dashboard & Compliance Score**
|
|
507
660
|
- [x] HIPAA Compliance Score (0-100) with severity weighting
|
|
508
661
|
- [x] Enhanced HTML reports with visual gauge
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Cache - Cache results by file hash
|
|
3
|
+
*/
|
|
4
|
+
export declare class AICache {
|
|
5
|
+
private cacheDir;
|
|
6
|
+
private ttlMs;
|
|
7
|
+
constructor();
|
|
8
|
+
ensureCacheDir(): Promise<void>;
|
|
9
|
+
getFileHash(content: string): string;
|
|
10
|
+
getCacheKey(fileHash: string, ruleId: string): string;
|
|
11
|
+
get(fileContent: string, ruleId: string): Promise<any | null>;
|
|
12
|
+
set(fileContent: string, ruleId: string, result: any): Promise<void>;
|
|
13
|
+
clear(): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/ai/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAeH,qBAAa,OAAO;IAClB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAAS;;IAOhB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAQrC,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAIpC,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IAI/C,GAAG,CACP,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IA2BhB,GAAG,CACP,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,GAAG,GACV,OAAO,CAAC,IAAI,CAAC;IAqBV,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAO7B"}
|
package/dist/ai/cache.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Cache - Cache results by file hash
|
|
3
|
+
*/
|
|
4
|
+
import * as crypto from 'crypto';
|
|
5
|
+
import * as fs from 'fs/promises';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
import { AI_CONFIG } from './config.js';
|
|
8
|
+
export class AICache {
|
|
9
|
+
cacheDir;
|
|
10
|
+
ttlMs;
|
|
11
|
+
constructor() {
|
|
12
|
+
this.cacheDir = AI_CONFIG.cache.directory;
|
|
13
|
+
this.ttlMs = AI_CONFIG.cache.ttlHours * 60 * 60 * 1000;
|
|
14
|
+
}
|
|
15
|
+
async ensureCacheDir() {
|
|
16
|
+
try {
|
|
17
|
+
await fs.mkdir(this.cacheDir, { recursive: true });
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
// Directory might already exist
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
getFileHash(content) {
|
|
24
|
+
return crypto.createHash('sha256').update(content).digest('hex');
|
|
25
|
+
}
|
|
26
|
+
getCacheKey(fileHash, ruleId) {
|
|
27
|
+
return `${fileHash}-${ruleId}.json`;
|
|
28
|
+
}
|
|
29
|
+
async get(fileContent, ruleId) {
|
|
30
|
+
if (!AI_CONFIG.cache.enabled) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
await this.ensureCacheDir();
|
|
34
|
+
const fileHash = this.getFileHash(fileContent);
|
|
35
|
+
const cacheKey = this.getCacheKey(fileHash, ruleId);
|
|
36
|
+
const cachePath = path.join(this.cacheDir, cacheKey);
|
|
37
|
+
try {
|
|
38
|
+
const data = await fs.readFile(cachePath, 'utf-8');
|
|
39
|
+
const entry = JSON.parse(data);
|
|
40
|
+
// Check if cache is expired
|
|
41
|
+
const age = Date.now() - entry.timestamp;
|
|
42
|
+
if (age > this.ttlMs) {
|
|
43
|
+
await fs.unlink(cachePath); // Delete expired cache
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
return entry.result;
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async set(fileContent, ruleId, result) {
|
|
53
|
+
if (!AI_CONFIG.cache.enabled) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
await this.ensureCacheDir();
|
|
57
|
+
const fileHash = this.getFileHash(fileContent);
|
|
58
|
+
const cacheKey = this.getCacheKey(fileHash, ruleId);
|
|
59
|
+
const cachePath = path.join(this.cacheDir, cacheKey);
|
|
60
|
+
const entry = {
|
|
61
|
+
fileHash,
|
|
62
|
+
ruleId,
|
|
63
|
+
result,
|
|
64
|
+
timestamp: Date.now(),
|
|
65
|
+
ttl: this.ttlMs,
|
|
66
|
+
};
|
|
67
|
+
await fs.writeFile(cachePath, JSON.stringify(entry, null, 2), 'utf-8');
|
|
68
|
+
}
|
|
69
|
+
async clear() {
|
|
70
|
+
await this.ensureCacheDir();
|
|
71
|
+
const files = await fs.readdir(this.cacheDir);
|
|
72
|
+
await Promise.all(files.map((file) => fs.unlink(path.join(this.cacheDir, file))));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/ai/cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anthropic AI Client (singleton)
|
|
3
|
+
*/
|
|
4
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
5
|
+
export declare function getAIClient(): Anthropic;
|
|
6
|
+
export declare function isAIAvailable(): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Reset client (useful for testing)
|
|
9
|
+
*/
|
|
10
|
+
export declare function resetAIClient(): void;
|
|
11
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/ai/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAI1C,wBAAgB,WAAW,IAAI,SAAS,CAavC;AAED,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAEpC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anthropic AI Client (singleton)
|
|
3
|
+
*/
|
|
4
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
5
|
+
let client = null;
|
|
6
|
+
export function getAIClient() {
|
|
7
|
+
if (!client) {
|
|
8
|
+
const apiKey = process.env.ANTHROPIC_API_KEY || process.env.VLAYER_AI_KEY;
|
|
9
|
+
if (!apiKey) {
|
|
10
|
+
throw new Error('AI features require an Anthropic API key.\n' +
|
|
11
|
+
'Set ANTHROPIC_API_KEY or VLAYER_AI_KEY environment variable.\n' +
|
|
12
|
+
'Get your key at: https://console.anthropic.com/settings/keys');
|
|
13
|
+
}
|
|
14
|
+
client = new Anthropic({ apiKey });
|
|
15
|
+
}
|
|
16
|
+
return client;
|
|
17
|
+
}
|
|
18
|
+
export function isAIAvailable() {
|
|
19
|
+
return !!(process.env.ANTHROPIC_API_KEY || process.env.VLAYER_AI_KEY);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Reset client (useful for testing)
|
|
23
|
+
*/
|
|
24
|
+
export function resetAIClient() {
|
|
25
|
+
client = null;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/ai/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAE1C,IAAI,MAAM,GAAqB,IAAI,CAAC;AAEpC,MAAM,UAAU,WAAW;IACzB,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;QAC1E,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CACb,6CAA6C;gBAC3C,gEAAgE;gBAChE,8DAA8D,CACjE,CAAC;QACJ,CAAC;QACD,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;AACxE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,GAAG,IAAI,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Configuration
|
|
3
|
+
*/
|
|
4
|
+
export declare const AI_CONFIG: {
|
|
5
|
+
readonly model: "claude-sonnet-4-20250514";
|
|
6
|
+
readonly maxTokens: 2048;
|
|
7
|
+
readonly temperature: 0.1;
|
|
8
|
+
readonly maxFileSizeBytes: 50000;
|
|
9
|
+
readonly maxConcurrentCalls: 3;
|
|
10
|
+
readonly rateLimit: {
|
|
11
|
+
readonly maxCallsPerMinute: 20;
|
|
12
|
+
readonly maxCallsPerScan: 50;
|
|
13
|
+
};
|
|
14
|
+
readonly budget: {
|
|
15
|
+
readonly defaultMaxCentsPerScan: 50;
|
|
16
|
+
readonly estimatedCostPerCall: 1.5;
|
|
17
|
+
};
|
|
18
|
+
readonly cache: {
|
|
19
|
+
readonly enabled: true;
|
|
20
|
+
readonly directory: ".vlayer/ai-cache";
|
|
21
|
+
readonly ttlHours: 24;
|
|
22
|
+
};
|
|
23
|
+
readonly pricing: {
|
|
24
|
+
readonly inputCostPerMillion: 3;
|
|
25
|
+
readonly outputCostPerMillion: 15;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
export type AIModel = typeof AI_CONFIG.model;
|
|
29
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/ai/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;CAwBZ,CAAC;AAEX,MAAM,MAAM,OAAO,GAAG,OAAO,SAAS,CAAC,KAAK,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Configuration
|
|
3
|
+
*/
|
|
4
|
+
export const AI_CONFIG = {
|
|
5
|
+
model: 'claude-sonnet-4-20250514',
|
|
6
|
+
maxTokens: 2048,
|
|
7
|
+
temperature: 0.1, // Deterministic for security
|
|
8
|
+
maxFileSizeBytes: 50_000, // Don't send files > 50KB
|
|
9
|
+
maxConcurrentCalls: 3,
|
|
10
|
+
rateLimit: {
|
|
11
|
+
maxCallsPerMinute: 20,
|
|
12
|
+
maxCallsPerScan: 50,
|
|
13
|
+
},
|
|
14
|
+
budget: {
|
|
15
|
+
defaultMaxCentsPerScan: 50, // $0.50 default
|
|
16
|
+
estimatedCostPerCall: 1.5, // ~$0.015 per call with Sonnet
|
|
17
|
+
},
|
|
18
|
+
cache: {
|
|
19
|
+
enabled: true,
|
|
20
|
+
directory: '.vlayer/ai-cache',
|
|
21
|
+
ttlHours: 24,
|
|
22
|
+
},
|
|
23
|
+
pricing: {
|
|
24
|
+
// Claude Sonnet 4 pricing (per million tokens)
|
|
25
|
+
inputCostPerMillion: 3.0,
|
|
26
|
+
outputCostPerMillion: 15.0,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/ai/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,KAAK,EAAE,0BAAmC;IAC1C,SAAS,EAAE,IAAI;IACf,WAAW,EAAE,GAAG,EAAE,6BAA6B;IAC/C,gBAAgB,EAAE,MAAM,EAAE,0BAA0B;IACpD,kBAAkB,EAAE,CAAC;IACrB,SAAS,EAAE;QACT,iBAAiB,EAAE,EAAE;QACrB,eAAe,EAAE,EAAE;KACpB;IACD,MAAM,EAAE;QACN,sBAAsB,EAAE,EAAE,EAAE,gBAAgB;QAC5C,oBAAoB,EAAE,GAAG,EAAE,+BAA+B;KAC3D;IACD,KAAK,EAAE;QACL,OAAO,EAAE,IAAI;QACb,SAAS,EAAE,kBAAkB;QAC7B,QAAQ,EAAE,EAAE;KACb;IACD,OAAO,EAAE;QACP,+CAA+C;QAC/C,mBAAmB,EAAE,GAAG;QACxB,oBAAoB,EAAE,IAAI;KAC3B;CACO,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cost Tracker - Track AI API usage and costs
|
|
3
|
+
*/
|
|
4
|
+
export declare class CostTracker {
|
|
5
|
+
private totalInputTokens;
|
|
6
|
+
private totalOutputTokens;
|
|
7
|
+
private totalCalls;
|
|
8
|
+
private budgetCents;
|
|
9
|
+
constructor(budgetCents?: number);
|
|
10
|
+
trackUsage(inputTokens: number, outputTokens: number): void;
|
|
11
|
+
getEstimatedCostCents(): number;
|
|
12
|
+
isOverBudget(): boolean;
|
|
13
|
+
getSummary(): string;
|
|
14
|
+
getEstimate(): string;
|
|
15
|
+
getStats(): {
|
|
16
|
+
totalCalls: number;
|
|
17
|
+
totalInputTokens: number;
|
|
18
|
+
totalOutputTokens: number;
|
|
19
|
+
estimatedCost: number;
|
|
20
|
+
};
|
|
21
|
+
reset(): void;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=cost-tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost-tracker.d.ts","sourceRoot":"","sources":["../../src/ai/cost-tracker.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,qBAAa,WAAW;IACtB,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,WAAW,CAAS;gBAEhB,WAAW,GAAE,MAAgD;IAIzE,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI;IAM3D,qBAAqB,IAAI,MAAM;IAW/B,YAAY,IAAI,OAAO;IAIvB,UAAU,IAAI,MAAM;IAUpB,WAAW,IAAI,MAAM;IAOrB,QAAQ;;;;;;IASR,KAAK,IAAI,IAAI;CAKd"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cost Tracker - Track AI API usage and costs
|
|
3
|
+
*/
|
|
4
|
+
import { AI_CONFIG } from './config.js';
|
|
5
|
+
export class CostTracker {
|
|
6
|
+
totalInputTokens = 0;
|
|
7
|
+
totalOutputTokens = 0;
|
|
8
|
+
totalCalls = 0;
|
|
9
|
+
budgetCents;
|
|
10
|
+
constructor(budgetCents = AI_CONFIG.budget.defaultMaxCentsPerScan) {
|
|
11
|
+
this.budgetCents = budgetCents;
|
|
12
|
+
}
|
|
13
|
+
trackUsage(inputTokens, outputTokens) {
|
|
14
|
+
this.totalInputTokens += inputTokens;
|
|
15
|
+
this.totalOutputTokens += outputTokens;
|
|
16
|
+
this.totalCalls++;
|
|
17
|
+
}
|
|
18
|
+
getEstimatedCostCents() {
|
|
19
|
+
// Sonnet pricing: $3/M input, $15/M output
|
|
20
|
+
const inputCost = (this.totalInputTokens * AI_CONFIG.pricing.inputCostPerMillion) /
|
|
21
|
+
1_000_000;
|
|
22
|
+
const outputCost = (this.totalOutputTokens * AI_CONFIG.pricing.outputCostPerMillion) /
|
|
23
|
+
1_000_000;
|
|
24
|
+
return (inputCost + outputCost) * 100; // Convert to cents
|
|
25
|
+
}
|
|
26
|
+
isOverBudget() {
|
|
27
|
+
return this.getEstimatedCostCents() >= this.budgetCents;
|
|
28
|
+
}
|
|
29
|
+
getSummary() {
|
|
30
|
+
const cost = this.getEstimatedCostCents() / 100;
|
|
31
|
+
return (`AI scan: ${this.totalCalls} calls, ` +
|
|
32
|
+
`${this.totalInputTokens} input tokens, ` +
|
|
33
|
+
`${this.totalOutputTokens} output tokens, ` +
|
|
34
|
+
`~$${cost.toFixed(3)}`);
|
|
35
|
+
}
|
|
36
|
+
getEstimate() {
|
|
37
|
+
const estimatedCalls = this.totalCalls || 1;
|
|
38
|
+
const estimatedCost = (estimatedCalls * AI_CONFIG.budget.estimatedCostPerCall) / 100;
|
|
39
|
+
return `Estimated cost: ~$${estimatedCost.toFixed(3)} (${estimatedCalls} calls)`;
|
|
40
|
+
}
|
|
41
|
+
getStats() {
|
|
42
|
+
return {
|
|
43
|
+
totalCalls: this.totalCalls,
|
|
44
|
+
totalInputTokens: this.totalInputTokens,
|
|
45
|
+
totalOutputTokens: this.totalOutputTokens,
|
|
46
|
+
estimatedCost: this.getEstimatedCostCents(),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
reset() {
|
|
50
|
+
this.totalInputTokens = 0;
|
|
51
|
+
this.totalOutputTokens = 0;
|
|
52
|
+
this.totalCalls = 0;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=cost-tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost-tracker.js","sourceRoot":"","sources":["../../src/ai/cost-tracker.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,OAAO,WAAW;IACd,gBAAgB,GAAG,CAAC,CAAC;IACrB,iBAAiB,GAAG,CAAC,CAAC;IACtB,UAAU,GAAG,CAAC,CAAC;IACf,WAAW,CAAS;IAE5B,YAAY,cAAsB,SAAS,CAAC,MAAM,CAAC,sBAAsB;QACvE,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IACjC,CAAC;IAED,UAAU,CAAC,WAAmB,EAAE,YAAoB;QAClD,IAAI,CAAC,gBAAgB,IAAI,WAAW,CAAC;QACrC,IAAI,CAAC,iBAAiB,IAAI,YAAY,CAAC;QACvC,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;IAED,qBAAqB;QACnB,2CAA2C;QAC3C,MAAM,SAAS,GACb,CAAC,IAAI,CAAC,gBAAgB,GAAG,SAAS,CAAC,OAAO,CAAC,mBAAmB,CAAC;YAC/D,SAAS,CAAC;QACZ,MAAM,UAAU,GACd,CAAC,IAAI,CAAC,iBAAiB,GAAG,SAAS,CAAC,OAAO,CAAC,oBAAoB,CAAC;YACjE,SAAS,CAAC;QACZ,OAAO,CAAC,SAAS,GAAG,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,mBAAmB;IAC5D,CAAC;IAED,YAAY;QACV,OAAO,IAAI,CAAC,qBAAqB,EAAE,IAAI,IAAI,CAAC,WAAW,CAAC;IAC1D,CAAC;IAED,UAAU;QACR,MAAM,IAAI,GAAG,IAAI,CAAC,qBAAqB,EAAE,GAAG,GAAG,CAAC;QAChD,OAAO,CACL,YAAY,IAAI,CAAC,UAAU,UAAU;YACrC,GAAG,IAAI,CAAC,gBAAgB,iBAAiB;YACzC,GAAG,IAAI,CAAC,iBAAiB,kBAAkB;YAC3C,KAAK,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CACvB,CAAC;IACJ,CAAC;IAED,WAAW;QACT,MAAM,cAAc,GAAG,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC;QAC5C,MAAM,aAAa,GACjB,CAAC,cAAc,GAAG,SAAS,CAAC,MAAM,CAAC,oBAAoB,CAAC,GAAG,GAAG,CAAC;QACjE,OAAO,qBAAqB,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,cAAc,SAAS,CAAC;IACnF,CAAC;IAED,QAAQ;QACN,OAAO;YACL,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;YACvC,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;YACzC,aAAa,EAAE,IAAI,CAAC,qBAAqB,EAAE;SAC5C,CAAC;IACJ,CAAC;IAED,KAAK;QACH,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC;QAC1B,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;QAC3B,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;IACtB,CAAC;CACF"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI-Powered HIPAA Scanning
|
|
3
|
+
* Export all AI functionality
|
|
4
|
+
*/
|
|
5
|
+
export { getAIClient, isAIAvailable } from './client.js';
|
|
6
|
+
export { AI_CONFIG } from './config.js';
|
|
7
|
+
export { sanitizeCodeForLLM } from './sanitizer.js';
|
|
8
|
+
export type { SanitizationResult } from './sanitizer.js';
|
|
9
|
+
export { CostTracker } from './cost-tracker.js';
|
|
10
|
+
export { AICache } from './cache.js';
|
|
11
|
+
export { RateLimiter } from './rate-limiter.js';
|
|
12
|
+
export { RuleRunner, triageFinding, triageFindings, AI_RULES, } from './rules/index.js';
|
|
13
|
+
export type { LLMRule, AIFinding, TriagedFinding, TriageClassification, LLMRuleResponse, TriageResponse, } from './rules/index.js';
|
|
14
|
+
export { runAIScan, triageExistingFindings } from './scanner.js';
|
|
15
|
+
export type { AIScanOptions, AIScanResult } from './scanner.js';
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ai/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EACL,UAAU,EACV,aAAa,EACb,cAAc,EACd,QAAQ,GACT,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,OAAO,EACP,SAAS,EACT,cAAc,EACd,oBAAoB,EACpB,eAAe,EACf,cAAc,GACf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACjE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/ai/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI-Powered HIPAA Scanning
|
|
3
|
+
* Export all AI functionality
|
|
4
|
+
*/
|
|
5
|
+
export { getAIClient, isAIAvailable } from './client.js';
|
|
6
|
+
export { AI_CONFIG } from './config.js';
|
|
7
|
+
export { sanitizeCodeForLLM } from './sanitizer.js';
|
|
8
|
+
export { CostTracker } from './cost-tracker.js';
|
|
9
|
+
export { AICache } from './cache.js';
|
|
10
|
+
export { RateLimiter } from './rate-limiter.js';
|
|
11
|
+
export { RuleRunner, triageFinding, triageFindings, AI_RULES, } from './rules/index.js';
|
|
12
|
+
export { runAIScan, triageExistingFindings } from './scanner.js';
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ai/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEpD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EACL,UAAU,EACV,aAAa,EACb,cAAc,EACd,QAAQ,GACT,MAAM,kBAAkB,CAAC;AAS1B,OAAO,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rate Limiter - Prevent exceeding API rate limits
|
|
3
|
+
*/
|
|
4
|
+
export declare class RateLimiter {
|
|
5
|
+
private callTimestamps;
|
|
6
|
+
private totalCalls;
|
|
7
|
+
canMakeCall(): boolean;
|
|
8
|
+
recordCall(): void;
|
|
9
|
+
waitIfNeeded(): Promise<void>;
|
|
10
|
+
reset(): void;
|
|
11
|
+
getStats(): {
|
|
12
|
+
callsThisMinute: number;
|
|
13
|
+
totalCalls: number;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=rate-limiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../src/ai/rate-limiter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,qBAAa,WAAW;IACtB,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,UAAU,CAAK;IAEvB,WAAW,IAAI,OAAO;IAsBtB,UAAU,IAAI,IAAI;IAKZ,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAenC,KAAK,IAAI,IAAI;IAKb,QAAQ,IAAI;QAAE,eAAe,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE;CAM5D"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rate Limiter - Prevent exceeding API rate limits
|
|
3
|
+
*/
|
|
4
|
+
import { AI_CONFIG } from './config.js';
|
|
5
|
+
export class RateLimiter {
|
|
6
|
+
callTimestamps = [];
|
|
7
|
+
totalCalls = 0;
|
|
8
|
+
canMakeCall() {
|
|
9
|
+
const now = Date.now();
|
|
10
|
+
const oneMinuteAgo = now - 60000;
|
|
11
|
+
// Remove timestamps older than 1 minute
|
|
12
|
+
this.callTimestamps = this.callTimestamps.filter((t) => t > oneMinuteAgo);
|
|
13
|
+
// Check per-minute limit
|
|
14
|
+
if (this.callTimestamps.length >= AI_CONFIG.rateLimit.maxCallsPerMinute) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
// Check per-scan limit
|
|
18
|
+
if (this.totalCalls >= AI_CONFIG.rateLimit.maxCallsPerScan) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
recordCall() {
|
|
24
|
+
this.callTimestamps.push(Date.now());
|
|
25
|
+
this.totalCalls++;
|
|
26
|
+
}
|
|
27
|
+
async waitIfNeeded() {
|
|
28
|
+
if (this.canMakeCall()) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
// Wait for the oldest call to expire
|
|
32
|
+
const oldestCall = this.callTimestamps[0];
|
|
33
|
+
if (oldestCall) {
|
|
34
|
+
const waitTime = 60000 - (Date.now() - oldestCall) + 100; // +100ms buffer
|
|
35
|
+
if (waitTime > 0) {
|
|
36
|
+
await new Promise((resolve) => setTimeout(resolve, waitTime));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
reset() {
|
|
41
|
+
this.callTimestamps = [];
|
|
42
|
+
this.totalCalls = 0;
|
|
43
|
+
}
|
|
44
|
+
getStats() {
|
|
45
|
+
const now = Date.now();
|
|
46
|
+
const oneMinuteAgo = now - 60000;
|
|
47
|
+
const callsThisMinute = this.callTimestamps.filter((t) => t > oneMinuteAgo).length;
|
|
48
|
+
return { callsThisMinute, totalCalls: this.totalCalls };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=rate-limiter.js.map
|