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