@@ -11,6 +11,8 @@ const { Validators } = require('./validators');
11
11
const { HealthChecker } = require ( './health-checker' ) ;
12
12
const { displayValidationResults, displayTopicSummary } = require ( './utils' ) ;
13
13
const { SupabaseAnalytics } = require ( './analytics' ) ;
14
+ const { NATSObjectStore } = require ( './nats-object-store' ) ;
15
+ const { log } = require ( 'console' ) ;
14
16
15
17
class CLI {
16
18
constructor ( options = { } ) {
@@ -21,6 +23,7 @@ class CLI {
21
23
} ;
22
24
this . kafkaClient = null ;
23
25
this . fileService = null ;
26
+ this . natsObjectStore = null ;
24
27
this . analytics = new SupabaseAnalytics ( ) ;
25
28
26
29
// Handle bootstrap-servers option mapping to brokers
@@ -115,6 +118,39 @@ class CLI {
115
118
}
116
119
}
117
120
121
+ async loadNATSConfig ( natsConfigPath ) {
122
+ try {
123
+ const fullPath = path . resolve ( natsConfigPath ) ;
124
+ if ( ! fs . existsSync ( fullPath ) ) {
125
+ throw new Error ( `NATS config file not found: ${ fullPath } ` ) ;
126
+ }
127
+
128
+ const configContent = fs . readFileSync ( fullPath , 'utf8' ) ;
129
+ const natsConfig = JSON . parse ( configContent ) ;
130
+
131
+ // Create NATS object store
132
+ this . natsObjectStore = new NATSObjectStore ( natsConfig ) ;
133
+
134
+ // Connect to NATS
135
+ const connected = await this . natsObjectStore . connect ( ) ;
136
+ if ( ! connected ) {
137
+ throw new Error ( 'Failed to connect to NATS' ) ;
138
+ }
139
+
140
+ // Setup object store bucket
141
+ const bucketReady = await this . natsObjectStore . getOrCreateBucket ( ) ;
142
+ if ( ! bucketReady ) {
143
+ throw new Error ( 'Failed to setup Object Store bucket' ) ;
144
+ }
145
+
146
+ console . log ( chalk . green ( `✅ NATS configuration loaded from: ${ fullPath } ` ) ) ;
147
+ return true ;
148
+ } catch ( error ) {
149
+ console . error ( chalk . red ( `❌ Failed to load NATS config file: ${ error . message } ` ) ) ;
150
+ return false ;
151
+ }
152
+ }
153
+
118
154
async promptForConfig ( ) {
119
155
console . log ( chalk . blue ( '\n🚀 Superstream Kafka Analyzer\n' ) ) ;
120
156
console . log ( chalk . gray ( 'Configure your analysis settings:\n' ) ) ;
@@ -177,6 +213,7 @@ class CLI {
177
213
178
214
// Authentication configuration based on vendor
179
215
let saslConfig = null ;
216
+ let sslConfig = null ;
180
217
if ( vendorAnswer . vendor === 'aws-msk' ) {
181
218
console . log ( chalk . yellow ( '\n🔐 AWS MSK Authentication' ) ) ;
182
219
const authType = await inquirer . prompt ( [
@@ -268,27 +305,50 @@ class CLI {
268
305
{
269
306
type : 'input' ,
270
307
name : 'username' ,
271
- message : 'Username:' ,
308
+ message : 'Username (leave empty is using SSL only) :' ,
272
309
validate : ( input ) => {
273
- if ( ! input . trim ( ) ) return 'Username is required for Aiven' ;
274
310
return true ;
275
311
}
276
312
} ,
277
313
{
278
314
type : 'password' ,
279
315
name : 'password' ,
280
- message : 'Password:' ,
316
+ message : 'Password (leave empty if using SSL only) :' ,
281
317
validate : ( input ) => {
282
- if ( ! input . trim ( ) ) return 'Password is required for Aiven' ;
283
318
return true ;
284
319
}
320
+ } ,
321
+ {
322
+ type : 'input' ,
323
+ name : 'caPath' ,
324
+ message : 'CA Certificate path (optional, e.g., "./certs/ca.pem"):' ,
325
+ default : './certs/ca.pem'
326
+ } ,
327
+ {
328
+ type : 'input' ,
329
+ name : 'certPath' ,
330
+ message : 'Client Certificate path (optional, eg. "./certs/service.cert"):' ,
331
+ default : './certs/service.cert' ,
332
+ } ,
333
+ {
334
+ type : 'input' ,
335
+ name : 'keyPath' ,
336
+ message : 'Client Private Key path (optional, eg. "./certs/service.key"):' ,
337
+ default : './certs/service.key' ,
285
338
}
286
339
] ) ;
340
+
287
341
saslConfig = {
288
342
mechanism : 'scram-sha-256' ,
289
343
username : aivenAnswers . username ,
290
344
password : aivenAnswers . password
291
345
} ;
346
+
347
+ sslConfig = {
348
+ ca : aivenAnswers . caPath ,
349
+ cert : aivenAnswers . certPath ,
350
+ key : aivenAnswers . keyPath
351
+ } ;
292
352
} else {
293
353
// For other vendors, ask if SASL is needed
294
354
const useSasl = await inquirer . prompt ( [
@@ -346,7 +406,8 @@ class CLI {
346
406
brokers : kafkaAnswers . brokers . split ( ',' ) . map ( broker => broker . trim ( ) ) , // Convert string to array
347
407
vendor : vendorAnswer . vendor ,
348
408
useSasl : ! ! saslConfig ,
349
- sasl : saslConfig
409
+ sasl : saslConfig ,
410
+ ssl : sslConfig
350
411
} ;
351
412
352
413
// File Output Configuration
@@ -417,6 +478,7 @@ class CLI {
417
478
418
479
// Use Commander.js options
419
480
const configPath = this . options . config ;
481
+ const natsConfigPath = this . options . natsConfig ;
420
482
421
483
if ( configPath ) {
422
484
console . log ( chalk . gray ( `Debug: Loading config from: ${ configPath } ` ) ) ;
@@ -430,6 +492,16 @@ class CLI {
430
492
await this . promptForConfig ( ) ;
431
493
}
432
494
495
+ // Load NATS config if provided
496
+ if ( natsConfigPath ) {
497
+ console . log ( chalk . gray ( `Debug: Loading NATS config from: ${ natsConfigPath } ` ) ) ;
498
+ const natsConfigLoaded = await this . loadNATSConfig ( natsConfigPath ) ;
499
+ if ( ! natsConfigLoaded ) {
500
+ process . exit ( 1 ) ;
501
+ }
502
+ console . log ( chalk . gray ( 'Debug: NATS config loaded successfully' ) ) ;
503
+ }
504
+
433
505
// Initialize services without validation
434
506
console . log ( chalk . yellow ( '\n⚠️ Validation skipped - proceeding directly to analysis' ) ) ;
435
507
this . kafkaClient = new KafkaClient ( this . config . kafka ) ;
@@ -582,6 +654,16 @@ class CLI {
582
654
if ( healthResults ) {
583
655
analysisResults . healthChecks = healthResults ;
584
656
}
657
+
658
+ // Store results in NATS
659
+ if ( this . options . natsConfig ) {
660
+ spinner . text = 'Saving results to NATS...' ;
661
+ spinner . render ( ) ;
662
+ await this . natsObjectStore . storeObject ( analysisResults ) ;
663
+ spinner . stop ( ) ;
664
+ console . log ( chalk . green ( '\n✅ Analysis completed and stored to NATS!' ) ) ;
665
+ process . exit ( 0 ) ;
666
+ }
585
667
586
668
// Check if email is provided for file generation
587
669
if ( this . config . email && this . config . email . trim ( ) ) {
0 commit comments