@simonecoelhosfo/optimizely-mcp-server
Version:
Optimizely MCP Server for AI assistants with integrated CLI tools
142 lines (133 loc) • 5.3 kB
JavaScript
/**
* Project Entity Validator
* @description Validates entity operations against project capabilities
*
* Prevents common errors like:
* - Creating flags in Web Experimentation projects
* - Creating experiments in Feature Experimentation projects
* - Missing project type specification
*
* @author Optimizely MCP Server
* @version 1.0.0
*/
import { HardStopError, HardStopErrorType } from '../errors/HardStopError.js';
import { getLogger } from '../logging/Logger.js';
export class ProjectEntityValidator {
/**
* Feature Experimentation entities
*/
static FEATURE_ENTITIES = new Set([
'flag',
'ruleset',
'rule',
'environment' // Feature environments
]);
/**
* Web Experimentation entities
*/
static WEB_ENTITIES = new Set([
'experiment',
'campaign',
'page',
'extension'
]);
/**
* Shared entities (available in both project types)
*/
static SHARED_ENTITIES = new Set([
'audience',
'event',
'attribute',
'webhook',
'group',
'collaborator',
'project',
'variation' // Variations exist in both platforms
]);
/**
* Validate if an entity type is supported by the project
* @throws HardStopError if entity is not supported
*/
static validateEntityForProject(entityType, projectInfo, operation = 'create') {
const logger = getLogger();
// If no project info, we can't validate
if (!projectInfo) {
logger.warn({ entityType, operation }, 'No project info available for validation');
return;
}
// Determine project type
const isFeatureProject = projectInfo.is_flags_enabled === true ||
projectInfo.platform === 'custom';
const isWebProject = !isFeatureProject;
logger.debug({
entityType,
projectId: projectInfo.id,
isFeatureProject,
isWebProject,
is_flags_enabled: projectInfo.is_flags_enabled,
platform: projectInfo.platform
}, 'Validating entity for project type');
// Check if entity is supported
if (this.FEATURE_ENTITIES.has(entityType) && isWebProject) {
throw new HardStopError(HardStopErrorType.ENTITY_TYPE_MISMATCH, 'FEATURE_ENTITY_IN_WEB_PROJECT', `Cannot ${operation} ${entityType} in Web Experimentation project.
${entityType.charAt(0).toUpperCase() + entityType.slice(1)}s are only available in Feature Experimentation projects.
This project (${projectInfo.name || projectInfo.id}) is a Web Experimentation project.
To use ${entityType}s, you need a Feature Experimentation project with is_flags_enabled=true.`, 'ASK_USER', 400, ['retry', 'continue', 'auto_fix', 'ignore']);
}
if (this.WEB_ENTITIES.has(entityType) && isFeatureProject) {
throw new HardStopError(HardStopErrorType.ENTITY_TYPE_MISMATCH, 'WEB_ENTITY_IN_FEATURE_PROJECT', `Cannot ${operation} ${entityType} in Feature Experimentation project.
${entityType.charAt(0).toUpperCase() + entityType.slice(1)}s are only available in Web Experimentation projects.
This project (${projectInfo.name || projectInfo.id}) is a Feature Experimentation project.
To use ${entityType}s, you need a Web Experimentation project (standard project without is_flags_enabled).`, 'ASK_USER', 400, ['retry', 'continue', 'auto_fix', 'ignore']);
}
// Entity is either shared or valid for this project type
logger.debug({
entityType,
projectId: projectInfo.id,
validation: 'passed'
}, 'Entity validation passed');
}
/**
* Get a helpful message when project type is ambiguous
*/
static getProjectTypeGuidance() {
return `Project type not specified. Optimizely has two project types:
1. **Feature Experimentation Projects**
- For feature flags, remote configuration, and server-side A/B testing
- Supports: flags, rulesets, environments
- Create with: { "is_flags_enabled": true }
2. **Web Experimentation Projects**
- For website A/B testing, personalization, and visual editing
- Supports: experiments, campaigns, pages
- Create with: standard project (is_flags_enabled not set)
Please specify which type of project you want to create.`;
}
/**
* Determine if an entity type requires a specific project type
*/
static getRequiredProjectType(entityType) {
if (this.FEATURE_ENTITIES.has(entityType)) {
return 'feature';
}
if (this.WEB_ENTITIES.has(entityType)) {
return 'web';
}
return 'any';
}
/**
* Get supported entities for a project
*/
static getSupportedEntities(projectInfo) {
const isFeatureProject = projectInfo.is_flags_enabled === true ||
projectInfo.platform === 'custom';
const supported = [...this.SHARED_ENTITIES];
if (isFeatureProject) {
this.FEATURE_ENTITIES.forEach(e => supported.push(e));
}
else {
this.WEB_ENTITIES.forEach(e => supported.push(e));
}
return supported.sort();
}
}
//# sourceMappingURL=ProjectEntityValidator.js.map