@tamyla/clodo-framework 3.1.4 → 3.1.8

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 (62) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/bin/clodo-service.js +29 -989
  3. package/bin/database/enterprise-db-manager.js +7 -5
  4. package/bin/security/security-cli.js +0 -0
  5. package/bin/service-management/create-service.js +0 -0
  6. package/bin/service-management/init-service.js +0 -0
  7. package/bin/shared/cloudflare/domain-discovery.js +11 -10
  8. package/bin/shared/cloudflare/ops.js +1 -1
  9. package/bin/shared/config/ConfigurationManager.js +539 -0
  10. package/bin/shared/config/index.js +13 -1
  11. package/bin/shared/database/connection-manager.js +2 -2
  12. package/bin/shared/database/orchestrator.js +5 -4
  13. package/bin/shared/deployment/auditor.js +9 -8
  14. package/bin/shared/logging/Logger.js +214 -0
  15. package/bin/shared/monitoring/production-monitor.js +21 -9
  16. package/bin/shared/utils/ErrorHandler.js +675 -0
  17. package/bin/shared/utils/error-recovery.js +33 -13
  18. package/bin/shared/utils/file-manager.js +162 -0
  19. package/bin/shared/utils/formatters.js +247 -0
  20. package/bin/shared/utils/index.js +14 -4
  21. package/bin/shared/validation/ValidationRegistry.js +143 -0
  22. package/dist/deployment/auditor.js +23 -8
  23. package/dist/deployment/orchestration/BaseDeploymentOrchestrator.js +426 -0
  24. package/dist/deployment/orchestration/EnterpriseOrchestrator.js +401 -0
  25. package/dist/deployment/orchestration/PortfolioOrchestrator.js +273 -0
  26. package/dist/deployment/orchestration/SingleServiceOrchestrator.js +231 -0
  27. package/dist/deployment/orchestration/UnifiedDeploymentOrchestrator.js +662 -0
  28. package/dist/deployment/orchestration/index.js +17 -0
  29. package/dist/index.js +12 -0
  30. package/dist/orchestration/modules/DomainResolver.js +8 -6
  31. package/dist/orchestration/multi-domain-orchestrator.js +13 -1
  32. package/dist/security/index.js +2 -2
  33. package/dist/service-management/ConfirmationEngine.js +8 -7
  34. package/dist/service-management/ErrorTracker.js +7 -2
  35. package/dist/service-management/InputCollector.js +31 -16
  36. package/dist/service-management/ServiceCreator.js +22 -7
  37. package/dist/service-management/ServiceInitializer.js +12 -18
  38. package/dist/shared/cloudflare/domain-discovery.js +11 -10
  39. package/dist/shared/cloudflare/ops.js +1 -1
  40. package/dist/shared/config/ConfigurationManager.js +519 -0
  41. package/dist/shared/config/index.js +5 -1
  42. package/dist/shared/database/connection-manager.js +2 -2
  43. package/dist/shared/database/orchestrator.js +13 -4
  44. package/dist/shared/deployment/auditor.js +23 -8
  45. package/dist/shared/logging/Logger.js +209 -0
  46. package/dist/shared/monitoring/production-monitor.js +24 -8
  47. package/dist/{utils → shared/utils}/ErrorHandler.js +306 -28
  48. package/dist/shared/utils/error-recovery.js +33 -13
  49. package/dist/shared/utils/file-manager.js +155 -0
  50. package/dist/shared/utils/formatters.js +215 -0
  51. package/dist/shared/utils/index.js +14 -4
  52. package/dist/shared/validation/ValidationRegistry.js +126 -0
  53. package/dist/utils/config/unified-config-manager.js +14 -12
  54. package/dist/utils/deployment/config-cache.js +3 -1
  55. package/dist/utils/deployment/secret-generator.js +32 -29
  56. package/dist/utils/framework-config.js +6 -3
  57. package/dist/utils/ui-structures-loader.js +3 -0
  58. package/dist/worker/integration.js +11 -1
  59. package/package.json +31 -3
  60. package/dist/config/FeatureManager.js +0 -426
  61. package/dist/config/features.js +0 -230
  62. package/dist/utils/error-recovery.js +0 -240
@@ -11,12 +11,18 @@
11
11
  */
12
12
 
13
13
  import { randomBytes, createHash } from 'crypto';
14
- import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync, statSync, appendFileSync } from 'fs';
14
+ import { readdirSync, statSync } from 'fs';
15
15
  import { join, dirname } from 'path';
16
16
  import { execSync } from 'child_process';
17
17
  import { fileURLToPath } from 'url';
18
+ import { FileManager } from '../../../bin/shared/utils/file-manager.js';
18
19
  let __filename, __dirname;
19
20
 
21
+ // Module-level FileManager for standalone functions
22
+ const moduleFileManager = new FileManager({
23
+ enableCache: true
24
+ });
25
+
20
26
  // Handle test environment where import.meta might be transformed
21
27
  try {
22
28
  __filename = fileURLToPath(import.meta.url);
@@ -85,6 +91,9 @@ const SECRET_CONFIGS = {
85
91
  */
86
92
  export class EnhancedSecretManager {
87
93
  constructor(options = {}) {
94
+ this.fileManager = new FileManager({
95
+ enableCache: true
96
+ });
88
97
  this.projectRoot = options.projectRoot || join(__dirname, '..', '..');
89
98
  this.dryRun = options.dryRun || false;
90
99
  this.retryAttempts = options.retryAttempts || 3;
@@ -535,7 +544,7 @@ export class EnhancedSecretManager {
535
544
  default:
536
545
  throw new Error(`Unsupported format: ${format}`);
537
546
  }
538
- writeFileSync(filepath, content);
547
+ this.fileManager.writeFile(filepath, content);
539
548
  return {
540
549
  format,
541
550
  filename,
@@ -635,7 +644,7 @@ ${Object.entries(SECRET_CONFIGS).map(([key, config]) => `- **${key}**: ${config.
635
644
  `;
636
645
  const readmeFile = join(domain, environment, 'README.md');
637
646
  const readmePath = join(this.secretPaths.distribution, readmeFile);
638
- writeFileSync(readmePath, readmeContent);
647
+ this.fileManager.writeFile(readmePath, readmeContent);
639
648
  return {
640
649
  filename: 'README.md',
641
650
  filepath: readmePath,
@@ -655,11 +664,11 @@ ${Object.entries(SECRET_CONFIGS).map(([key, config]) => `- **${key}**: ${config.
655
664
  }
656
665
  async loadDomainSecrets(domain, environment) {
657
666
  const filename = join(this.secretPaths.root, `${domain}-${environment}-secrets.json`);
658
- if (!existsSync(filename)) {
667
+ if (!this.fileManager.exists(filename)) {
659
668
  return null;
660
669
  }
661
670
  try {
662
- const data = JSON.parse(readFileSync(filename, 'utf8'));
671
+ const data = JSON.parse(this.fileManager.readFile(filename, 'utf8'));
663
672
  const {
664
673
  domain: d,
665
674
  environment: e,
@@ -693,15 +702,13 @@ ${Object.entries(SECRET_CONFIGS).map(([key, config]) => `- **${key}**: ${config.
693
702
  console.log(` 🔍 DRY RUN: Would save secrets to ${filename}`);
694
703
  return filename;
695
704
  }
696
- writeFileSync(filename, JSON.stringify(secretData, null, 2));
705
+ this.fileManager.writeFile(filename, JSON.stringify(secretData, null, 2));
697
706
  console.log(` 💾 Secrets saved: ${filename}`);
698
707
  return filename;
699
708
  }
700
709
  ensureDirectory(path) {
701
- if (!existsSync(path)) {
702
- mkdirSync(path, {
703
- recursive: true
704
- });
710
+ if (!this.fileManager.exists(path)) {
711
+ this.fileManager.ensureDir(path);
705
712
  }
706
713
  }
707
714
  logSecretEvent(event, domain, details = {}) {
@@ -719,10 +726,10 @@ ${Object.entries(SECRET_CONFIGS).map(([key, config]) => `- **${key}**: ${config.
719
726
  };
720
727
  try {
721
728
  const logLine = JSON.stringify(logEntry) + '\n';
722
- if (existsSync(this.secretPaths.audit)) {
723
- appendFileSync(this.secretPaths.audit, logLine);
729
+ if (this.fileManager.exists(this.secretPaths.audit)) {
730
+ this.fileManager.appendFile(this.secretPaths.audit, logLine);
724
731
  } else {
725
- writeFileSync(this.secretPaths.audit, logLine);
732
+ this.fileManager.writeFile(this.secretPaths.audit, logLine);
726
733
  }
727
734
  } catch (error) {
728
735
  console.warn(`⚠️ Failed to log secret event: ${error.message}`);
@@ -747,10 +754,8 @@ export function generateSingleSecret(length = 32) {
747
754
  }
748
755
  export function saveSecrets(domain, environment, secrets, additionalData = {}) {
749
756
  const secretsDir = 'secrets';
750
- if (!existsSync(secretsDir)) {
751
- mkdirSync(secretsDir, {
752
- recursive: true
753
- });
757
+ if (!moduleFileManager.exists(secretsDir)) {
758
+ moduleFileManager.ensureDir(secretsDir);
754
759
  }
755
760
  const data = {
756
761
  domain,
@@ -761,16 +766,16 @@ export function saveSecrets(domain, environment, secrets, additionalData = {}) {
761
766
  ...secrets
762
767
  };
763
768
  const filename = join(secretsDir, `${domain}-secrets.json`);
764
- writeFileSync(filename, JSON.stringify(data, null, 2));
769
+ moduleFileManager.writeFile(filename, JSON.stringify(data, null, 2));
765
770
  return filename;
766
771
  }
767
772
  export function loadSecrets(domain) {
768
773
  const filename = join('secrets', `${domain}-secrets.json`);
769
- if (!existsSync(filename)) {
774
+ if (!moduleFileManager.exists(filename)) {
770
775
  return null;
771
776
  }
772
777
  try {
773
- const data = JSON.parse(readFileSync(filename, 'utf8'));
778
+ const data = JSON.parse(moduleFileManager.readFile(filename, 'utf8'));
774
779
  const {
775
780
  domain: d,
776
781
  environment,
@@ -794,32 +799,30 @@ export function loadSecrets(domain) {
794
799
  }
795
800
  export function distributeSecrets(domain, secrets) {
796
801
  const distDir = join('secrets', 'distribution', domain);
797
- mkdirSync(distDir, {
798
- recursive: true
799
- });
802
+ moduleFileManager.ensureDir(distDir);
800
803
  const files = {};
801
804
 
802
805
  // .env format
803
806
  const envContent = Object.entries(secrets).map(([key, value]) => `${key}=${value}`).join('\n');
804
807
  const envFile = join(distDir, '.env');
805
- writeFileSync(envFile, envContent);
808
+ moduleFileManager.writeFile(envFile, envContent);
806
809
  files.env = envFile;
807
810
 
808
811
  // JSON format
809
812
  const jsonFile = join(distDir, 'secrets.json');
810
- writeFileSync(jsonFile, JSON.stringify(secrets, null, 2));
813
+ moduleFileManager.writeFile(jsonFile, JSON.stringify(secrets, null, 2));
811
814
  files.json = jsonFile;
812
815
 
813
816
  // Shell script format (cross-platform)
814
817
  const shellContent = Object.entries(secrets).map(([key, value]) => `echo "${value}" | npx wrangler secret put ${key} --env production`).join('\n');
815
818
  const shellFile = join(distDir, 'deploy-secrets.sh');
816
- writeFileSync(shellFile, shellContent);
819
+ moduleFileManager.writeFile(shellFile, shellContent);
817
820
  files.shell = shellFile;
818
821
 
819
822
  // PowerShell script format
820
823
  const psContent = Object.entries(secrets).map(([key, value]) => `"${value}" | npx wrangler secret put ${key} --env production`).join('\n');
821
824
  const psFile = join(distDir, 'deploy-secrets.ps1');
822
- writeFileSync(psFile, psContent);
825
+ moduleFileManager.writeFile(psFile, psContent);
823
826
  files.powershell = psFile;
824
827
 
825
828
  // README
@@ -857,7 +860,7 @@ chmod +x deploy-secrets.sh
857
860
  - Distribute via secure channels only
858
861
  `;
859
862
  const readmeFile = join(distDir, 'README.md');
860
- writeFileSync(readmeFile, readme);
863
+ moduleFileManager.writeFile(readmeFile, readme);
861
864
  files.readme = readmeFile;
862
865
  return {
863
866
  directory: distDir,
@@ -882,7 +885,7 @@ export function validateSecrets(secrets) {
882
885
  }
883
886
  export function listSecretsFiles() {
884
887
  const secretsDir = 'secrets';
885
- if (!existsSync(secretsDir)) {
888
+ if (!moduleFileManager.exists(secretsDir)) {
886
889
  return [];
887
890
  }
888
891
  try {
@@ -6,11 +6,14 @@
6
6
  * from validation-config.json and environment variables
7
7
  */
8
8
 
9
- import { readFileSync, existsSync } from 'fs';
10
9
  import { join, dirname } from 'path';
11
10
  import { fileURLToPath } from 'url';
11
+ import { FileManager } from '../../bin/shared/utils/file-manager.js';
12
12
  export class FrameworkConfig {
13
13
  constructor(configPath = null) {
14
+ this.fileManager = new FileManager({
15
+ enableCache: true
16
+ });
14
17
  this.configPath = configPath || this.findConfigFile();
15
18
  this.config = this.loadConfig();
16
19
  this.environment = process.env.ENVIRONMENT || 'development';
@@ -36,7 +39,7 @@ export class FrameworkConfig {
36
39
  }
37
40
  const possiblePaths = ['./validation-config.json', '../validation-config.json', '../../validation-config.json', join(process.cwd(), 'validation-config.json'), join(__dirname, '..', '..', 'validation-config.json')];
38
41
  for (const path of possiblePaths) {
39
- if (existsSync(path)) {
42
+ if (this.fileManager.exists(path)) {
40
43
  return path;
41
44
  }
42
45
  }
@@ -56,7 +59,7 @@ export class FrameworkConfig {
56
59
  return this.getDefaultConfig();
57
60
  }
58
61
  try {
59
- const configContent = readFileSync(this.configPath, 'utf8');
62
+ const configContent = this.fileManager.readFile(this.configPath, 'utf8');
60
63
  const config = JSON.parse(configContent);
61
64
  console.log(`📋 Loaded configuration from: ${this.configPath}`);
62
65
  return config;
@@ -38,14 +38,17 @@ class UIStructuresLoader {
38
38
 
39
39
  // Load reference templates
40
40
  const referenceDir = path.join(uiStructuresDir, 'reference');
41
+ console.log('🔍 Reference dir:', referenceDir, 'exists:', fs.existsSync(referenceDir));
41
42
  if (fs.existsSync(referenceDir)) {
42
43
  const referenceFiles = fs.readdirSync(referenceDir).filter(f => f.endsWith('.json'));
44
+ console.log('🔍 Reference files:', referenceFiles);
43
45
  for (const file of referenceFiles) {
44
46
  const filePath = path.join(referenceDir, file);
45
47
  const content = fs.readFileSync(filePath, 'utf8');
46
48
  const template = JSON.parse(content);
47
49
  // Use template.name if available, otherwise filename
48
50
  const name = template.template?.name || path.basename(file, '.json');
51
+ console.log('🔍 Loaded template:', name);
49
52
  this.templates.set(name, template);
50
53
  }
51
54
  }
@@ -1,6 +1,16 @@
1
- import { featureManager, COMMON_FEATURES } from '../config/features.js';
1
+ import { COMMON_FEATURES, ConfigurationManager } from '../../bin/shared/config/ConfigurationManager.js';
2
2
  import { getDomainFromEnv, createEnvironmentConfig } from '../config/domains.js';
3
3
 
4
+ // Create a singleton instance of ConfigurationManager for use in integration
5
+ export const configManager = new ConfigurationManager({});
6
+
7
+ // Legacy featureManager compatibility interface using ConfigurationManager
8
+ const featureManager = {
9
+ setDomain: domainConfig => configManager.setDomain(domainConfig),
10
+ getEnabledFeatures: () => configManager.getEnabledFeatures(),
11
+ isEnabled: featureName => configManager.isFeatureEnabled(featureName)
12
+ };
13
+
4
14
  // Simple inline logger to avoid circular dependency with index.js
5
15
  const logger = {
6
16
  info: (message, ...args) => console.log(`[WorkerIntegration] ${message}`, ...args),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tamyla/clodo-framework",
3
- "version": "3.1.4",
3
+ "version": "3.1.8",
4
4
  "description": "Reusable framework for Clodo-style software architecture on Cloudflare Workers + D1",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -70,19 +70,40 @@
70
70
  ],
71
71
  "scripts": {
72
72
  "build": "npm run prebuild && babel src/ --out-dir dist/ && babel bin/shared/ --out-dir dist/shared/ && babel bin/shared/production-tester/ --out-dir dist/deployment/testers/ && babel bin/shared/deployment/ --out-dir dist/deployment/ && node -e \"const fs=require('fs'); fs.cpSync('ui-structures', 'dist/ui-structures', {recursive: true});\" && npm run postbuild",
73
+ "build:ci": "npm run prebuild:ci && babel src/ --out-dir dist/ && babel bin/shared/ --out-dir dist/shared/ && babel bin/shared/production-tester/ --out-dir dist/deployment/testers/ && babel bin/shared/deployment/ --out-dir dist/deployment/ && node -e \"const fs=require('fs'); fs.cpSync('ui-structures', 'dist/ui-structures', {recursive: true});\" && npm run postbuild",
73
74
  "prebuild": "npm run clean && npm run type-check",
75
+ "prebuild:ci": "npm run clean && npm run type-check",
74
76
  "postbuild": "npm run check:bundle",
75
77
  "clean": "rimraf dist",
76
78
  "clean:generated": "rimraf generated",
77
79
  "clean:all": "npm run clean && npm run clean:generated",
78
80
  "test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --passWithNoTests",
81
+ "test:ci": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --passWithNoTests --testPathIgnorePatterns=\"test/cli-integration|backups/|i-docs/|generated/\"",
82
+ "test:unit": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --passWithNoTests",
79
83
  "test:watch": "jest --watch",
80
84
  "test:coverage": "jest --coverage",
85
+ "test:cli": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/cli-integration/ --verbose",
81
86
  "test:cli-integration": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --config test/cli-integration/jest.config.js",
82
87
  "test:cli-create": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/cli-integration/clodo-create-service.test.js",
83
88
  "test:cli-init": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/cli-integration/clodo-init-service.test.js",
84
89
  "test:cli-security": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/cli-integration/clodo-security.test.js",
85
90
  "test:cli-e2e": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/cli-integration/e2e-workflows.test.js",
91
+ "test:deployment": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/deployment/ test/deployment-security.spec.js --verbose",
92
+ "test:services": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/service-management/ test/services/ --verbose",
93
+ "test:services:create": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/service-orchestrator.test.js test/service-orchestrator-unit.test.js test/multi-domain-orchestrator-unit.test.js test/database-orchestrator-unit.test.js test/generic-data-service.test.js --verbose",
94
+ "test:generation": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/generation-engine.test.js test/generation-engine-unit.test.js --verbose",
95
+ "test:routing": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/routing/ --verbose",
96
+ "test:security": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/deployment-security.spec.js test/security-validation.test.js test/validation.test.js --verbose",
97
+ "test:handlers": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/handlers/ --verbose",
98
+ "test:utils": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/utils/ test/shared/ test/input-collector.test.js test/interactive-utils.test.js test/import-cleanup.test.js test/ui-structures.test.js --verbose",
99
+ "test:config": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/config/ --verbose",
100
+ "test:schema": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/schema/ --verbose",
101
+ "test:worker": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/worker/ --verbose",
102
+ "test:integration": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/integration/ --verbose",
103
+ "test:comprehensive": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/comprehensive-suite.spec.js --verbose",
104
+ "test:coverage:cli": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/cli-integration/ --coverage",
105
+ "test:coverage:deployment": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/deployment/ test/deployment-security.spec.js --coverage",
106
+ "test:coverage:services": "cross-env NODE_OPTIONS=--experimental-vm-modules jest test/service-management/ test/services/ --coverage",
86
107
  "lint": "eslint --config ./eslint.config.js src",
87
108
  "lint:fix": "eslint --config ./eslint.config.js src --fix",
88
109
  "type-check": "tsc --noEmit",
@@ -92,7 +113,7 @@
92
113
  "analyze:bundle": "echo 'Bundle analysis not implemented yet'",
93
114
  "docs": "echo 'JSDoc documentation generation not configured yet'",
94
115
  "validate": "npm run check:all",
95
- "prepublishOnly": "npm run validate && npm run build",
116
+ "prepublishOnly": "npm run build:ci",
96
117
  "postpublish": "echo 'Published successfully to npm registry!'",
97
118
  "publish:beta": "npm publish --tag beta",
98
119
  "publish:latest": "npm publish --tag latest",
@@ -103,7 +124,14 @@
103
124
  "validate-service": "node bin/clodo-service.js validate",
104
125
  "customer-config": "node bin/shared/config/customer-cli.js",
105
126
  "push:safe": "powershell -ExecutionPolicy Bypass -File ./scripts/utilities/safe-push.ps1",
106
- "sync": "git fetch && git rebase origin/master"
127
+ "sync": "git fetch && git rebase origin/master",
128
+ "test:automated": "node scripts/automated-testing-suite.js",
129
+ "test:automated:cli": "node scripts/automated-testing-suite.js cli",
130
+ "test:automated:deployment": "node scripts/automated-testing-suite.js deployment",
131
+ "test:automated:lifecycle": "node scripts/automated-testing-suite.js lifecycle",
132
+ "test:automated:integration": "node scripts/automated-testing-suite.js integration",
133
+ "test:automated:performance": "node scripts/automated-testing-suite.js performance",
134
+ "test:automated:regression": "node scripts/automated-testing-suite.js regression"
107
135
  },
108
136
  "keywords": [
109
137
  "cloudflare",