@tamyla/clodo-framework 2.0.1 → 2.0.3

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/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ ## [2.0.3](https://github.com/tamylaa/clodo-framework/compare/v2.0.2...v2.0.3) (2025-10-11)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * Add reusable deployment command with Three-Tier input architecture ([0e13bfc](https://github.com/tamylaa/clodo-framework/commit/0e13bfcdda56d0a137bcd44cfd8a9ca49af30503))
7
+ * test - Remove placeholder tests that require unimplemented classes ([b009b34](https://github.com/tamylaa/clodo-framework/commit/b009b34cf1f9f7542fbaab2fa2419b2766c72f10))
8
+
9
+ ## [2.0.2](https://github.com/tamylaa/clodo-framework/compare/v2.0.1...v2.0.2) (2025-10-11)
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * resolve CLI tool import paths and runtime dependencies ([6a726b9](https://github.com/tamylaa/clodo-framework/commit/6a726b95a5e55055048a262d1c146a50a4f0b46f))
15
+
1
16
  ## [2.0.1](https://github.com/tamylaa/clodo-framework/compare/v2.0.0...v2.0.1) (2025-10-10)
2
17
 
3
18
 
@@ -15,8 +15,8 @@
15
15
  import { Command } from 'commander';
16
16
  import { createInterface } from 'readline';
17
17
  import chalk from 'chalk';
18
- import { ServiceOrchestrator } from '../src/service-management/ServiceOrchestrator.js';
19
- import { InputCollector } from '../src/service-management/InputCollector.js';
18
+ import { ServiceOrchestrator } from '../dist/service-management/ServiceOrchestrator.js';
19
+ import { InputCollector } from '../dist/service-management/InputCollector.js';
20
20
 
21
21
  const program = new Command();
22
22
 
@@ -413,4 +413,169 @@ program
413
413
  }
414
414
  });
415
415
 
416
+ // Deploy command - using existing InputCollector + CustomerConfigLoader (reusable pattern)
417
+ program
418
+ .command('deploy')
419
+ .description('Deploy service using three-tier input architecture')
420
+ .option('-c, --customer <name>', 'Customer name')
421
+ .option('-e, --env <environment>', 'Target environment (development, staging, production)')
422
+ .option('-i, --interactive', 'Interactive mode (review confirmations)', true)
423
+ .option('--non-interactive', 'Non-interactive mode (use stored config)')
424
+ .option('--dry-run', 'Simulate deployment without making changes')
425
+ .option('--domain <domain>', 'Domain name (overrides stored config)')
426
+ .option('--service-path <path>', 'Path to service directory', '.')
427
+ .action(async (options) => {
428
+ try {
429
+ // Use existing reusable components
430
+ const { InputCollector } = await import('../dist/service-management/InputCollector.js');
431
+ const { CustomerConfigLoader } = await import('../dist/config/customer-config-loader.js');
432
+ const { ConfirmationHandler } = await import('../dist/service-management/handlers/ConfirmationHandler.js');
433
+ const { MultiDomainOrchestrator } = await import('../dist/orchestration/multi-domain-orchestrator.js');
434
+
435
+ console.log(chalk.cyan('\nšŸš€ Clodo Framework Deployment'));
436
+ console.log(chalk.white('Using Three-Tier Input Architecture\n'));
437
+
438
+ const isInteractive = options.interactive && !options.nonInteractive;
439
+ const configLoader = new CustomerConfigLoader();
440
+ const inputCollector = new InputCollector({ interactive: isInteractive });
441
+ const confirmationHandler = new ConfirmationHandler({ interactive: isInteractive });
442
+
443
+ let coreInputs = {};
444
+ let source = 'interactive';
445
+
446
+ try {
447
+ // Try to load existing customer config first
448
+ if (options.customer && options.env) {
449
+ const storedConfig = configLoader.loadConfig(options.customer, options.env);
450
+
451
+ if (storedConfig) {
452
+ source = 'stored-config';
453
+ console.log(chalk.cyan('šŸ“‹ Found Existing Configuration\n'));
454
+ configLoader.displayConfig(storedConfig.parsed);
455
+
456
+ if (!isInteractive) {
457
+ // Non-interactive: use stored config as-is
458
+ coreInputs = storedConfig.parsed;
459
+ console.log(chalk.green('\nāœ… Using stored configuration (non-interactive mode)\n'));
460
+ } else {
461
+ // Interactive: ask to confirm or re-collect
462
+ const useStored = await inputCollector.question('\nUse this configuration? (Y/n): ');
463
+
464
+ if (useStored.toLowerCase() !== 'n') {
465
+ coreInputs = storedConfig.parsed;
466
+ console.log(chalk.green('\nāœ… Using stored configuration\n'));
467
+ } else {
468
+ console.log(chalk.white('\nCollecting new configuration...\n'));
469
+ source = 'interactive';
470
+ }
471
+ }
472
+ } else {
473
+ console.log(chalk.yellow(`āš ļø No configuration found for ${options.customer}/${options.env}`));
474
+ console.log(chalk.white('Collecting inputs interactively...\n'));
475
+ }
476
+ }
477
+
478
+ // Collect inputs if we don't have them from stored config
479
+ if (!coreInputs.cloudflareAccountId) {
480
+ console.log(chalk.cyan('šŸ“Š Tier 1: Core Input Collection\n'));
481
+
482
+ // Use InputCollector for what it does best - collecting inputs
483
+ coreInputs = {
484
+ customer: options.customer || await inputCollector.question('Customer name: '),
485
+ environment: options.env || await inputCollector.collectEnvironment(),
486
+ serviceName: await inputCollector.collectServiceName(),
487
+ serviceType: await inputCollector.collectServiceType(),
488
+ domainName: options.domain || await inputCollector.collectDomainName(),
489
+ cloudflareToken: process.env.CLOUDFLARE_API_TOKEN || await inputCollector.collectCloudflareToken(),
490
+ cloudflareAccountId: process.env.CLOUDFLARE_ACCOUNT_ID || await inputCollector.collectCloudflareAccountId(),
491
+ cloudflareZoneId: process.env.CLOUDFLARE_ZONE_ID || await inputCollector.collectCloudflareZoneId()
492
+ };
493
+
494
+ source = 'interactive';
495
+ }
496
+
497
+ // Allow domain override
498
+ if (options.domain) {
499
+ coreInputs.domainName = options.domain;
500
+ }
501
+
502
+ // Tier 2: Generate smart confirmations using existing ConfirmationHandler
503
+ console.log(chalk.cyan('āš™ļø Tier 2: Smart Confirmations\n'));
504
+ const confirmations = await confirmationHandler.generateAndConfirm(coreInputs);
505
+
506
+ // Show deployment summary
507
+ console.log(chalk.cyan('\nšŸ“Š Deployment Summary'));
508
+ console.log(chalk.gray('─'.repeat(60)));
509
+
510
+ console.log(chalk.white(`Source: ${source}`));
511
+ console.log(chalk.white(`Customer: ${coreInputs.customer}`));
512
+ console.log(chalk.white(`Environment: ${coreInputs.environment}`));
513
+ console.log(chalk.white(`Domain: ${coreInputs.domainName}`));
514
+ console.log(chalk.white(`Account ID: ${coreInputs.cloudflareAccountId?.substring(0, 8)}...`));
515
+ console.log(chalk.white(`Zone ID: ${coreInputs.cloudflareZoneId?.substring(0, 8)}...`));
516
+
517
+ if (confirmations.workerName) {
518
+ console.log(chalk.white(`Worker: ${confirmations.workerName}`));
519
+ }
520
+ if (confirmations.databaseName) {
521
+ console.log(chalk.white(`Database: ${confirmations.databaseName}`));
522
+ }
523
+
524
+ console.log(chalk.gray('─'.repeat(60)));
525
+
526
+ if (options.dryRun) {
527
+ console.log(chalk.yellow('\nšŸ” DRY RUN MODE - No changes will be made\n'));
528
+ }
529
+
530
+ // Tier 3: Execute deployment
531
+ console.log(chalk.cyan('\nāš™ļø Tier 3: Automated Deployment\n'));
532
+
533
+ const orchestrator = new MultiDomainOrchestrator({
534
+ domains: [coreInputs.domainName],
535
+ environment: coreInputs.environment,
536
+ dryRun: options.dryRun,
537
+ servicePath: options.servicePath
538
+ });
539
+
540
+ await orchestrator.initialize();
541
+
542
+ console.log(chalk.cyan('šŸš€ Starting deployment...\n'));
543
+
544
+ const result = await orchestrator.deployDomain(coreInputs.domainName, {
545
+ ...coreInputs,
546
+ ...confirmations,
547
+ servicePath: options.servicePath
548
+ });
549
+
550
+ // Display results
551
+ console.log(chalk.green('\nāœ… Deployment Completed Successfully!'));
552
+ console.log(chalk.gray('─'.repeat(60)));
553
+ console.log(chalk.white(` Worker: ${confirmations.workerName || 'N/A'}`));
554
+ console.log(chalk.white(` URL: ${result.url || confirmations.deploymentUrl || 'N/A'}`));
555
+ console.log(chalk.white(` Status: ${result.status || 'deployed'}`));
556
+
557
+ if (result.health) {
558
+ console.log(chalk.white(` Health: ${result.health}`));
559
+ }
560
+
561
+ console.log(chalk.gray('─'.repeat(60)));
562
+
563
+ console.log(chalk.cyan('\nšŸ“‹ Next Steps:'));
564
+ console.log(chalk.white(` • Test deployment: curl ${result.url || confirmations.deploymentUrl}/health`));
565
+ console.log(chalk.white(` • Monitor logs: wrangler tail ${confirmations.workerName}`));
566
+ console.log(chalk.white(` • View dashboard: https://dash.cloudflare.com`));
567
+
568
+ } finally {
569
+ inputCollector.close();
570
+ }
571
+
572
+ } catch (error) {
573
+ console.error(chalk.red(`\nāŒ Deployment failed: ${error.message}`));
574
+ if (error.stack && process.env.DEBUG) {
575
+ console.error(chalk.gray(error.stack));
576
+ }
577
+ process.exit(1);
578
+ }
579
+ });
580
+
416
581
  program.parse();
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { SecurityCLI } from '../../src/security/SecurityCLI.js';
3
+ import { SecurityCLI } from '../../dist/security/SecurityCLI.js';
4
4
 
5
5
  const command = process.argv[2];
6
6
  const args = process.argv.slice(3);
@@ -5,7 +5,7 @@
5
5
  * Creates new ser console.log(`āœ“ Using Clodo Framework ServiceCreator module`);ices from predefined templates
6
6
  */
7
7
 
8
- import { ServiceCreator } from '../../src/service-management/ServiceCreator.js';
8
+ import { ServiceCreator } from '../../dist/service-management/ServiceCreator.js';
9
9
 
10
10
  const SERVICE_TYPES = ['data-service', 'auth-service', 'content-service', 'api-gateway', 'generic'];
11
11
 
@@ -11,7 +11,7 @@
11
11
  */
12
12
 
13
13
  import { program } from 'commander';
14
- import { ServiceInitializer } from '../../src/service-management/ServiceInitializer.js';
14
+ import { ServiceInitializer } from '../../dist/service-management/ServiceInitializer.js';
15
15
 
16
16
  const SERVICE_TYPES = ['generic', 'data-service', 'auth-service', 'content-service', 'api-gateway'];
17
17