@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.
- package/CHANGELOG.md +564 -0
- package/LICENSE +21 -0
- package/README.md +1393 -0
- package/bin/README.md +71 -0
- package/bin/clodo-service.js +416 -0
- package/bin/security/security-cli.js +96 -0
- package/bin/service-management/README.md +74 -0
- package/bin/service-management/create-service.js +129 -0
- package/bin/service-management/init-service.js +102 -0
- package/bin/service-management/init-service.js.backup +889 -0
- package/bin/shared/config/customer-cli.js +293 -0
- package/dist/config/ConfigurationManager.js +159 -0
- package/dist/config/CustomerConfigCLI.js +220 -0
- package/dist/config/FeatureManager.js +426 -0
- package/dist/config/customers.js +441 -0
- package/dist/config/domains.js +180 -0
- package/dist/config/features.js +225 -0
- package/dist/config/index.js +6 -0
- package/dist/database/database-orchestrator.js +730 -0
- package/dist/database/index.js +4 -0
- package/dist/deployment/auditor.js +971 -0
- package/dist/deployment/index.js +10 -0
- package/dist/deployment/rollback-manager.js +523 -0
- package/dist/deployment/testers/api-tester.js +80 -0
- package/dist/deployment/testers/auth-tester.js +129 -0
- package/dist/deployment/testers/core.js +217 -0
- package/dist/deployment/testers/database-tester.js +105 -0
- package/dist/deployment/testers/index.js +74 -0
- package/dist/deployment/testers/load-tester.js +120 -0
- package/dist/deployment/testers/performance-tester.js +105 -0
- package/dist/deployment/validator.js +558 -0
- package/dist/deployment/wrangler-deployer.js +574 -0
- package/dist/handlers/GenericRouteHandler.js +532 -0
- package/dist/index.js +39 -0
- package/dist/migration/MigrationAdapters.js +562 -0
- package/dist/modules/ModuleManager.js +668 -0
- package/dist/modules/security.js +98 -0
- package/dist/orchestration/cross-domain-coordinator.js +1083 -0
- package/dist/orchestration/index.js +5 -0
- package/dist/orchestration/modules/DeploymentCoordinator.js +258 -0
- package/dist/orchestration/modules/DomainResolver.js +196 -0
- package/dist/orchestration/modules/StateManager.js +332 -0
- package/dist/orchestration/multi-domain-orchestrator.js +255 -0
- package/dist/routing/EnhancedRouter.js +158 -0
- package/dist/schema/SchemaManager.js +778 -0
- package/dist/security/ConfigurationValidator.js +490 -0
- package/dist/security/DeploymentManager.js +208 -0
- package/dist/security/SecretGenerator.js +142 -0
- package/dist/security/SecurityCLI.js +228 -0
- package/dist/security/index.js +51 -0
- package/dist/security/patterns/environment-rules.js +66 -0
- package/dist/security/patterns/insecure-patterns.js +21 -0
- package/dist/service-management/ConfirmationEngine.js +411 -0
- package/dist/service-management/ErrorTracker.js +294 -0
- package/dist/service-management/GenerationEngine.js +3109 -0
- package/dist/service-management/InputCollector.js +237 -0
- package/dist/service-management/ServiceCreator.js +229 -0
- package/dist/service-management/ServiceInitializer.js +448 -0
- package/dist/service-management/ServiceOrchestrator.js +638 -0
- package/dist/service-management/handlers/ConfigMutator.js +130 -0
- package/dist/service-management/handlers/ConfirmationHandler.js +71 -0
- package/dist/service-management/handlers/GenerationHandler.js +80 -0
- package/dist/service-management/handlers/InputHandler.js +59 -0
- package/dist/service-management/handlers/ValidationHandler.js +203 -0
- package/dist/service-management/index.js +7 -0
- package/dist/services/GenericDataService.js +488 -0
- package/dist/shared/cloudflare/domain-discovery.js +562 -0
- package/dist/shared/cloudflare/domain-manager.js +912 -0
- package/dist/shared/cloudflare/index.js +8 -0
- package/dist/shared/cloudflare/ops.js +387 -0
- package/dist/shared/config/cache.js +1167 -0
- package/dist/shared/config/command-config-manager.js +174 -0
- package/dist/shared/config/customer-cli.js +258 -0
- package/dist/shared/config/index.js +9 -0
- package/dist/shared/config/manager.js +289 -0
- package/dist/shared/database/connection-manager.js +338 -0
- package/dist/shared/database/index.js +7 -0
- package/dist/shared/database/orchestrator.js +632 -0
- package/dist/shared/deployment/auditor.js +971 -0
- package/dist/shared/deployment/index.js +10 -0
- package/dist/shared/deployment/rollback-manager.js +523 -0
- package/dist/shared/deployment/validator.js +558 -0
- package/dist/shared/index.js +32 -0
- package/dist/shared/monitoring/health-checker.js +250 -0
- package/dist/shared/monitoring/index.js +8 -0
- package/dist/shared/monitoring/memory-manager.js +382 -0
- package/dist/shared/monitoring/production-monitor.js +390 -0
- package/dist/shared/production-tester/api-tester.js +80 -0
- package/dist/shared/production-tester/auth-tester.js +129 -0
- package/dist/shared/production-tester/core.js +217 -0
- package/dist/shared/production-tester/database-tester.js +105 -0
- package/dist/shared/production-tester/index.js +74 -0
- package/dist/shared/production-tester/load-tester.js +120 -0
- package/dist/shared/production-tester/performance-tester.js +105 -0
- package/dist/shared/security/api-token-manager.js +296 -0
- package/dist/shared/security/index.js +8 -0
- package/dist/shared/security/secret-generator.js +918 -0
- package/dist/shared/security/secure-token-manager.js +379 -0
- package/dist/shared/utils/error-recovery.js +240 -0
- package/dist/shared/utils/graceful-shutdown-manager.js +380 -0
- package/dist/shared/utils/index.js +9 -0
- package/dist/shared/utils/interactive-prompts.js +134 -0
- package/dist/shared/utils/rate-limiter.js +249 -0
- package/dist/utils/ErrorHandler.js +173 -0
- package/dist/utils/deployment/config-cache.js +1160 -0
- package/dist/utils/deployment/index.js +6 -0
- package/dist/utils/deployment/interactive-prompts.js +97 -0
- package/dist/utils/deployment/secret-generator.js +896 -0
- package/dist/utils/dirname-helper.js +35 -0
- package/dist/utils/domain-config.js +159 -0
- package/dist/utils/error-recovery.js +240 -0
- package/dist/utils/esm-helper.js +52 -0
- package/dist/utils/framework-config.js +481 -0
- package/dist/utils/graceful-shutdown-manager.js +379 -0
- package/dist/utils/health-checker.js +114 -0
- package/dist/utils/index.js +36 -0
- package/dist/utils/prompt-handler.js +98 -0
- package/dist/utils/usage-tracker.js +252 -0
- package/dist/utils/validation.js +112 -0
- package/dist/version/VersionDetector.js +723 -0
- package/dist/worker/index.js +4 -0
- package/dist/worker/integration.js +332 -0
- package/docs/FRAMEWORK-ARCHITECTURE-OVERVIEW.md +206 -0
- package/docs/INTEGRATION_GUIDE.md +2045 -0
- package/docs/README.md +82 -0
- package/docs/SECURITY.md +242 -0
- package/docs/deployment/deployment-guide.md +540 -0
- package/docs/overview.md +280 -0
- package/package.json +176 -0
- package/types/index.d.ts +575 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clodo Framework - Usage Tracking & License Management
|
|
3
|
+
*
|
|
4
|
+
* Tracks usage for free tier limitations and validates paid subscriptions.
|
|
5
|
+
* Free tier: 3 services max, development environment only.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import os from 'os';
|
|
11
|
+
import crypto from 'crypto';
|
|
12
|
+
export class UsageTracker {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.configDir = path.join(os.homedir(), '.clodo-framework');
|
|
15
|
+
this.usageFile = path.join(this.configDir, 'usage.json');
|
|
16
|
+
this.licenseFile = path.join(this.configDir, 'license.json');
|
|
17
|
+
this.ensureConfigDir();
|
|
18
|
+
}
|
|
19
|
+
ensureConfigDir() {
|
|
20
|
+
if (!fs.existsSync(this.configDir)) {
|
|
21
|
+
fs.mkdirSync(this.configDir, {
|
|
22
|
+
recursive: true
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
getUsage() {
|
|
27
|
+
try {
|
|
28
|
+
if (!fs.existsSync(this.usageFile)) {
|
|
29
|
+
return this.getDefaultUsage();
|
|
30
|
+
}
|
|
31
|
+
const data = fs.readFileSync(this.usageFile, 'utf8');
|
|
32
|
+
return JSON.parse(data);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.warn('Warning: Could not read usage data, resetting to defaults');
|
|
35
|
+
return this.getDefaultUsage();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
getDefaultUsage() {
|
|
39
|
+
return {
|
|
40
|
+
servicesCreated: 0,
|
|
41
|
+
lastReset: new Date().toISOString(),
|
|
42
|
+
version: '1.0.0'
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
saveUsage(usage) {
|
|
46
|
+
try {
|
|
47
|
+
fs.writeFileSync(this.usageFile, JSON.stringify(usage, null, 2));
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.warn('Warning: Could not save usage data');
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
getLicense() {
|
|
53
|
+
try {
|
|
54
|
+
if (!fs.existsSync(this.licenseFile)) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
const data = fs.readFileSync(this.licenseFile, 'utf8');
|
|
58
|
+
return JSON.parse(data);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
saveLicense(license) {
|
|
64
|
+
try {
|
|
65
|
+
fs.writeFileSync(this.licenseFile, JSON.stringify(license, null, 2));
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error('Error: Could not save license data');
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
isPaidUser() {
|
|
71
|
+
const license = this.getLicense();
|
|
72
|
+
if (!license) return false;
|
|
73
|
+
|
|
74
|
+
// Founder/Admin licenses are always valid (no expiry)
|
|
75
|
+
if (license.plan === 'founder' || license.plan === 'admin') {
|
|
76
|
+
return license.active;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Check if regular license is valid and not expired
|
|
80
|
+
const now = new Date();
|
|
81
|
+
const expiry = new Date(license.expiry);
|
|
82
|
+
return license.active && expiry > now;
|
|
83
|
+
}
|
|
84
|
+
getPlanLimits() {
|
|
85
|
+
const license = this.getLicense();
|
|
86
|
+
|
|
87
|
+
// Founder/Admin licenses have unlimited access
|
|
88
|
+
if (license && (license.plan === 'founder' || license.plan === 'admin')) {
|
|
89
|
+
return {
|
|
90
|
+
maxServices: -1,
|
|
91
|
+
// unlimited
|
|
92
|
+
allowedEnvironments: ['development', 'staging', 'production'],
|
|
93
|
+
premiumFeatures: true,
|
|
94
|
+
prioritySupport: true,
|
|
95
|
+
founderAccess: true
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (this.isPaidUser()) {
|
|
99
|
+
return {
|
|
100
|
+
maxServices: -1,
|
|
101
|
+
// unlimited
|
|
102
|
+
allowedEnvironments: ['development', 'staging', 'production'],
|
|
103
|
+
premiumFeatures: true,
|
|
104
|
+
prioritySupport: true,
|
|
105
|
+
founderAccess: false
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
maxServices: 3,
|
|
110
|
+
allowedEnvironments: ['development'],
|
|
111
|
+
premiumFeatures: false,
|
|
112
|
+
prioritySupport: false,
|
|
113
|
+
founderAccess: false
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
canCreateService(environment = 'development') {
|
|
117
|
+
const limits = this.getPlanLimits();
|
|
118
|
+
const usage = this.getUsage();
|
|
119
|
+
|
|
120
|
+
// Check service count limit
|
|
121
|
+
if (limits.maxServices !== -1 && usage.servicesCreated >= limits.maxServices) {
|
|
122
|
+
return {
|
|
123
|
+
allowed: false,
|
|
124
|
+
reason: 'service_limit',
|
|
125
|
+
message: `Free tier limited to ${limits.maxServices} services. Upgrade to create more!`
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Check environment restriction
|
|
130
|
+
if (!limits.allowedEnvironments.includes(environment)) {
|
|
131
|
+
return {
|
|
132
|
+
allowed: false,
|
|
133
|
+
reason: 'environment_restricted',
|
|
134
|
+
message: `Free tier only allows ${limits.allowedEnvironments.join(', ')} environments. Upgrade for all environments!`
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
allowed: true
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
recordServiceCreation(environment = 'development') {
|
|
142
|
+
const usage = this.getUsage();
|
|
143
|
+
usage.servicesCreated += 1;
|
|
144
|
+
this.saveUsage(usage);
|
|
145
|
+
}
|
|
146
|
+
getUpgradeMessage(reason) {
|
|
147
|
+
const baseMessage = `
|
|
148
|
+
🎉 Love Clodo Framework? Upgrade to unlock unlimited potential!
|
|
149
|
+
|
|
150
|
+
✨ Unlimited services across all environments
|
|
151
|
+
🚀 Premium templates & advanced features
|
|
152
|
+
🎯 Priority support & updates
|
|
153
|
+
💰 Consulting sessions at $69/hour
|
|
154
|
+
|
|
155
|
+
Choose your plan:
|
|
156
|
+
• Monthly: $19/month
|
|
157
|
+
• Annual: $189/year (save 17%)
|
|
158
|
+
• Lifetime: $999 (one-time payment)
|
|
159
|
+
|
|
160
|
+
Upgrade now: https://clodo-framework.com/pricing
|
|
161
|
+
Or run: clodo-service upgrade
|
|
162
|
+
|
|
163
|
+
Your current usage: ${this.getUsage().servicesCreated}/3 services created
|
|
164
|
+
`;
|
|
165
|
+
return baseMessage;
|
|
166
|
+
}
|
|
167
|
+
showUpgradePrompt(reason) {
|
|
168
|
+
console.log('\n' + '='.repeat(60));
|
|
169
|
+
console.log('🚀 Clodo Framework - Upgrade Required');
|
|
170
|
+
console.log('='.repeat(60));
|
|
171
|
+
console.log(this.getUpgradeMessage(reason));
|
|
172
|
+
console.log('='.repeat(60));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// For future use - validate license keys
|
|
176
|
+
validateLicenseKey(key) {
|
|
177
|
+
// This would validate against a server or use cryptography
|
|
178
|
+
// For now, just check format
|
|
179
|
+
return key && key.length === 32 && /^[a-f0-9]+$/.test(key);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Generate founder/admin license (unlimited, never expires)
|
|
183
|
+
generateFounderLicense(userEmail = 'founder', userName = 'Framework Builder') {
|
|
184
|
+
const license = {
|
|
185
|
+
id: crypto.randomUUID(),
|
|
186
|
+
plan: 'founder',
|
|
187
|
+
active: true,
|
|
188
|
+
activated: new Date().toISOString(),
|
|
189
|
+
expiry: '2099-12-31T23:59:59.999Z',
|
|
190
|
+
// Far future date (never expires)
|
|
191
|
+
userEmail: userEmail,
|
|
192
|
+
userName: userName,
|
|
193
|
+
specialAccess: true,
|
|
194
|
+
generated: new Date().toISOString()
|
|
195
|
+
};
|
|
196
|
+
this.saveLicense(license);
|
|
197
|
+
return license;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Generate admin license for selected team members
|
|
201
|
+
generateAdminLicense(userEmail, userName = 'Admin User') {
|
|
202
|
+
const license = {
|
|
203
|
+
id: crypto.randomUUID(),
|
|
204
|
+
plan: 'admin',
|
|
205
|
+
active: true,
|
|
206
|
+
activated: new Date().toISOString(),
|
|
207
|
+
expiry: '2099-12-31T23:59:59.999Z',
|
|
208
|
+
// Far future date (never expires)
|
|
209
|
+
userEmail: userEmail,
|
|
210
|
+
userName: userName,
|
|
211
|
+
specialAccess: true,
|
|
212
|
+
generated: new Date().toISOString()
|
|
213
|
+
};
|
|
214
|
+
this.saveLicense(license);
|
|
215
|
+
return license;
|
|
216
|
+
}
|
|
217
|
+
getExpiryDate(plan) {
|
|
218
|
+
const now = new Date();
|
|
219
|
+
switch (plan) {
|
|
220
|
+
case 'monthly':
|
|
221
|
+
return new Date(now.setMonth(now.getMonth() + 1)).toISOString();
|
|
222
|
+
case 'annual':
|
|
223
|
+
return new Date(now.setFullYear(now.getFullYear() + 1)).toISOString();
|
|
224
|
+
case 'lifetime':
|
|
225
|
+
return new Date(now.setFullYear(now.getFullYear() + 100)).toISOString();
|
|
226
|
+
default:
|
|
227
|
+
return new Date(now.setMonth(now.getMonth() + 1)).toISOString();
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
getUsageStats() {
|
|
231
|
+
const usage = this.getUsage();
|
|
232
|
+
const limits = this.getPlanLimits();
|
|
233
|
+
const license = this.getLicense();
|
|
234
|
+
return {
|
|
235
|
+
currentUsage: usage.servicesCreated,
|
|
236
|
+
limit: limits.maxServices,
|
|
237
|
+
plan: this.isPaidUser() ? license.plan : 'free',
|
|
238
|
+
environments: limits.allowedEnvironments,
|
|
239
|
+
premiumFeatures: limits.premiumFeatures,
|
|
240
|
+
daysUntilExpiry: license ? this.getDaysUntilExpiry(license.expiry) : null
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
getDaysUntilExpiry(expiryDate) {
|
|
244
|
+
const expiry = new Date(expiryDate);
|
|
245
|
+
const now = new Date();
|
|
246
|
+
const diffTime = expiry - now;
|
|
247
|
+
return Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Export singleton instance
|
|
252
|
+
export const usageTracker = new UsageTracker();
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation utilities for Clodo Framework service creation
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Validate service name format
|
|
7
|
+
* - Only lowercase letters, numbers, and hyphens
|
|
8
|
+
* - No leading/trailing hyphens
|
|
9
|
+
* - At least 3 characters
|
|
10
|
+
*/
|
|
11
|
+
export function validateServiceName(name) {
|
|
12
|
+
if (!name || typeof name !== 'string') {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Check length
|
|
17
|
+
if (name.length < 3 || name.length > 50) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Check format: lowercase, numbers, hyphens only
|
|
22
|
+
if (!/^[a-z0-9-]+$/.test(name)) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// No leading or trailing hyphens
|
|
27
|
+
if (name.startsWith('-') || name.endsWith('-')) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// No consecutive hyphens
|
|
32
|
+
if (name.includes('--')) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Validate domain name format
|
|
40
|
+
* - Basic domain name validation
|
|
41
|
+
* - Supports subdomains
|
|
42
|
+
*/
|
|
43
|
+
export function validateDomainName(domain) {
|
|
44
|
+
if (!domain || typeof domain !== 'string') {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Remove trailing dot if present
|
|
49
|
+
domain = domain.replace(/\.$/, '');
|
|
50
|
+
|
|
51
|
+
// Check basic format
|
|
52
|
+
const domainRegex = /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
|
|
53
|
+
return domainRegex.test(domain) && domain.length <= 253;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Validate Cloudflare API token format
|
|
58
|
+
* - Basic length and character validation
|
|
59
|
+
*/
|
|
60
|
+
export function validateCloudflareToken(token) {
|
|
61
|
+
if (!token || typeof token !== 'string') {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// API tokens are typically long alphanumeric strings
|
|
66
|
+
return token.length >= 20 && /^[a-zA-Z0-9_-]+$/.test(token);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Validate Cloudflare Account/Zone ID format
|
|
71
|
+
* - 32 hexadecimal characters
|
|
72
|
+
*/
|
|
73
|
+
export function validateCloudflareId(id) {
|
|
74
|
+
if (!id || typeof id !== 'string') {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
return /^[a-f0-9]{32}$/i.test(id);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Validate service type
|
|
82
|
+
*/
|
|
83
|
+
export function validateServiceType(type) {
|
|
84
|
+
const validTypes = ['data-service', 'auth-service', 'content-service', 'api-gateway', 'generic'];
|
|
85
|
+
return validTypes.includes(type);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Validate environment
|
|
90
|
+
*/
|
|
91
|
+
export function validateEnvironment(env) {
|
|
92
|
+
const validEnvs = ['development', 'staging', 'production'];
|
|
93
|
+
return validEnvs.includes(env);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Validate feature configuration
|
|
98
|
+
*/
|
|
99
|
+
export function validateFeatures(features, serviceType) {
|
|
100
|
+
if (!features || typeof features !== 'object') {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Ensure required base features are present
|
|
105
|
+
const requiredBaseFeatures = ['logging', 'monitoring', 'errorReporting'];
|
|
106
|
+
for (const feature of requiredBaseFeatures) {
|
|
107
|
+
if (!(feature in features)) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return true;
|
|
112
|
+
}
|