@ayurak/aribot-cli 1.0.5 → 1.0.7

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/src/sdk.ts ADDED
@@ -0,0 +1,1017 @@
1
+ /**
2
+ * Aribot Node.js SDK - Economic, Regulatory & Security APIs for Modern Applications
3
+ *
4
+ * Analyze your tech stack. Optimize architecture. Model costs. Identify threats dynamically.
5
+ * APIs that help you build better systems with practical, actionable recommendations.
6
+ *
7
+ * Platform Capabilities:
8
+ * - Advanced Threat Modeling: Multi-framework (STRIDE, PASTA, NIST, Aristiun Framework)
9
+ * - Cloud Security: Real-time CSPM, CNAPP, misconfiguration detection
10
+ * - Living Architecture: Dynamic architecture diagrams with real-time updates
11
+ * - Economic Intelligence: Security ROI, TCO analysis, risk quantification in real dollars
12
+ * - FinOps: Cloud cost optimization, security spend tracking
13
+ * - Compliance: 100+ regulatory standards (SOC2, ISO27001, NIST, PCI-DSS, GDPR, HIPAA, etc.)
14
+ * - Red Team: Automated attack simulations, penetration testing orchestration
15
+ *
16
+ * Usage:
17
+ * import { AribotClient } from '@ayurak/aribot-cli';
18
+ *
19
+ * const client = new AribotClient({ apiKey: 'ak_...' });
20
+ *
21
+ * // Threat Modeling
22
+ * const diagram = await client.threatModeling.upload('architecture.png');
23
+ * const threats = await client.threatModeling.getThreats(diagram.id);
24
+ *
25
+ * // Compliance
26
+ * const assessment = await client.compliance.assess(diagramId, 'SOC2');
27
+ *
28
+ * // Red Team
29
+ * const simulation = await client.redteam.runSimulation(targetId, 'lateral_movement');
30
+ */
31
+
32
+ import * as fs from 'fs';
33
+ import * as path from 'path';
34
+ import * as crypto from 'crypto';
35
+
36
+ const VERSION = '1.0.6';
37
+ const DEFAULT_BASE_URL = 'https://api.aribot.ayurak.com/aribot-api';
38
+
39
+ // =============================================================================
40
+ // TYPES & INTERFACES
41
+ // =============================================================================
42
+
43
+ export interface AribotConfig {
44
+ apiKey?: string;
45
+ baseUrl?: string;
46
+ timeout?: number;
47
+ maxRetries?: number;
48
+ }
49
+
50
+ export interface Diagram {
51
+ id: string;
52
+ name: string;
53
+ filename?: string;
54
+ stage: string;
55
+ threats_count: number;
56
+ created_at: string;
57
+ updated_at?: string;
58
+ }
59
+
60
+ export interface Threat {
61
+ id: string;
62
+ title: string;
63
+ description?: string;
64
+ severity: string;
65
+ category: string;
66
+ stride_category?: string;
67
+ mitigation?: string;
68
+ cvss_score?: number;
69
+ attack_vector?: string;
70
+ }
71
+
72
+ export interface ComplianceAssessment {
73
+ id: string;
74
+ standard: string;
75
+ score: number;
76
+ passed_controls: number;
77
+ failed_controls: number;
78
+ status: string;
79
+ created_at: string;
80
+ }
81
+
82
+ export interface SecurityFinding {
83
+ id: string;
84
+ title: string;
85
+ severity: string;
86
+ resource_type: string;
87
+ resource_id: string;
88
+ policy: string;
89
+ remediation?: string;
90
+ status: string;
91
+ }
92
+
93
+ export interface PaginatedResponse<T> {
94
+ count: number;
95
+ next?: string;
96
+ previous?: string;
97
+ results: T[];
98
+ }
99
+
100
+ // =============================================================================
101
+ // ERRORS
102
+ // =============================================================================
103
+
104
+ export class AribotError extends Error {
105
+ constructor(message: string) {
106
+ super(message);
107
+ this.name = 'AribotError';
108
+ }
109
+ }
110
+
111
+ export class AuthenticationError extends AribotError {
112
+ constructor(message: string = 'Invalid or expired API key') {
113
+ super(message);
114
+ this.name = 'AuthenticationError';
115
+ }
116
+ }
117
+
118
+ export class RateLimitError extends AribotError {
119
+ retryAfter?: number;
120
+
121
+ constructor(message: string = 'Rate limit exceeded', retryAfter?: number) {
122
+ super(message);
123
+ this.name = 'RateLimitError';
124
+ this.retryAfter = retryAfter;
125
+ }
126
+ }
127
+
128
+ export class APIError extends AribotError {
129
+ statusCode?: number;
130
+ response?: any;
131
+
132
+ constructor(message: string, statusCode?: number, response?: any) {
133
+ super(message);
134
+ this.name = 'APIError';
135
+ this.statusCode = statusCode;
136
+ this.response = response;
137
+ }
138
+ }
139
+
140
+ // =============================================================================
141
+ // API CLIENT
142
+ // =============================================================================
143
+
144
+ export class AribotClient {
145
+ private apiKey: string;
146
+ private baseUrl: string;
147
+ private timeout: number;
148
+ private maxRetries: number;
149
+
150
+ // Resource managers
151
+ public threatModeling: ThreatModelingResource;
152
+ public cloudSecurity: CloudSecurityResource;
153
+ public compliance: ComplianceResource;
154
+ public economics: EconomicsResource;
155
+ public finops: FinOpsResource;
156
+ public redteam: RedTeamResource;
157
+ public architecture: ArchitectureResource;
158
+ public user: UserResource;
159
+ public ai: AIResource; // Secure AI usage management
160
+
161
+ // Aliases
162
+ public diagrams: ThreatModelingResource;
163
+
164
+ constructor(config: AribotConfig = {}) {
165
+ this.apiKey = config.apiKey || process.env.ARIBOT_API_KEY || '';
166
+ if (!this.apiKey) {
167
+ throw new AuthenticationError(
168
+ 'API key required. Pass apiKey in config or set ARIBOT_API_KEY env var.'
169
+ );
170
+ }
171
+
172
+ this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, '');
173
+ this.timeout = config.timeout || 60000;
174
+ this.maxRetries = config.maxRetries || 3;
175
+
176
+ // Initialize resources
177
+ this.threatModeling = new ThreatModelingResource(this);
178
+ this.cloudSecurity = new CloudSecurityResource(this);
179
+ this.compliance = new ComplianceResource(this);
180
+ this.economics = new EconomicsResource(this);
181
+ this.finops = new FinOpsResource(this);
182
+ this.redteam = new RedTeamResource(this);
183
+ this.architecture = new ArchitectureResource(this);
184
+ this.user = new UserResource(this);
185
+ this.ai = new AIResource(this);
186
+
187
+ // Aliases
188
+ this.diagrams = this.threatModeling;
189
+ }
190
+
191
+ private getHeaders(contentType: string = 'application/json'): Record<string, string> {
192
+ const headers: Record<string, string> = {
193
+ 'X-API-Key': this.apiKey,
194
+ 'User-Agent': `aribot-sdk/${VERSION} (Node.js)`,
195
+ 'X-Request-ID': crypto.randomBytes(16).toString('base64url'),
196
+ 'X-Request-Timestamp': new Date().toISOString(),
197
+ };
198
+ if (contentType) {
199
+ headers['Content-Type'] = contentType;
200
+ }
201
+ return headers;
202
+ }
203
+
204
+ private getAuthHeader(): Record<string, string> {
205
+ return {
206
+ 'Authorization': `Bearer ${this.apiKey}`,
207
+ 'User-Agent': `aribot-sdk/${VERSION} (Node.js)`,
208
+ 'X-Request-ID': crypto.randomBytes(16).toString('base64url'),
209
+ 'X-Request-Timestamp': new Date().toISOString(),
210
+ };
211
+ }
212
+
213
+ async request<T = any>(
214
+ method: string,
215
+ endpoint: string,
216
+ options: {
217
+ body?: any;
218
+ params?: Record<string, string | number>;
219
+ formData?: FormData;
220
+ } = {}
221
+ ): Promise<T> {
222
+ const fetch = (await import('node-fetch')).default;
223
+ const url = new URL(`${this.baseUrl}${endpoint}`);
224
+
225
+ if (options.params) {
226
+ Object.entries(options.params).forEach(([key, value]) => {
227
+ url.searchParams.set(key, String(value));
228
+ });
229
+ }
230
+
231
+ const headers = options.formData ? this.getAuthHeader() : this.getHeaders();
232
+
233
+ let lastError: Error | null = null;
234
+
235
+ for (let attempt = 0; attempt < this.maxRetries; attempt++) {
236
+ try {
237
+ const requestOptions: any = {
238
+ method,
239
+ headers,
240
+ timeout: this.timeout,
241
+ };
242
+
243
+ if (options.formData) {
244
+ requestOptions.body = options.formData;
245
+ } else if (options.body) {
246
+ requestOptions.body = JSON.stringify(options.body);
247
+ }
248
+
249
+ const response = await fetch(url.toString(), requestOptions);
250
+
251
+ if (response.ok) {
252
+ const contentType = response.headers.get('content-type');
253
+ if (contentType?.includes('application/json')) {
254
+ return await response.json() as T;
255
+ }
256
+ return await response.buffer() as any;
257
+ }
258
+
259
+ if (response.status === 401) {
260
+ throw new AuthenticationError();
261
+ }
262
+
263
+ if (response.status === 403) {
264
+ throw new AuthenticationError('Access denied. Check API key permissions.');
265
+ }
266
+
267
+ if (response.status === 429) {
268
+ const retryAfter = response.headers.get('Retry-After');
269
+ throw new RateLimitError(
270
+ 'Rate limit exceeded',
271
+ retryAfter ? parseInt(retryAfter) : undefined
272
+ );
273
+ }
274
+
275
+ let errorMessage: string;
276
+ try {
277
+ const errorData = await response.json() as any;
278
+ errorMessage = errorData.detail || errorData.message || JSON.stringify(errorData);
279
+ } catch {
280
+ errorMessage = `HTTP ${response.status}`;
281
+ }
282
+
283
+ throw new APIError(errorMessage, response.status);
284
+
285
+ } catch (error: any) {
286
+ lastError = error;
287
+
288
+ if (error instanceof AuthenticationError) {
289
+ throw error;
290
+ }
291
+
292
+ if (error instanceof RateLimitError && error.retryAfter) {
293
+ await this.sleep(error.retryAfter * 1000);
294
+ continue;
295
+ }
296
+
297
+ if (error.code === 'ETIMEDOUT' || error.code === 'ECONNRESET') {
298
+ const sleepTime = Math.pow(2, attempt) * 1000 + Math.random() * 1000;
299
+ await this.sleep(sleepTime);
300
+ continue;
301
+ }
302
+
303
+ throw error;
304
+ }
305
+ }
306
+
307
+ throw lastError || new APIError(`Request failed after ${this.maxRetries} attempts`);
308
+ }
309
+
310
+ private sleep(ms: number): Promise<void> {
311
+ return new Promise(resolve => setTimeout(resolve, ms));
312
+ }
313
+ }
314
+
315
+ // =============================================================================
316
+ // THREAT MODELING RESOURCE
317
+ // =============================================================================
318
+
319
+ class ThreatModelingResource {
320
+ constructor(private client: AribotClient) {}
321
+
322
+ async list(options: { limit?: number; offset?: number } = {}): Promise<PaginatedResponse<Diagram>> {
323
+ return this.client.request('GET', '/v2/threat-modeling/diagrams/', {
324
+ params: { limit: options.limit || 20, offset: options.offset || 0 }
325
+ });
326
+ }
327
+
328
+ async get(diagramId: string): Promise<Diagram> {
329
+ return this.client.request('GET', `/v2/threat-modeling/diagrams/${diagramId}/`);
330
+ }
331
+
332
+ async upload(
333
+ filePath: string,
334
+ options: { name?: string; autoGenerateThreats?: boolean } = {}
335
+ ): Promise<Diagram> {
336
+ const FormData = (await import('form-data')).default;
337
+ const form = new FormData();
338
+
339
+ form.append('file', fs.createReadStream(filePath));
340
+ form.append('name', options.name || path.basename(filePath, path.extname(filePath)));
341
+ form.append('auto_generate_threats', String(options.autoGenerateThreats !== false));
342
+
343
+ return this.client.request('POST', '/v2/threat-modeling/diagrams/upload-analyze/', {
344
+ formData: form as any
345
+ });
346
+ }
347
+
348
+ async getThreats(diagramId: string, options: { severity?: string } = {}): Promise<Threat[]> {
349
+ const data = await this.client.request<any>('GET', `/v2/threat-modeling/diagrams/${diagramId}/threats/`, {
350
+ params: options.severity ? { severity: options.severity } : {}
351
+ });
352
+ return data.threats || data.results || [];
353
+ }
354
+
355
+ async generateThreats(
356
+ diagramId: string,
357
+ options: { waitForCompletion?: boolean; timeout?: number } = {}
358
+ ): Promise<Diagram> {
359
+ await this.client.request('POST', `/v2/threat-modeling/diagrams/${diagramId}/generate-threats/`);
360
+
361
+ if (options.waitForCompletion !== false) {
362
+ const timeout = options.timeout || 120000;
363
+ const start = Date.now();
364
+
365
+ while (Date.now() - start < timeout) {
366
+ await new Promise(r => setTimeout(r, 2000));
367
+ const status = await this.get(diagramId);
368
+ if (status.stage === 'completed') {
369
+ return status;
370
+ }
371
+ }
372
+ }
373
+
374
+ return this.get(diagramId);
375
+ }
376
+
377
+ async export(
378
+ diagramId: string,
379
+ options: { format?: string; outputPath?: string } = {}
380
+ ): Promise<any> {
381
+ const format = options.format || 'json';
382
+ const data = await this.client.request('GET', `/v2/threat-modeling/diagrams/${diagramId}/export/`, {
383
+ params: { format }
384
+ });
385
+
386
+ if (options.outputPath) {
387
+ if (format === 'json') {
388
+ fs.writeFileSync(options.outputPath, JSON.stringify(data, null, 2));
389
+ } else {
390
+ fs.writeFileSync(options.outputPath, data);
391
+ }
392
+ }
393
+
394
+ return data;
395
+ }
396
+ }
397
+
398
+ // =============================================================================
399
+ // CLOUD SECURITY RESOURCE
400
+ // =============================================================================
401
+
402
+ class CloudSecurityResource {
403
+ constructor(private client: AribotClient) {}
404
+
405
+ async scanPosture(cloudProvider?: string): Promise<any> {
406
+ return this.client.request('POST', '/v2/cloud-security/scan/', {
407
+ params: cloudProvider ? { provider: cloudProvider } : {}
408
+ });
409
+ }
410
+
411
+ async getFindings(options: { severity?: string; status?: string; limit?: number } = {}): Promise<SecurityFinding[]> {
412
+ const data = await this.client.request<any>('GET', '/v2/cloud-security/findings/', {
413
+ params: {
414
+ status: options.status || 'open',
415
+ limit: options.limit || 50,
416
+ ...(options.severity && { severity: options.severity })
417
+ }
418
+ });
419
+ return data.results || data.findings || [];
420
+ }
421
+
422
+ async getDashboard(): Promise<any> {
423
+ return this.client.request('GET', '/v2/cloud-security/dashboard/');
424
+ }
425
+
426
+ async remediate(findingId: string, autoFix: boolean = false): Promise<any> {
427
+ return this.client.request('POST', `/v2/cloud-security/findings/${findingId}/remediate/`, {
428
+ body: { auto_fix: autoFix }
429
+ });
430
+ }
431
+ }
432
+
433
+ // =============================================================================
434
+ // COMPLIANCE RESOURCE
435
+ // =============================================================================
436
+
437
+ class ComplianceResource {
438
+ // 100+ supported standards
439
+ static SUPPORTED_STANDARDS = [
440
+ 'SOC2', 'ISO27001', 'ISO27017', 'ISO27018', 'ISO22301',
441
+ 'NIST-CSF', 'NIST-800-53', 'NIST-800-171',
442
+ 'PCI-DSS', 'PCI-DSS-4.0',
443
+ 'GDPR', 'CCPA', 'LGPD', 'PIPEDA',
444
+ 'HIPAA', 'HITRUST',
445
+ 'FedRAMP-Low', 'FedRAMP-Moderate', 'FedRAMP-High',
446
+ 'CIS-AWS', 'CIS-Azure', 'CIS-GCP', 'CIS-Kubernetes',
447
+ 'SOX', 'GLBA', 'FISMA',
448
+ 'CSA-CCM', 'CSA-STAR',
449
+ 'MITRE-ATT&CK', 'OWASP-TOP-10',
450
+ ];
451
+
452
+ constructor(private client: AribotClient) {}
453
+
454
+ async listStandards(): Promise<any[]> {
455
+ return this.client.request('GET', '/v2/compliances/custom-standards/');
456
+ }
457
+
458
+ async assess(
459
+ diagramId: string,
460
+ standard: string = 'SOC2',
461
+ includeRecommendations: boolean = true
462
+ ): Promise<ComplianceAssessment> {
463
+ return this.client.request('POST', '/v2/compliances/assess_diagram/', {
464
+ body: {
465
+ diagram_id: diagramId,
466
+ standard,
467
+ include_recommendations: includeRecommendations
468
+ }
469
+ });
470
+ }
471
+
472
+ async getAssessment(assessmentId: string): Promise<ComplianceAssessment> {
473
+ return this.client.request('GET', `/v2/compliances/compliance-reports/${assessmentId}/`);
474
+ }
475
+
476
+ async listReports(limit: number = 20): Promise<ComplianceAssessment[]> {
477
+ const data = await this.client.request<any>('GET', '/v2/compliances/reports/', {
478
+ params: { limit }
479
+ });
480
+ return data.results || [];
481
+ }
482
+
483
+ async runScan(
484
+ targetId: string,
485
+ standards: string[] = ['SOC2', 'ISO27001'],
486
+ scanType: string = 'comprehensive'
487
+ ): Promise<any> {
488
+ return this.client.request('POST', '/v2/compliances/scan/', {
489
+ body: { target_id: targetId, standards, scan_type: scanType }
490
+ });
491
+ }
492
+
493
+ async getRemediation(findingId: string): Promise<any> {
494
+ return this.client.request('GET', `/v2/compliances/remediation/${findingId}/`);
495
+ }
496
+
497
+ async getDashboard(): Promise<any> {
498
+ return this.client.request('GET', '/v2/compliances/dashboard/trends/');
499
+ }
500
+ }
501
+
502
+ // =============================================================================
503
+ // ECONOMICS INTELLIGENCE RESOURCE
504
+ // =============================================================================
505
+
506
+ class EconomicsResource {
507
+ constructor(private client: AribotClient) {}
508
+
509
+ async calculateROI(
510
+ securityInvestment: number,
511
+ riskReductionPercent: number = 50,
512
+ timeHorizonYears: number = 3
513
+ ): Promise<any> {
514
+ return this.client.request('POST', '/v2/economic-intelligence/v2/roi/create/', {
515
+ body: {
516
+ investment: securityInvestment,
517
+ risk_reduction: riskReductionPercent,
518
+ time_horizon: timeHorizonYears
519
+ }
520
+ });
521
+ }
522
+
523
+ async calculateTCO(
524
+ cloudProvider: string,
525
+ workloadType: string = 'general',
526
+ durationMonths: number = 36
527
+ ): Promise<any> {
528
+ return this.client.request('POST', '/v2/economic-intelligence/tco/', {
529
+ body: {
530
+ provider: cloudProvider,
531
+ workload_type: workloadType,
532
+ duration_months: durationMonths
533
+ }
534
+ });
535
+ }
536
+
537
+ async analyzeCosts(diagramId: string): Promise<any> {
538
+ return this.client.request('POST', '/v2/economic-intelligence/analyze/', {
539
+ body: { diagram_id: diagramId }
540
+ });
541
+ }
542
+
543
+ async getMarketIntelligence(): Promise<any> {
544
+ return this.client.request('GET', '/v2/economic-intelligence/v2/intelligence/');
545
+ }
546
+
547
+ async getDashboard(): Promise<any> {
548
+ return this.client.request('GET', '/v2/economic-intelligence/v2/dashboard/');
549
+ }
550
+
551
+ async createForecast(months: number = 12): Promise<any> {
552
+ return this.client.request('POST', '/v2/economic-intelligence/v2/forecast/create/', {
553
+ body: { forecast_months: months }
554
+ });
555
+ }
556
+ }
557
+
558
+ // =============================================================================
559
+ // FINOPS RESOURCE
560
+ // =============================================================================
561
+
562
+ class FinOpsResource {
563
+ constructor(private client: AribotClient) {}
564
+
565
+ async getCloudCosts(options: { provider?: string; period?: string } = {}): Promise<any> {
566
+ return this.client.request('GET', '/v2/finops/costs/', {
567
+ params: {
568
+ period: options.period || 'month',
569
+ ...(options.provider && { provider: options.provider })
570
+ }
571
+ });
572
+ }
573
+
574
+ async getSecuritySpend(): Promise<any> {
575
+ return this.client.request('GET', '/v2/finops/security-spend/');
576
+ }
577
+
578
+ async getOptimizationRecommendations(): Promise<any[]> {
579
+ const data = await this.client.request<any>('GET', '/v2/finops/recommendations/');
580
+ return data.recommendations || [];
581
+ }
582
+
583
+ async getPricing(service: string, provider: string = 'aws'): Promise<any> {
584
+ return this.client.request('GET', '/v2/economic-intelligence/pricing/', {
585
+ params: { service, provider }
586
+ });
587
+ }
588
+ }
589
+
590
+ // =============================================================================
591
+ // RED TEAM RESOURCE
592
+ // =============================================================================
593
+
594
+ class RedTeamResource {
595
+ static ATTACK_TYPES = [
596
+ 'lateral_movement',
597
+ 'privilege_escalation',
598
+ 'data_exfiltration',
599
+ 'ransomware',
600
+ 'supply_chain',
601
+ 'insider_threat',
602
+ 'credential_theft',
603
+ 'api_abuse',
604
+ ];
605
+
606
+ constructor(private client: AribotClient) {}
607
+
608
+ async runSimulation(
609
+ targetId: string,
610
+ attackType: string = 'lateral_movement',
611
+ intensity: string = 'medium'
612
+ ): Promise<any> {
613
+ if (!RedTeamResource.ATTACK_TYPES.includes(attackType)) {
614
+ throw new AribotError(`Invalid attack type. Choose from: ${RedTeamResource.ATTACK_TYPES.join(', ')}`);
615
+ }
616
+
617
+ return this.client.request('POST', '/v2/redteam/simulate/', {
618
+ body: {
619
+ target_id: targetId,
620
+ attack_type: attackType,
621
+ intensity
622
+ }
623
+ });
624
+ }
625
+
626
+ async getAttackPaths(diagramId: string): Promise<any[]> {
627
+ const data = await this.client.request<any>('GET', `/v2/threat-modeling/diagrams/${diagramId}/attack-paths/`);
628
+ return data.attack_paths || [];
629
+ }
630
+
631
+ async listSimulations(limit: number = 20): Promise<any[]> {
632
+ const data = await this.client.request<any>('GET', '/v2/redteam/simulations/', {
633
+ params: { limit }
634
+ });
635
+ return data.results || [];
636
+ }
637
+
638
+ async getSimulation(simulationId: string): Promise<any> {
639
+ return this.client.request('GET', `/v2/redteam/simulations/${simulationId}/`);
640
+ }
641
+ }
642
+
643
+ // =============================================================================
644
+ // ARCHITECTURE RESOURCE
645
+ // =============================================================================
646
+
647
+ class ArchitectureResource {
648
+ constructor(private client: AribotClient) {}
649
+
650
+ async listComponents(diagramId: string): Promise<any[]> {
651
+ const data = await this.client.request<any>('GET', `/v2/threat-modeling/diagrams/${diagramId}/components/`);
652
+ return data.components || data.results || [];
653
+ }
654
+
655
+ async getComponent(diagramId: string, componentId: string): Promise<any> {
656
+ return this.client.request('GET', `/v2/threat-modeling/diagrams/${diagramId}/components/${componentId}/`);
657
+ }
658
+
659
+ async updateComponent(diagramId: string, componentId: string, updates: any): Promise<any> {
660
+ return this.client.request('PATCH', `/v2/threat-modeling/diagrams/${diagramId}/components/${componentId}/`, {
661
+ body: updates
662
+ });
663
+ }
664
+
665
+ async getConnections(diagramId: string): Promise<any[]> {
666
+ const data = await this.client.request<any>('GET', `/v2/threat-modeling/diagrams/${diagramId}/connections/`);
667
+ return data.connections || data.results || [];
668
+ }
669
+ }
670
+
671
+ // =============================================================================
672
+ // USER RESOURCE
673
+ // =============================================================================
674
+
675
+ class UserResource {
676
+ constructor(private client: AribotClient) {}
677
+
678
+ async me(): Promise<any> {
679
+ return this.client.request('GET', '/v1/users/me/');
680
+ }
681
+
682
+ async apiKeys(): Promise<any[]> {
683
+ return this.client.request('GET', '/v1/developer/api-keys/');
684
+ }
685
+
686
+ async getUsage(): Promise<any> {
687
+ return this.client.request('GET', '/v1/developer/usage/');
688
+ }
689
+
690
+ async getRateLimits(): Promise<any> {
691
+ return this.client.request('GET', '/v1/developer/rate-limits/');
692
+ }
693
+ }
694
+
695
+ // =============================================================================
696
+ // AI RESOURCE - Secure AI Usage Management
697
+ // =============================================================================
698
+
699
+ class AIResource {
700
+ /**
701
+ * Secure AI usage management and configuration.
702
+ *
703
+ * Features:
704
+ * - AI model selection and configuration
705
+ * - Usage tracking and quotas
706
+ * - Cost monitoring for AI operations
707
+ * - Secure prompt/response handling
708
+ * - AI processing queue management
709
+ *
710
+ * Security:
711
+ * - All AI requests are signed and authenticated
712
+ * - Sensitive data is sanitized before AI processing
713
+ * - Usage is tracked per API key for audit compliance
714
+ * - Rate limiting prevents abuse
715
+ */
716
+
717
+ static AI_OPERATIONS = [
718
+ 'threat_analysis',
719
+ 'diagram_parsing',
720
+ 'compliance_mapping',
721
+ 'risk_scoring',
722
+ 'attack_path_analysis',
723
+ 'remediation_generation',
724
+ 'architecture_optimization',
725
+ ];
726
+
727
+ static MODEL_TIERS = ['standard', 'advanced', 'enterprise'];
728
+
729
+ constructor(private client: AribotClient) {}
730
+
731
+ /**
732
+ * Get AI usage statistics for the current billing period.
733
+ */
734
+ async getUsage(): Promise<any> {
735
+ return this.client.request('GET', '/v2/ai/usage/');
736
+ }
737
+
738
+ /**
739
+ * Get current AI quota and limits.
740
+ */
741
+ async getQuota(): Promise<any> {
742
+ return this.client.request('GET', '/v2/ai/quota/');
743
+ }
744
+
745
+ /**
746
+ * List available AI models for your subscription tier.
747
+ */
748
+ async getModels(): Promise<any[]> {
749
+ return this.client.request('GET', '/v2/ai/models/');
750
+ }
751
+
752
+ /**
753
+ * Configure AI settings for your account.
754
+ */
755
+ async configure(options: {
756
+ modelTier?: string;
757
+ maxTokens?: number;
758
+ temperature?: number;
759
+ enableCaching?: boolean;
760
+ } = {}): Promise<any> {
761
+ const modelTier = options.modelTier || 'standard';
762
+ if (!AIResource.MODEL_TIERS.includes(modelTier)) {
763
+ throw new AribotError(`Invalid model tier. Choose from: ${AIResource.MODEL_TIERS.join(', ')}`);
764
+ }
765
+
766
+ return this.client.request('POST', '/v2/ai/configure/', {
767
+ body: {
768
+ model_tier: modelTier,
769
+ max_tokens: options.maxTokens || 4000,
770
+ temperature: options.temperature || 0.7,
771
+ enable_caching: options.enableCaching !== false,
772
+ }
773
+ });
774
+ }
775
+
776
+ /**
777
+ * Run AI analysis on content.
778
+ */
779
+ async analyze(
780
+ content: string,
781
+ options: {
782
+ operation?: string;
783
+ context?: Record<string, any>;
784
+ sanitizePii?: boolean;
785
+ } = {}
786
+ ): Promise<any> {
787
+ const operation = options.operation || 'threat_analysis';
788
+ if (!AIResource.AI_OPERATIONS.includes(operation)) {
789
+ throw new AribotError(`Invalid operation. Choose from: ${AIResource.AI_OPERATIONS.join(', ')}`);
790
+ }
791
+
792
+ return this.client.request('POST', '/v2/ai/analyze/', {
793
+ body: {
794
+ content,
795
+ operation,
796
+ context: options.context || {},
797
+ sanitize_pii: options.sanitizePii !== false,
798
+ }
799
+ });
800
+ }
801
+
802
+ /**
803
+ * Get status of pending AI processing jobs.
804
+ */
805
+ async getQueueStatus(): Promise<any> {
806
+ return this.client.request('GET', '/v2/ai/queue/status/');
807
+ }
808
+
809
+ /**
810
+ * List AI processing jobs.
811
+ */
812
+ async listJobs(options: { status?: string; limit?: number } = {}): Promise<any[]> {
813
+ const data = await this.client.request<any>('GET', '/v2/ai/jobs/', {
814
+ params: {
815
+ status: options.status || 'all',
816
+ limit: options.limit || 20,
817
+ }
818
+ });
819
+ return data.results || [];
820
+ }
821
+
822
+ /**
823
+ * Get details of a specific AI job.
824
+ */
825
+ async getJob(jobId: string): Promise<any> {
826
+ return this.client.request('GET', `/v2/ai/jobs/${jobId}/`);
827
+ }
828
+
829
+ /**
830
+ * Cancel a pending AI job.
831
+ */
832
+ async cancelJob(jobId: string): Promise<any> {
833
+ return this.client.request('POST', `/v2/ai/jobs/${jobId}/cancel/`);
834
+ }
835
+
836
+ /**
837
+ * Get cost estimate for an AI operation before executing.
838
+ */
839
+ async getCostEstimate(
840
+ operation: string,
841
+ contentLength: number,
842
+ modelTier: string = 'standard'
843
+ ): Promise<any> {
844
+ return this.client.request('POST', '/v2/ai/estimate/', {
845
+ body: {
846
+ operation,
847
+ content_length: contentLength,
848
+ model_tier: modelTier,
849
+ }
850
+ });
851
+ }
852
+
853
+ /**
854
+ * Get AI usage audit log for compliance.
855
+ */
856
+ async getAuditLog(options: {
857
+ startDate?: string;
858
+ endDate?: string;
859
+ limit?: number;
860
+ } = {}): Promise<any[]> {
861
+ const params: Record<string, string | number> = { limit: options.limit || 100 };
862
+ if (options.startDate) params.start_date = options.startDate;
863
+ if (options.endDate) params.end_date = options.endDate;
864
+
865
+ const data = await this.client.request<any>('GET', '/v2/ai/audit/', { params });
866
+ return data.entries || [];
867
+ }
868
+ }
869
+
870
+ // =============================================================================
871
+ // SECURITY UTILITIES
872
+ // =============================================================================
873
+
874
+ /**
875
+ * HMAC-SHA256 request signing for API request integrity.
876
+ */
877
+ export class RequestSigner {
878
+ /**
879
+ * Generate HMAC-SHA256 signature for request.
880
+ */
881
+ static sign(
882
+ apiKey: string,
883
+ method: string,
884
+ path: string,
885
+ timestamp: string,
886
+ body?: string
887
+ ): string {
888
+ const parts = [method.toUpperCase(), path, timestamp];
889
+ if (body) {
890
+ const bodyHash = crypto.createHash('sha256').update(body).digest('hex');
891
+ parts.push(bodyHash);
892
+ }
893
+
894
+ const canonical = parts.join('\n');
895
+ const signature = crypto
896
+ .createHmac('sha256', apiKey)
897
+ .update(canonical)
898
+ .digest('base64');
899
+
900
+ return signature;
901
+ }
902
+
903
+ /**
904
+ * Verify request signature and timestamp freshness.
905
+ */
906
+ static verify(
907
+ apiKey: string,
908
+ signature: string,
909
+ method: string,
910
+ path: string,
911
+ timestamp: string,
912
+ body?: string,
913
+ maxAgeSeconds: number = 300
914
+ ): boolean {
915
+ // Check timestamp freshness
916
+ try {
917
+ const ts = new Date(timestamp);
918
+ const age = Math.abs(Date.now() - ts.getTime()) / 1000;
919
+ if (age > maxAgeSeconds) return false;
920
+ } catch {
921
+ return false;
922
+ }
923
+
924
+ // Verify signature
925
+ const expected = RequestSigner.sign(apiKey, method, path, timestamp, body);
926
+ return crypto.timingSafeEqual(
927
+ Buffer.from(signature),
928
+ Buffer.from(expected)
929
+ );
930
+ }
931
+ }
932
+
933
+ /**
934
+ * Secure credential storage utilities.
935
+ */
936
+ export class SecureCredentialManager {
937
+ private static SERVICE_NAME = 'aribot-api';
938
+
939
+ /**
940
+ * Store API key securely using environment variable.
941
+ * For production, use OS keyring via native modules.
942
+ */
943
+ static setApiKey(apiKey: string): void {
944
+ process.env.ARIBOT_API_KEY = apiKey;
945
+ }
946
+
947
+ /**
948
+ * Retrieve API key from environment.
949
+ */
950
+ static getApiKey(): string | undefined {
951
+ return process.env.ARIBOT_API_KEY;
952
+ }
953
+
954
+ /**
955
+ * Clear stored API key.
956
+ */
957
+ static clearApiKey(): void {
958
+ delete process.env.ARIBOT_API_KEY;
959
+ }
960
+
961
+ /**
962
+ * Validate API key format.
963
+ */
964
+ static isValidFormat(apiKey: string): boolean {
965
+ return /^ak_[a-zA-Z0-9]{32,}$/.test(apiKey);
966
+ }
967
+ }
968
+
969
+ // =============================================================================
970
+ // CONVENIENCE FUNCTIONS
971
+ // =============================================================================
972
+
973
+ /**
974
+ * Quick function to analyze a diagram and get threats.
975
+ */
976
+ export async function analyzeDiagram(
977
+ filePath: string,
978
+ options: { apiKey?: string; name?: string; waitForThreats?: boolean } = {}
979
+ ): Promise<{ diagram: Diagram; threats: Threat[] }> {
980
+ const client = new AribotClient({ apiKey: options.apiKey });
981
+ const diagram = await client.threatModeling.upload(filePath, {
982
+ name: options.name,
983
+ autoGenerateThreats: options.waitForThreats !== false
984
+ });
985
+
986
+ if (options.waitForThreats !== false) {
987
+ await new Promise(r => setTimeout(r, 2000));
988
+
989
+ for (let i = 0; i < 30; i++) {
990
+ const updated = await client.threatModeling.get(diagram.id);
991
+ if (updated.stage === 'completed') {
992
+ break;
993
+ }
994
+ await new Promise(r => setTimeout(r, 2000));
995
+ }
996
+
997
+ const threats = await client.threatModeling.getThreats(diagram.id);
998
+ return { diagram, threats };
999
+ }
1000
+
1001
+ return { diagram, threats: [] };
1002
+ }
1003
+
1004
+ /**
1005
+ * Quick compliance check against multiple standards.
1006
+ */
1007
+ export async function runComplianceCheck(
1008
+ diagramId: string,
1009
+ standards: string[] = ['SOC2', 'ISO27001'],
1010
+ apiKey?: string
1011
+ ): Promise<any> {
1012
+ const client = new AribotClient({ apiKey });
1013
+ return client.compliance.runScan(diagramId, standards);
1014
+ }
1015
+
1016
+ // Export default client
1017
+ export default AribotClient;