@tamyla/clodo-framework 1.0.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.
Files changed (130) hide show
  1. package/CHANGELOG.md +564 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1393 -0
  4. package/bin/README.md +71 -0
  5. package/bin/clodo-service.js +416 -0
  6. package/bin/security/security-cli.js +96 -0
  7. package/bin/service-management/README.md +74 -0
  8. package/bin/service-management/create-service.js +129 -0
  9. package/bin/service-management/init-service.js +102 -0
  10. package/bin/service-management/init-service.js.backup +889 -0
  11. package/bin/shared/config/customer-cli.js +293 -0
  12. package/dist/config/ConfigurationManager.js +159 -0
  13. package/dist/config/CustomerConfigCLI.js +220 -0
  14. package/dist/config/FeatureManager.js +426 -0
  15. package/dist/config/customers.js +441 -0
  16. package/dist/config/domains.js +180 -0
  17. package/dist/config/features.js +225 -0
  18. package/dist/config/index.js +6 -0
  19. package/dist/database/database-orchestrator.js +730 -0
  20. package/dist/database/index.js +4 -0
  21. package/dist/deployment/auditor.js +971 -0
  22. package/dist/deployment/index.js +10 -0
  23. package/dist/deployment/rollback-manager.js +523 -0
  24. package/dist/deployment/testers/api-tester.js +80 -0
  25. package/dist/deployment/testers/auth-tester.js +129 -0
  26. package/dist/deployment/testers/core.js +217 -0
  27. package/dist/deployment/testers/database-tester.js +105 -0
  28. package/dist/deployment/testers/index.js +74 -0
  29. package/dist/deployment/testers/load-tester.js +120 -0
  30. package/dist/deployment/testers/performance-tester.js +105 -0
  31. package/dist/deployment/validator.js +558 -0
  32. package/dist/deployment/wrangler-deployer.js +574 -0
  33. package/dist/handlers/GenericRouteHandler.js +532 -0
  34. package/dist/index.js +39 -0
  35. package/dist/migration/MigrationAdapters.js +562 -0
  36. package/dist/modules/ModuleManager.js +668 -0
  37. package/dist/modules/security.js +98 -0
  38. package/dist/orchestration/cross-domain-coordinator.js +1083 -0
  39. package/dist/orchestration/index.js +5 -0
  40. package/dist/orchestration/modules/DeploymentCoordinator.js +258 -0
  41. package/dist/orchestration/modules/DomainResolver.js +196 -0
  42. package/dist/orchestration/modules/StateManager.js +332 -0
  43. package/dist/orchestration/multi-domain-orchestrator.js +255 -0
  44. package/dist/routing/EnhancedRouter.js +158 -0
  45. package/dist/schema/SchemaManager.js +778 -0
  46. package/dist/security/ConfigurationValidator.js +490 -0
  47. package/dist/security/DeploymentManager.js +208 -0
  48. package/dist/security/SecretGenerator.js +142 -0
  49. package/dist/security/SecurityCLI.js +228 -0
  50. package/dist/security/index.js +51 -0
  51. package/dist/security/patterns/environment-rules.js +66 -0
  52. package/dist/security/patterns/insecure-patterns.js +21 -0
  53. package/dist/service-management/ConfirmationEngine.js +411 -0
  54. package/dist/service-management/ErrorTracker.js +294 -0
  55. package/dist/service-management/GenerationEngine.js +3109 -0
  56. package/dist/service-management/InputCollector.js +237 -0
  57. package/dist/service-management/ServiceCreator.js +229 -0
  58. package/dist/service-management/ServiceInitializer.js +448 -0
  59. package/dist/service-management/ServiceOrchestrator.js +638 -0
  60. package/dist/service-management/handlers/ConfigMutator.js +130 -0
  61. package/dist/service-management/handlers/ConfirmationHandler.js +71 -0
  62. package/dist/service-management/handlers/GenerationHandler.js +80 -0
  63. package/dist/service-management/handlers/InputHandler.js +59 -0
  64. package/dist/service-management/handlers/ValidationHandler.js +203 -0
  65. package/dist/service-management/index.js +7 -0
  66. package/dist/services/GenericDataService.js +488 -0
  67. package/dist/shared/cloudflare/domain-discovery.js +562 -0
  68. package/dist/shared/cloudflare/domain-manager.js +912 -0
  69. package/dist/shared/cloudflare/index.js +8 -0
  70. package/dist/shared/cloudflare/ops.js +387 -0
  71. package/dist/shared/config/cache.js +1167 -0
  72. package/dist/shared/config/command-config-manager.js +174 -0
  73. package/dist/shared/config/customer-cli.js +258 -0
  74. package/dist/shared/config/index.js +9 -0
  75. package/dist/shared/config/manager.js +289 -0
  76. package/dist/shared/database/connection-manager.js +338 -0
  77. package/dist/shared/database/index.js +7 -0
  78. package/dist/shared/database/orchestrator.js +632 -0
  79. package/dist/shared/deployment/auditor.js +971 -0
  80. package/dist/shared/deployment/index.js +10 -0
  81. package/dist/shared/deployment/rollback-manager.js +523 -0
  82. package/dist/shared/deployment/validator.js +558 -0
  83. package/dist/shared/index.js +32 -0
  84. package/dist/shared/monitoring/health-checker.js +250 -0
  85. package/dist/shared/monitoring/index.js +8 -0
  86. package/dist/shared/monitoring/memory-manager.js +382 -0
  87. package/dist/shared/monitoring/production-monitor.js +390 -0
  88. package/dist/shared/production-tester/api-tester.js +80 -0
  89. package/dist/shared/production-tester/auth-tester.js +129 -0
  90. package/dist/shared/production-tester/core.js +217 -0
  91. package/dist/shared/production-tester/database-tester.js +105 -0
  92. package/dist/shared/production-tester/index.js +74 -0
  93. package/dist/shared/production-tester/load-tester.js +120 -0
  94. package/dist/shared/production-tester/performance-tester.js +105 -0
  95. package/dist/shared/security/api-token-manager.js +296 -0
  96. package/dist/shared/security/index.js +8 -0
  97. package/dist/shared/security/secret-generator.js +918 -0
  98. package/dist/shared/security/secure-token-manager.js +379 -0
  99. package/dist/shared/utils/error-recovery.js +240 -0
  100. package/dist/shared/utils/graceful-shutdown-manager.js +380 -0
  101. package/dist/shared/utils/index.js +9 -0
  102. package/dist/shared/utils/interactive-prompts.js +134 -0
  103. package/dist/shared/utils/rate-limiter.js +249 -0
  104. package/dist/utils/ErrorHandler.js +173 -0
  105. package/dist/utils/deployment/config-cache.js +1160 -0
  106. package/dist/utils/deployment/index.js +6 -0
  107. package/dist/utils/deployment/interactive-prompts.js +97 -0
  108. package/dist/utils/deployment/secret-generator.js +896 -0
  109. package/dist/utils/dirname-helper.js +35 -0
  110. package/dist/utils/domain-config.js +159 -0
  111. package/dist/utils/error-recovery.js +240 -0
  112. package/dist/utils/esm-helper.js +52 -0
  113. package/dist/utils/framework-config.js +481 -0
  114. package/dist/utils/graceful-shutdown-manager.js +379 -0
  115. package/dist/utils/health-checker.js +114 -0
  116. package/dist/utils/index.js +36 -0
  117. package/dist/utils/prompt-handler.js +98 -0
  118. package/dist/utils/usage-tracker.js +252 -0
  119. package/dist/utils/validation.js +112 -0
  120. package/dist/version/VersionDetector.js +723 -0
  121. package/dist/worker/index.js +4 -0
  122. package/dist/worker/integration.js +332 -0
  123. package/docs/FRAMEWORK-ARCHITECTURE-OVERVIEW.md +206 -0
  124. package/docs/INTEGRATION_GUIDE.md +2045 -0
  125. package/docs/README.md +82 -0
  126. package/docs/SECURITY.md +242 -0
  127. package/docs/deployment/deployment-guide.md +540 -0
  128. package/docs/overview.md +280 -0
  129. package/package.json +176 -0
  130. package/types/index.d.ts +575 -0
@@ -0,0 +1,1167 @@
1
+ /**
2
+ * Enterprise Configuration Cache Manager
3
+ *
4
+ * Advanced configuration management system for multi-domain deployments with:
5
+ * - Smart configuration caching with TTL and invalidation
6
+ * - Template-based configuration generation
7
+ * - Runtime configuration discovery and validation
8
+ * - Multi-environment configuration coordination
9
+ * - Configuration versioning and rollback capabilities
10
+ * - Performance-optimized caching with compression
11
+ * - Cross-domain configuration inheritance
12
+ * - Configuration backup and restore
13
+ * - Real-time configuration updates
14
+ * - Compliance and audit trail for config changes
15
+ *
16
+ * @module config-cache
17
+ * @version 2.0.0
18
+ */
19
+
20
+ import { access, writeFile, readFile, mkdir, readdir, stat } from 'fs/promises';
21
+ import { join, dirname, basename } from 'path';
22
+ import { exec } from 'child_process';
23
+ import { promisify } from 'util';
24
+ const execAsync = promisify(exec);
25
+ export class ConfigurationCacheManager {
26
+ constructor(options = {}) {
27
+ this.config = {
28
+ // Cache configuration
29
+ cacheDir: options.cacheDir || 'config-cache',
30
+ cacheTTL: options.cacheTTL || 3600000,
31
+ // 1 hour in ms
32
+ maxCacheSize: options.maxCacheSize || 50 * 1024 * 1024,
33
+ // 50MB
34
+ enableCompression: options.enableCompression !== false,
35
+ // Template configuration
36
+ templateDir: options.templateDir || 'config-templates',
37
+ enableTemplateInheritance: options.enableTemplateInheritance !== false,
38
+ templateVersioning: options.templateVersioning !== false,
39
+ // Runtime discovery
40
+ enableRuntimeDiscovery: options.enableRuntimeDiscovery !== false,
41
+ discoveryTimeout: options.discoveryTimeout || 30000,
42
+ cloudflareCaching: options.cloudflareCaching !== false,
43
+ // Environments
44
+ environments: options.environments || ['development', 'staging', 'production'],
45
+ defaultEnvironment: options.defaultEnvironment || 'production',
46
+ // Validation and backups
47
+ enableValidation: options.enableValidation !== false,
48
+ enableBackups: options.enableBackups !== false,
49
+ backupRetentionDays: options.backupRetentionDays || 30,
50
+ // Performance
51
+ enableMetrics: options.enableMetrics !== false,
52
+ preloadConfigs: options.preloadConfigs || [],
53
+ // Cross-domain features
54
+ enableCrossDomainSharing: options.enableCrossDomainSharing !== false,
55
+ sharedConfigKeys: options.sharedConfigKeys || ['features', 'settings.security'],
56
+ // Output formats
57
+ outputFormats: options.outputFormats || ['json', 'js', 'yaml', 'env']
58
+ };
59
+
60
+ // Cache state
61
+ this.cache = new Map();
62
+ this.templates = new Map();
63
+ this.metrics = {
64
+ cacheHits: 0,
65
+ cacheMisses: 0,
66
+ discoveryRequests: 0,
67
+ validationErrors: 0,
68
+ templateGenerations: 0
69
+ };
70
+
71
+ // Configuration registry
72
+ this.configRegistry = {
73
+ domains: new Map(),
74
+ templates: new Map(),
75
+ shared: new Map()
76
+ };
77
+
78
+ // Built-in configuration templates
79
+ this.builtinTemplates = {
80
+ 'domain-standard': this.getStandardDomainTemplate(),
81
+ 'domain-minimal': this.getMinimalDomainTemplate(),
82
+ 'domain-enterprise': this.getEnterpriseDomainTemplate(),
83
+ 'cloudflare-worker': this.getCloudflareWorkerTemplate(),
84
+ 'database-standard': this.getStandardDatabaseTemplate()
85
+ };
86
+ }
87
+
88
+ /**
89
+ * Initialize the configuration cache manager
90
+ * @returns {Promise<void>}
91
+ */
92
+ async initialize() {
93
+ await this.initializeCacheSystem();
94
+ this.loadBuiltinTemplates();
95
+ console.log('🎛️ Configuration Cache Manager initialized');
96
+ if (this.config.enableMetrics) {
97
+ console.log(` 💾 Cache Directory: ${this.config.cacheDir}`);
98
+ console.log(` ⏰ Cache TTL: ${this.config.cacheTTL}ms`);
99
+ console.log(` 📋 Templates: ${Object.keys(this.builtinTemplates).length} builtin`);
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Initialize cache system directories and structures
105
+ * @returns {Promise<void>}
106
+ */
107
+ async initializeCacheSystem() {
108
+ this.paths = {
109
+ cache: this.config.cacheDir,
110
+ templates: this.config.templateDir,
111
+ backups: join(this.config.cacheDir, 'backups'),
112
+ versions: join(this.config.cacheDir, 'versions'),
113
+ shared: join(this.config.cacheDir, 'shared'),
114
+ runtime: join(this.config.cacheDir, 'runtime'),
115
+ metrics: join(this.config.cacheDir, 'metrics')
116
+ };
117
+
118
+ // Create directory structure
119
+ for (const path of Object.values(this.paths)) {
120
+ try {
121
+ await access(path);
122
+ } catch {
123
+ await mkdir(path, {
124
+ recursive: true
125
+ });
126
+ }
127
+ }
128
+
129
+ // Initialize cache metadata
130
+ this.cacheMetadataFile = join(this.paths.cache, 'cache-metadata.json');
131
+ await this.loadCacheMetadata();
132
+ }
133
+
134
+ /**
135
+ * Load cache metadata from disk
136
+ * @returns {Promise<void>}
137
+ */
138
+ async loadCacheMetadata() {
139
+ try {
140
+ await access(this.cacheMetadataFile);
141
+ const metadataContent = await readFile(this.cacheMetadataFile, 'utf8');
142
+ const metadata = JSON.parse(metadataContent);
143
+ this.cacheMetadata = {
144
+ ...metadata,
145
+ loadedAt: new Date()
146
+ };
147
+ } catch (error) {
148
+ if (error.code !== 'ENOENT') {
149
+ console.warn('⚠️ Failed to load cache metadata, initializing new');
150
+ }
151
+ this.cacheMetadata = this.createEmptyMetadata();
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Create empty cache metadata structure
157
+ * @returns {Object} Empty metadata
158
+ */
159
+ createEmptyMetadata() {
160
+ return {
161
+ version: '2.0.0',
162
+ createdAt: new Date(),
163
+ lastUpdate: new Date(),
164
+ cacheEntries: {},
165
+ templateVersions: {},
166
+ sharedConfigs: {}
167
+ };
168
+ }
169
+
170
+ /**
171
+ * Save cache metadata to disk
172
+ * @returns {Promise<void>}
173
+ */
174
+ async saveCacheMetadata() {
175
+ this.cacheMetadata.lastUpdate = new Date();
176
+ await writeFile(this.cacheMetadataFile, JSON.stringify(this.cacheMetadata, null, 2));
177
+ }
178
+
179
+ /**
180
+ * Load builtin configuration templates
181
+ */
182
+ loadBuiltinTemplates() {
183
+ Object.entries(this.builtinTemplates).forEach(([name, template]) => {
184
+ this.templates.set(name, {
185
+ ...template,
186
+ builtin: true,
187
+ loadedAt: new Date()
188
+ });
189
+ });
190
+ }
191
+
192
+ /**
193
+ * Get or create configuration for a domain
194
+ * @param {string} domain - Domain name
195
+ * @param {Object} options - Configuration options
196
+ * @returns {Promise<Object>} Domain configuration
197
+ */
198
+ async getOrCreateDomainConfig(domain, options = {}) {
199
+ console.log(`🔍 Getting configuration for domain: ${domain}`);
200
+ const cacheKey = this.generateCacheKey(domain, options.environment || this.config.defaultEnvironment);
201
+
202
+ // Check cache first
203
+ if (this.isCacheValid(cacheKey)) {
204
+ this.metrics.cacheHits++;
205
+ console.log(` 💾 Cache hit for ${domain}`);
206
+ return await this.getCachedConfig(cacheKey);
207
+ }
208
+ this.metrics.cacheMisses++;
209
+ console.log(` 🔄 Cache miss, generating configuration for ${domain}`);
210
+ try {
211
+ let domainConfig;
212
+
213
+ // Check if we have a saved configuration
214
+ const savedConfig = await this.loadSavedConfig(domain, options.environment);
215
+ if (savedConfig && !options.forceRefresh) {
216
+ domainConfig = savedConfig;
217
+ } else if (this.config.enableRuntimeDiscovery && options.cloudflareToken) {
218
+ // Runtime discovery
219
+ domainConfig = await this.discoverDomainConfiguration(domain, options);
220
+ } else {
221
+ // Generate from template
222
+ domainConfig = await this.generateFromTemplate(domain, options);
223
+ }
224
+
225
+ // Validate configuration
226
+ if (this.config.enableValidation) {
227
+ const validation = await this.validateConfiguration(domainConfig);
228
+ if (!validation.valid) {
229
+ throw new Error(`Configuration validation failed: ${validation.errors.join(', ')}`);
230
+ }
231
+ }
232
+
233
+ // Cache the configuration
234
+ await this.cacheConfiguration(cacheKey, domainConfig);
235
+
236
+ // Save for future use
237
+ await this.saveConfiguration(domain, domainConfig, options.environment);
238
+ return domainConfig;
239
+ } catch (error) {
240
+ console.error(`❌ Failed to get configuration for ${domain}: ${error.message}`);
241
+ throw error;
242
+ }
243
+ }
244
+
245
+ /**
246
+ * Discover domain configuration from Cloudflare API
247
+ * @param {string} domain - Domain name
248
+ * @param {Object} options - Discovery options
249
+ * @returns {Promise<Object>} Discovered configuration
250
+ */
251
+ async discoverDomainConfiguration(domain, options = {}) {
252
+ console.log(` 🔍 Discovering Cloudflare configuration for ${domain}`);
253
+ this.metrics.discoveryRequests++;
254
+ const {
255
+ cloudflareToken,
256
+ environment = this.config.defaultEnvironment
257
+ } = options;
258
+ if (!cloudflareToken) {
259
+ throw new Error('Cloudflare token required for runtime discovery');
260
+ }
261
+ try {
262
+ // Get Cloudflare account information
263
+ const accountInfo = await this.fetchCloudflareAccounts(cloudflareToken);
264
+ const zoneInfo = await this.fetchCloudflareZone(domain, cloudflareToken);
265
+
266
+ // Build configuration from discovered data
267
+ const discoveredConfig = {
268
+ domain,
269
+ environment,
270
+ // Cloudflare metadata
271
+ cloudflare: {
272
+ accountId: accountInfo.id,
273
+ accountName: accountInfo.name,
274
+ zoneId: zoneInfo.id,
275
+ zoneName: zoneInfo.name,
276
+ discoveredAt: new Date().toISOString()
277
+ },
278
+ // Generate standard configuration structure
279
+ ...this.generateStandardConfig(domain, accountInfo, zoneInfo),
280
+ // Mark as dynamically discovered
281
+ metadata: {
282
+ type: 'discovered',
283
+ source: 'cloudflare-api',
284
+ timestamp: new Date(),
285
+ version: '1.0.0'
286
+ }
287
+ };
288
+ console.log(` ✅ Successfully discovered configuration for ${domain}`);
289
+ return discoveredConfig;
290
+ } catch (error) {
291
+ console.error(` ❌ Discovery failed for ${domain}: ${error.message}`);
292
+ throw error;
293
+ }
294
+ }
295
+
296
+ /**
297
+ * Generate configuration from template
298
+ * @param {string} domain - Domain name
299
+ * @param {Object} options - Generation options
300
+ * @returns {Promise<Object>} Generated configuration
301
+ */
302
+ async generateFromTemplate(domain, options = {}) {
303
+ console.log(` 📋 Generating configuration from template for ${domain}`);
304
+ this.metrics.templateGenerations++;
305
+ const {
306
+ templateName = 'domain-standard',
307
+ environment = this.config.defaultEnvironment,
308
+ customValues = {}
309
+ } = options;
310
+
311
+ // Get template
312
+ const template = this.getTemplate(templateName);
313
+ if (!template) {
314
+ throw new Error(`Template not found: ${templateName}`);
315
+ }
316
+
317
+ // Process template with domain-specific values
318
+ const templateValues = {
319
+ domain,
320
+ environment,
321
+ domainKey: this.getDomainKey(domain),
322
+ displayName: this.getDisplayName(domain),
323
+ timestamp: new Date().toISOString(),
324
+ ...customValues
325
+ };
326
+ const generatedConfig = await this.processTemplate(template, templateValues);
327
+
328
+ // Apply cross-domain sharing if enabled
329
+ if (this.config.enableCrossDomainSharing) {
330
+ await this.applyCrossDomainSharing(generatedConfig);
331
+ }
332
+ generatedConfig.metadata = {
333
+ type: 'generated',
334
+ source: `template:${templateName}`,
335
+ timestamp: new Date(),
336
+ version: template.version || '1.0.0'
337
+ };
338
+ console.log(` ✅ Generated configuration from template: ${templateName}`);
339
+ return generatedConfig;
340
+ }
341
+
342
+ /**
343
+ * Process template with values
344
+ * @param {Object} template - Template object
345
+ * @param {Object} values - Template values
346
+ * @returns {Promise<Object>} Processed configuration
347
+ */
348
+ async processTemplate(template, values) {
349
+ // Deep clone template structure
350
+ const config = JSON.parse(JSON.stringify(template.structure || template));
351
+
352
+ // Process template variables
353
+ const processValue = obj => {
354
+ if (typeof obj === 'string') {
355
+ return obj.replace(/\{\{(\w+)\}\}/g, (match, key) => {
356
+ return values[key] || match;
357
+ });
358
+ } else if (Array.isArray(obj)) {
359
+ return obj.map(processValue);
360
+ } else if (obj && typeof obj === 'object') {
361
+ const processed = {};
362
+ for (const [key, value] of Object.entries(obj)) {
363
+ processed[key] = processValue(value);
364
+ }
365
+ return processed;
366
+ }
367
+ return obj;
368
+ };
369
+ return processValue(config);
370
+ }
371
+
372
+ /**
373
+ * Apply cross-domain configuration sharing
374
+ * @param {Object} config - Configuration to enhance
375
+ */
376
+ async applyCrossDomainSharing(config) {
377
+ const sharedConfigs = await this.getSharedConfigurations();
378
+ for (const sharedKey of this.config.sharedConfigKeys) {
379
+ if (sharedConfigs[sharedKey]) {
380
+ this.setNestedValue(config, sharedKey, sharedConfigs[sharedKey]);
381
+ }
382
+ }
383
+ }
384
+
385
+ /**
386
+ * Get shared configurations
387
+ * @returns {Promise<Object>} Shared configurations
388
+ */
389
+ async getSharedConfigurations() {
390
+ const sharedFile = join(this.paths.shared, 'shared-configs.json');
391
+ try {
392
+ await access(sharedFile);
393
+ const content = await readFile(sharedFile, 'utf8');
394
+ return JSON.parse(content);
395
+ } catch (error) {
396
+ if (error.code !== 'ENOENT') {
397
+ console.warn('⚠️ Failed to load shared configurations');
398
+ }
399
+ return {};
400
+ }
401
+ }
402
+
403
+ /**
404
+ * Validate configuration object
405
+ * @param {Object} config - Configuration to validate
406
+ * @returns {Promise<Object>} Validation result
407
+ */
408
+ async validateConfiguration(config) {
409
+ const errors = [];
410
+ const warnings = [];
411
+
412
+ // Basic structure validation
413
+ if (!config.domain) errors.push('Missing domain');
414
+ if (!config.environment) errors.push('Missing environment');
415
+
416
+ // Cloudflare validation
417
+ if (config.cloudflare) {
418
+ if (!config.cloudflare.accountId) errors.push('Missing Cloudflare account ID');
419
+ if (!config.cloudflare.zoneId) errors.push('Missing Cloudflare zone ID');
420
+ }
421
+
422
+ // Services validation
423
+ if (config.services) {
424
+ for (const [serviceName, serviceConfig] of Object.entries(config.services)) {
425
+ if (!serviceConfig[config.environment]) {
426
+ warnings.push(`Missing ${serviceName} configuration for ${config.environment}`);
427
+ }
428
+ }
429
+ }
430
+
431
+ // Database validation
432
+ if (config.databases && config.databases[config.environment]) {
433
+ const dbConfig = config.databases[config.environment];
434
+ if (!dbConfig.name) errors.push(`Missing database name for ${config.environment}`);
435
+ }
436
+
437
+ // CORS validation
438
+ if (config.corsOrigins && config.corsOrigins[config.environment]) {
439
+ const corsOrigins = config.corsOrigins[config.environment];
440
+ if (!Array.isArray(corsOrigins) || corsOrigins.length === 0) {
441
+ warnings.push(`No CORS origins defined for ${config.environment}`);
442
+ }
443
+ }
444
+ if (errors.length > 0) {
445
+ this.metrics.validationErrors++;
446
+ }
447
+ return {
448
+ valid: errors.length === 0,
449
+ errors,
450
+ warnings
451
+ };
452
+ }
453
+
454
+ /**
455
+ * Cache configuration with TTL
456
+ * @param {string} cacheKey - Cache key
457
+ * @param {Object} config - Configuration to cache
458
+ */
459
+ async cacheConfiguration(cacheKey, config) {
460
+ const cacheEntry = {
461
+ config,
462
+ cachedAt: new Date(),
463
+ expiresAt: new Date(Date.now() + this.config.cacheTTL),
464
+ size: JSON.stringify(config).length
465
+ };
466
+
467
+ // Compress if enabled
468
+ if (this.config.enableCompression && cacheEntry.size > 1024) {
469
+ // In a real implementation, you'd use a compression library
470
+ cacheEntry.compressed = true;
471
+ cacheEntry.originalSize = cacheEntry.size;
472
+ }
473
+ this.cache.set(cacheKey, cacheEntry);
474
+
475
+ // Update metadata
476
+ this.cacheMetadata.cacheEntries[cacheKey] = {
477
+ cachedAt: cacheEntry.cachedAt,
478
+ expiresAt: cacheEntry.expiresAt,
479
+ size: cacheEntry.size
480
+ };
481
+ await this.saveCacheMetadata();
482
+
483
+ // Write to disk cache
484
+ await this.writeToDiskCache(cacheKey, cacheEntry);
485
+ console.log(` 💾 Cached configuration: ${cacheKey}`);
486
+ }
487
+
488
+ /**
489
+ * Check if cache entry is valid
490
+ * @param {string} cacheKey - Cache key
491
+ * @returns {boolean} True if cache is valid
492
+ */
493
+ isCacheValid(cacheKey) {
494
+ const cacheEntry = this.cache.get(cacheKey);
495
+ if (!cacheEntry) return false;
496
+ return new Date() < cacheEntry.expiresAt;
497
+ }
498
+
499
+ /**
500
+ * Get cached configuration
501
+ * @param {string} cacheKey - Cache key
502
+ * @returns {Promise<Object>} Cached configuration
503
+ */
504
+ async getCachedConfig(cacheKey) {
505
+ const cacheEntry = this.cache.get(cacheKey);
506
+ if (cacheEntry) {
507
+ return cacheEntry.config;
508
+ }
509
+
510
+ // Try to load from disk cache
511
+ return await this.loadFromDiskCache(cacheKey);
512
+ }
513
+
514
+ /**
515
+ * Write cache entry to disk
516
+ * @param {string} cacheKey - Cache key
517
+ * @param {Object} cacheEntry - Cache entry
518
+ */
519
+ async writeToDiskCache(cacheKey, cacheEntry) {
520
+ try {
521
+ const cacheFile = join(this.paths.cache, `${cacheKey}.json`);
522
+ await writeFile(cacheFile, JSON.stringify(cacheEntry, null, 2));
523
+ } catch (error) {
524
+ console.warn(`⚠️ Failed to write disk cache: ${error.message}`);
525
+ }
526
+ }
527
+
528
+ /**
529
+ * Load configuration from disk cache
530
+ * @param {string} cacheKey - Cache key
531
+ * @returns {Promise<Object|null>} Cached configuration or null
532
+ */
533
+ async loadFromDiskCache(cacheKey) {
534
+ try {
535
+ const cacheFile = join(this.paths.cache, `${cacheKey}.json`);
536
+ await access(cacheFile);
537
+ const content = await readFile(cacheFile, 'utf8');
538
+ const cacheEntry = JSON.parse(content);
539
+
540
+ // Check expiration
541
+ if (new Date() < new Date(cacheEntry.expiresAt)) {
542
+ this.cache.set(cacheKey, cacheEntry);
543
+ return cacheEntry.config;
544
+ }
545
+ } catch (error) {
546
+ if (error.code !== 'ENOENT') {
547
+ console.warn(`⚠️ Failed to load disk cache: ${error.message}`);
548
+ }
549
+ }
550
+ return null;
551
+ }
552
+
553
+ /**
554
+ * Save configuration to persistent storage
555
+ * @param {string} domain - Domain name
556
+ * @param {Object} config - Configuration to save
557
+ * @param {string} environment - Environment
558
+ */
559
+ async saveConfiguration(domain, config, environment) {
560
+ const configDir = join(this.paths.cache, 'domains', domain);
561
+ try {
562
+ await access(configDir);
563
+ } catch {
564
+ await mkdir(configDir, {
565
+ recursive: true
566
+ });
567
+ }
568
+ const configFile = join(configDir, `${environment || 'default'}.json`);
569
+
570
+ // Create backup if file exists
571
+ try {
572
+ await access(configFile);
573
+ if (this.config.enableBackups) {
574
+ await this.createConfigBackup(configFile);
575
+ }
576
+ } catch {
577
+ // File doesn't exist, no backup needed
578
+ }
579
+
580
+ // Save configuration with metadata
581
+ const saveData = {
582
+ ...config,
583
+ savedAt: new Date(),
584
+ version: config.version || '1.0.0'
585
+ };
586
+ await writeFile(configFile, JSON.stringify(saveData, null, 2));
587
+
588
+ // Generate additional formats if requested
589
+ await this.generateOutputFormats(domain, config, environment);
590
+ console.log(` 💾 Saved configuration: ${domain}/${environment}`);
591
+ }
592
+
593
+ /**
594
+ * Load saved configuration
595
+ * @param {string} domain - Domain name
596
+ * @param {string} environment - Environment
597
+ * @returns {Promise<Object|null>} Saved configuration or null
598
+ */
599
+ async loadSavedConfig(domain, environment) {
600
+ const configFile = join(this.paths.cache, 'domains', domain, `${environment || 'default'}.json`);
601
+ try {
602
+ await access(configFile);
603
+ const content = await readFile(configFile, 'utf8');
604
+ const config = JSON.parse(content);
605
+
606
+ // Check if config is still valid (not too old)
607
+ const savedAt = new Date(config.savedAt);
608
+ const maxAge = 24 * 60 * 60 * 1000; // 24 hours
609
+
610
+ if (Date.now() - savedAt.getTime() < maxAge) {
611
+ return config;
612
+ }
613
+ } catch (error) {
614
+ if (error.code !== 'ENOENT') {
615
+ console.warn(`⚠️ Failed to load saved config for ${domain}: ${error.message}`);
616
+ }
617
+ }
618
+ return null;
619
+ }
620
+
621
+ /**
622
+ * Generate output formats for configuration
623
+ * @param {string} domain - Domain name
624
+ * @param {Object} config - Configuration
625
+ * @param {string} environment - Environment
626
+ */
627
+ async generateOutputFormats(domain, config, environment) {
628
+ if (!this.config.outputFormats.length) return;
629
+ const outputDir = join(this.paths.cache, 'output', domain);
630
+ try {
631
+ await access(outputDir);
632
+ } catch {
633
+ await mkdir(outputDir, {
634
+ recursive: true
635
+ });
636
+ }
637
+ for (const format of this.config.outputFormats) {
638
+ try {
639
+ const fileName = `${environment || 'default'}.${format}`;
640
+ const filePath = join(outputDir, fileName);
641
+ let content = '';
642
+ switch (format) {
643
+ case 'json':
644
+ content = JSON.stringify(config, null, 2);
645
+ break;
646
+ case 'js':
647
+ content = `// Auto-generated configuration for ${domain}
648
+ export const config = ${JSON.stringify(config, null, 2)};
649
+ export default config;`;
650
+ break;
651
+ case 'yaml':
652
+ content = this.convertToYaml(config);
653
+ break;
654
+ case 'env':
655
+ content = this.convertToEnv(config);
656
+ break;
657
+ default:
658
+ console.warn(`⚠️ Unknown output format: ${format}`);
659
+ continue;
660
+ }
661
+ await writeFile(filePath, content);
662
+ console.log(` 📄 Generated ${format.toUpperCase()}: ${fileName}`);
663
+ } catch (error) {
664
+ console.error(`❌ Failed to generate ${format} format: ${error.message}`);
665
+ }
666
+ }
667
+ }
668
+
669
+ /**
670
+ * Convert configuration to YAML format
671
+ * @param {Object} config - Configuration object
672
+ * @returns {string} YAML string
673
+ */
674
+ convertToYaml(config) {
675
+ // Simple YAML conversion - in production, use a proper YAML library
676
+ const yamlify = (obj, indent = 0) => {
677
+ const spaces = ' '.repeat(indent);
678
+ let yaml = '';
679
+ for (const [key, value] of Object.entries(obj)) {
680
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
681
+ yaml += `${spaces}${key}:\n`;
682
+ yaml += yamlify(value, indent + 1);
683
+ } else if (Array.isArray(value)) {
684
+ yaml += `${spaces}${key}:\n`;
685
+ value.forEach(item => {
686
+ yaml += `${spaces} - ${JSON.stringify(item)}\n`;
687
+ });
688
+ } else {
689
+ yaml += `${spaces}${key}: ${JSON.stringify(value)}\n`;
690
+ }
691
+ }
692
+ return yaml;
693
+ };
694
+ return `# Auto-generated configuration\n${yamlify(config)}`;
695
+ }
696
+
697
+ /**
698
+ * Convert configuration to environment variables
699
+ * @param {Object} config - Configuration object
700
+ * @returns {string} Environment variables string
701
+ */
702
+ convertToEnv(config) {
703
+ const envVars = [];
704
+ const flatten = (obj, prefix = '') => {
705
+ for (const [key, value] of Object.entries(obj)) {
706
+ const envKey = (prefix + key).toUpperCase().replace(/[^A-Z0-9]/g, '_');
707
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
708
+ flatten(value, `${prefix}${key}_`);
709
+ } else if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
710
+ envVars.push(`${envKey}=${value}`);
711
+ }
712
+ }
713
+ };
714
+ flatten(config);
715
+ return envVars.join('\n');
716
+ }
717
+
718
+ /**
719
+ * Create backup of configuration file
720
+ * @param {string} configFile - Configuration file path
721
+ */
722
+ async createConfigBackup(configFile) {
723
+ try {
724
+ const backupDir = join(this.paths.backups, new Date().toISOString().split('T')[0]);
725
+ try {
726
+ await access(backupDir);
727
+ } catch {
728
+ await mkdir(backupDir, {
729
+ recursive: true
730
+ });
731
+ }
732
+ const backupFile = join(backupDir, `${Date.now()}-${basename(configFile)}`);
733
+ const content = await readFile(configFile, 'utf8');
734
+ await writeFile(backupFile, content);
735
+ console.log(` 💾 Created backup: ${backupFile}`);
736
+ } catch (error) {
737
+ console.warn(`⚠️ Failed to create backup: ${error.message}`);
738
+ }
739
+ }
740
+
741
+ /**
742
+ * Invalidate cache for domain
743
+ * @param {string} domain - Domain name
744
+ * @param {string} environment - Environment (optional)
745
+ * @returns {Promise<void>}
746
+ */
747
+ async invalidateCache(domain, environment = null) {
748
+ const pattern = environment ? this.generateCacheKey(domain, environment) : domain;
749
+ let invalidated = 0;
750
+ for (const [key, entry] of this.cache.entries()) {
751
+ if (key.includes(pattern)) {
752
+ this.cache.delete(key);
753
+ delete this.cacheMetadata.cacheEntries[key];
754
+ invalidated++;
755
+ }
756
+ }
757
+ await this.saveCacheMetadata();
758
+ console.log(`🗑️ Invalidated ${invalidated} cache entries for ${domain}${environment ? `/${environment}` : ''}`);
759
+ }
760
+
761
+ /**
762
+ * Get cache statistics
763
+ * @returns {Object} Cache statistics
764
+ */
765
+ getCacheStatistics() {
766
+ const stats = {
767
+ entries: this.cache.size,
768
+ hitRate: this.metrics.cacheHits / (this.metrics.cacheHits + this.metrics.cacheMisses) * 100,
769
+ metrics: {
770
+ ...this.metrics
771
+ },
772
+ memory: {
773
+ cacheSize: 0,
774
+ totalEntries: this.cache.size
775
+ }
776
+ };
777
+
778
+ // Calculate memory usage
779
+ for (const [key, entry] of this.cache.entries()) {
780
+ stats.memory.cacheSize += entry.size || 0;
781
+ }
782
+ return stats;
783
+ }
784
+
785
+ /**
786
+ * Generate cache key
787
+ * @param {string} domain - Domain name
788
+ * @param {string} environment - Environment
789
+ * @returns {string} Cache key
790
+ */
791
+ generateCacheKey(domain, environment) {
792
+ return `${domain}:${environment}`;
793
+ }
794
+
795
+ /**
796
+ * Get domain key (sanitized version)
797
+ * @param {string} domain - Domain name
798
+ * @returns {string} Domain key
799
+ */
800
+ getDomainKey(domain) {
801
+ return domain.replace(/\./g, '').replace(/[^a-zA-Z0-9]/g, '');
802
+ }
803
+
804
+ /**
805
+ * Get display name for domain
806
+ * @param {string} domain - Domain name
807
+ * @returns {string} Display name
808
+ */
809
+ getDisplayName(domain) {
810
+ return domain.split('.')[0].split('-').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' ');
811
+ }
812
+
813
+ /**
814
+ * Get template by name
815
+ * @param {string} templateName - Template name
816
+ * @returns {Object|null} Template object
817
+ */
818
+ getTemplate(templateName) {
819
+ return this.templates.get(templateName);
820
+ }
821
+
822
+ /**
823
+ * Set nested value in object using dot notation
824
+ * @param {Object} obj - Target object
825
+ * @param {string} path - Path (e.g., 'a.b.c')
826
+ * @param {*} value - Value to set
827
+ */
828
+ setNestedValue(obj, path, value) {
829
+ const keys = path.split('.');
830
+ let current = obj;
831
+ for (let i = 0; i < keys.length - 1; i++) {
832
+ const key = keys[i];
833
+ if (!(key in current) || typeof current[key] !== 'object') {
834
+ current[key] = {};
835
+ }
836
+ current = current[key];
837
+ }
838
+ current[keys[keys.length - 1]] = value;
839
+ }
840
+
841
+ // Built-in template definitions
842
+
843
+ /**
844
+ * Get standard domain template
845
+ * @returns {Object} Standard template
846
+ */
847
+ getStandardDomainTemplate() {
848
+ return {
849
+ version: '1.0.0',
850
+ name: 'domain-standard',
851
+ description: 'Standard domain configuration template',
852
+ structure: {
853
+ domain: '{{domain}}',
854
+ environment: '{{environment}}',
855
+ name: '{{domainKey}}',
856
+ displayName: '{{displayName}}',
857
+ domains: {
858
+ production: '{{domain}}',
859
+ staging: '{{domain}}',
860
+ development: '{{domain}}'
861
+ },
862
+ services: {
863
+ frontend: {
864
+ production: 'https://{{domain}}',
865
+ staging: 'https://staging.{{domain}}',
866
+ development: 'http://localhost:3000'
867
+ },
868
+ api: {
869
+ production: 'https://{{domainKey}}-data-service.tamylatrading.workers.dev',
870
+ staging: 'https://{{domainKey}}-data-service-staging.tamylatrading.workers.dev',
871
+ development: 'http://localhost:8787'
872
+ },
873
+ auth: {
874
+ production: 'https://auth.{{domain}}',
875
+ staging: 'https://auth-staging.{{domain}}',
876
+ development: 'http://localhost:8787'
877
+ }
878
+ },
879
+ corsOrigins: {
880
+ production: ['https://{{domain}}', 'https://*.{{domain}}'],
881
+ staging: ['https://staging.{{domain}}', 'https://*.staging.{{domain}}'],
882
+ development: ['http://localhost:3000', 'http://localhost:8787']
883
+ },
884
+ databases: {
885
+ production: {
886
+ name: '{{domainKey}}-auth-db',
887
+ id: null
888
+ },
889
+ staging: {
890
+ name: '{{domainKey}}-auth-db-staging',
891
+ id: null
892
+ },
893
+ development: {
894
+ name: '{{domainKey}}-auth-db-local',
895
+ id: null
896
+ }
897
+ },
898
+ features: {
899
+ magicLinkAuth: true,
900
+ fileStorage: true,
901
+ userProfiles: true,
902
+ logging: true,
903
+ webhooks: false
904
+ },
905
+ settings: {
906
+ magicLinkExpiryMinutes: 15,
907
+ rateLimitWindowMs: 900000,
908
+ rateLimitMax: 100,
909
+ maxFileSize: 26214400,
910
+ allowedFileTypes: ['image/jpeg', 'image/png', 'image/webp', 'image/gif', 'application/pdf', 'video/mp4', 'video/webm', 'audio/mpeg', 'audio/wav']
911
+ }
912
+ }
913
+ };
914
+ }
915
+
916
+ /**
917
+ * Get minimal domain template
918
+ * @returns {Object} Minimal template
919
+ */
920
+ getMinimalDomainTemplate() {
921
+ return {
922
+ version: '1.0.0',
923
+ name: 'domain-minimal',
924
+ description: 'Minimal domain configuration template',
925
+ structure: {
926
+ domain: '{{domain}}',
927
+ environment: '{{environment}}',
928
+ name: '{{domainKey}}',
929
+ services: {
930
+ api: {
931
+ production: 'https://{{domainKey}}-data-service.tamylatrading.workers.dev'
932
+ }
933
+ },
934
+ features: {
935
+ magicLinkAuth: true,
936
+ logging: false
937
+ }
938
+ }
939
+ };
940
+ }
941
+
942
+ /**
943
+ * Get enterprise domain template
944
+ * @returns {Object} Enterprise template
945
+ */
946
+ getEnterpriseDomainTemplate() {
947
+ return {
948
+ version: '1.0.0',
949
+ name: 'domain-enterprise',
950
+ description: 'Enterprise domain configuration template',
951
+ structure: {
952
+ domain: '{{domain}}',
953
+ environment: '{{environment}}',
954
+ name: '{{domainKey}}',
955
+ displayName: '{{displayName}}',
956
+ domains: {
957
+ production: '{{domain}}',
958
+ staging: 'staging.{{domain}}',
959
+ development: 'dev.{{domain}}'
960
+ },
961
+ services: {
962
+ frontend: {
963
+ production: 'https://{{domain}}',
964
+ staging: 'https://staging.{{domain}}',
965
+ development: 'https://dev.{{domain}}'
966
+ },
967
+ api: {
968
+ production: 'https://api.{{domain}}',
969
+ staging: 'https://api-staging.{{domain}}',
970
+ development: 'https://api-dev.{{domain}}'
971
+ },
972
+ cdn: {
973
+ production: 'https://cdn.{{domain}}',
974
+ staging: 'https://cdn-staging.{{domain}}',
975
+ development: 'https://cdn-dev.{{domain}}'
976
+ }
977
+ },
978
+ features: {
979
+ magicLinkAuth: true,
980
+ fileStorage: true,
981
+ userProfiles: true,
982
+ logging: true,
983
+ webhooks: true,
984
+ analytics: true,
985
+ monitoring: true,
986
+ backup: true
987
+ },
988
+ security: {
989
+ enableCSP: true,
990
+ enableHSTS: true,
991
+ requireHTTPS: true,
992
+ rateLimiting: true
993
+ }
994
+ }
995
+ };
996
+ }
997
+
998
+ /**
999
+ * Get Cloudflare Worker template
1000
+ * @returns {Object} Worker template
1001
+ */
1002
+ getCloudflareWorkerTemplate() {
1003
+ return {
1004
+ version: '1.0.0',
1005
+ name: 'cloudflare-worker',
1006
+ description: 'Cloudflare Worker configuration template',
1007
+ structure: {
1008
+ name: '{{domainKey}}-data-service',
1009
+ main: 'src/worker/worker.js',
1010
+ compatibility_date: '2023-12-01',
1011
+ env: {
1012
+ production: {
1013
+ vars: {
1014
+ ENVIRONMENT: 'production',
1015
+ CORS_ORIGIN: 'https://{{domain}}'
1016
+ }
1017
+ }
1018
+ }
1019
+ }
1020
+ };
1021
+ }
1022
+
1023
+ /**
1024
+ * Get standard database template
1025
+ * @returns {Object} Database template
1026
+ */
1027
+ getStandardDatabaseTemplate() {
1028
+ return {
1029
+ version: '1.0.0',
1030
+ name: 'database-standard',
1031
+ description: 'Standard database configuration template',
1032
+ structure: {
1033
+ databases: [{
1034
+ binding: 'DB',
1035
+ database_name: '{{domainKey}}-auth-db',
1036
+ database_id: null
1037
+ }],
1038
+ migrations_table: 'migrations',
1039
+ backup_schedule: 'daily',
1040
+ retention_days: 30
1041
+ }
1042
+ };
1043
+ }
1044
+
1045
+ /**
1046
+ * Fetch Cloudflare accounts
1047
+ * @param {string} token - Cloudflare API token
1048
+ * @returns {Promise<Object>} Account information
1049
+ */
1050
+ async fetchCloudflareAccounts(token) {
1051
+ // Implementation would make actual API call
1052
+ // This is a placeholder for the real implementation
1053
+ return {
1054
+ id: 'account-id',
1055
+ name: 'Account Name'
1056
+ };
1057
+ }
1058
+
1059
+ /**
1060
+ * Fetch Cloudflare zone information
1061
+ * @param {string} domain - Domain name
1062
+ * @param {string} token - Cloudflare API token
1063
+ * @returns {Promise<Object>} Zone information
1064
+ */
1065
+ async fetchCloudflareZone(domain, token) {
1066
+ // Implementation would make actual API call
1067
+ // This is a placeholder for the real implementation
1068
+ return {
1069
+ id: 'zone-id',
1070
+ name: domain
1071
+ };
1072
+ }
1073
+
1074
+ /**
1075
+ * Generate standard configuration structure
1076
+ * @param {string} domain - Domain name
1077
+ * @param {Object} accountInfo - Account information
1078
+ * @param {Object} zoneInfo - Zone information
1079
+ * @returns {Object} Standard configuration
1080
+ */
1081
+ generateStandardConfig(domain, accountInfo, zoneInfo) {
1082
+ const domainKey = this.getDomainKey(domain);
1083
+ const displayName = this.getDisplayName(domain);
1084
+ return {
1085
+ name: domainKey,
1086
+ displayName,
1087
+ domains: {
1088
+ production: domain,
1089
+ staging: domain
1090
+ },
1091
+ services: {
1092
+ frontend: {
1093
+ production: `https://${domain}`,
1094
+ staging: `https://${domain}`
1095
+ },
1096
+ api: {
1097
+ production: `https://${domainKey}-data-service.tamylatrading.workers.dev`,
1098
+ staging: `https://${domainKey}-data-service-staging.tamylatrading.workers.dev`
1099
+ }
1100
+ },
1101
+ corsOrigins: {
1102
+ production: [`https://${domain}`, `https://*.${domain}`],
1103
+ staging: [`https://${domain}`, `https://*.${domain}`]
1104
+ },
1105
+ databases: {
1106
+ production: {
1107
+ name: `${domainKey}-auth-db`,
1108
+ id: null
1109
+ },
1110
+ staging: {
1111
+ name: `${domainKey}-auth-db-staging`,
1112
+ id: null
1113
+ }
1114
+ }
1115
+ };
1116
+ }
1117
+ }
1118
+
1119
+ // Legacy function exports for backward compatibility
1120
+
1121
+ /**
1122
+ * Simple configuration cache
1123
+ * @param {string} domain - Domain name
1124
+ * @param {Object} options - Cache options
1125
+ * @returns {ConfigurationCacheManager} Cache manager instance
1126
+ */
1127
+ export function createConfigCache(domain, options = {}) {
1128
+ const cache = new ConfigurationCacheManager(options);
1129
+ return {
1130
+ get: env => cache.getOrCreateDomainConfig(domain, {
1131
+ environment: env
1132
+ }),
1133
+ invalidate: env => cache.invalidateCache(domain, env),
1134
+ save: (config, env) => cache.saveConfiguration(domain, config, env),
1135
+ validate: config => cache.validateConfiguration(config)
1136
+ };
1137
+ }
1138
+
1139
+ /**
1140
+ * Generate configuration from template
1141
+ * @param {string} domain - Domain name
1142
+ * @param {string} templateName - Template name
1143
+ * @param {Object} values - Template values
1144
+ * @returns {Promise<Object>} Generated configuration
1145
+ */
1146
+ export async function generateConfig(domain, templateName = 'domain-standard', values = {}) {
1147
+ const cache = new ConfigurationCacheManager();
1148
+ return cache.generateFromTemplate(domain, {
1149
+ templateName,
1150
+ customValues: values
1151
+ });
1152
+ }
1153
+
1154
+ /**
1155
+ * Discover domain configuration
1156
+ * @param {string} domain - Domain name
1157
+ * @param {string} cloudflareToken - Cloudflare API token
1158
+ * @returns {Promise<Object>} Discovered configuration
1159
+ */
1160
+ export async function discoverConfig(domain, cloudflareToken) {
1161
+ const cache = new ConfigurationCacheManager({
1162
+ enableRuntimeDiscovery: true
1163
+ });
1164
+ return cache.discoverDomainConfiguration(domain, {
1165
+ cloudflareToken
1166
+ });
1167
+ }