@simonecoelhosfo/optimizely-mcp-server
Version:
Optimizely MCP Server for AI assistants with integrated CLI tools
635 lines • 27.2 kB
JavaScript
/**
* Registry for Orchestration Sample Templates
* Manages discovery and retrieval of educational orchestration examples
*/
export class OrchestrationSampleRegistry {
samples = new Map();
initialized = false;
constructor() {
// Don't load samples in constructor - use initialize() instead
}
/**
* Initialize the registry by loading all samples
*/
async initialize() {
if (this.initialized)
return;
// Load skeleton samples (sync)
this.loadSkeletonSamples();
// Load pattern samples (async)
await this.loadPatternSamples();
// Load complete examples (async)
await this.loadCompleteExamples();
this.initialized = true;
}
/**
* Get a specific sample
*/
async getSample(workflowType, sampleType = 'skeleton', complexity = 1) {
await this.initialize();
const key = `${workflowType}_${sampleType}_${complexity}`;
return this.samples.get(key) || null;
}
/**
* Get a sample by ID
*/
async getSampleById(sampleId) {
await this.initialize();
// Try direct lookup by ID
for (const sample of this.samples.values()) {
if (sample.id === sampleId) {
return sample;
}
}
// If not found by ID, try by key
return this.samples.get(sampleId) || null;
}
/**
* List available samples with optional filtering
*/
async listAvailable(filters) {
await this.initialize();
const filtered = Array.from(this.samples.values()).filter(sample => {
if (filters?.platform && sample.platform !== filters.platform && sample.platform !== 'both') {
return false;
}
if (filters?.workflow_type && sample.workflow_type !== filters.workflow_type) {
return false;
}
if (filters?.sample_type && sample.sample_type !== filters.sample_type) {
return false;
}
if (filters?.complexity && sample.complexity !== filters.complexity) {
return false;
}
return true;
});
return this.buildCatalog(filtered);
}
/**
* Get the default sample for new users
*/
async getDefaultSample() {
await this.initialize();
// Default to simplest A/B test skeleton
return await this.getSample('ab_test', 'skeleton', 1) || this.createMinimalSample();
}
/**
* Build a catalog from a set of samples
*/
buildCatalog(samples) {
const catalog = {
total_samples: samples.length,
by_workflow: {},
by_platform: {
web: [],
feature: [],
both: []
},
learning_path: [
"1. Start with 'skeleton' samples to understand basic structure",
"2. Review 'pattern' samples for common implementation approaches",
"3. Study 'complete_example' samples for production-ready templates",
"4. Use the Orchestration Bible for advanced patterns and troubleshooting"
]
};
// Group by workflow type
const workflowTypes = new Set(samples.map(s => s.workflow_type));
workflowTypes.forEach(workflowType => {
const workflowSamples = samples.filter(s => s.workflow_type === workflowType);
const firstSample = workflowSamples[0];
catalog.by_workflow[workflowType] = {
description: firstSample?.description || '',
available_types: [...new Set(workflowSamples.map(s => s.sample_type))],
complexity_levels: [...new Set(workflowSamples.map(s => s.complexity))].sort(),
platforms: [...new Set(workflowSamples.map(s => s.platform))],
entity_count: this.getEntityCount(workflowType),
typical_duration: this.getTypicalDuration(workflowType),
use_cases: firstSample?.use_cases || []
};
});
// Group by platform
samples.forEach(sample => {
if (sample.platform === 'both') {
catalog.by_platform.web.push(sample.workflow_type);
catalog.by_platform.feature.push(sample.workflow_type);
}
else {
catalog.by_platform[sample.platform].push(sample.workflow_type);
}
});
// Remove duplicates
Object.keys(catalog.by_platform).forEach(platform => {
catalog.by_platform[platform] = [...new Set(catalog.by_platform[platform])];
});
return catalog;
}
// Removed loadSamples - now using initialize() instead
/**
* Load skeleton samples
*/
loadSkeletonSamples() {
// A/B Test Skeleton
this.addSample({
id: 'ab_test_skeleton_1',
workflow_type: 'ab_test',
sample_type: 'skeleton',
complexity: 1,
platform: 'both',
name: 'Basic A/B Test Skeleton',
description: 'Minimal structure for an A/B test with two variations',
use_cases: ['Learning template structure', 'Quick test setup'],
template: {
id: 'skeleton_ab_test',
name: 'Basic A/B Test',
description: 'Skeleton template for A/B testing',
version: '1.0.0',
type: 'user',
platform: 'both',
author: 'system',
parameters: {
project_id: {
type: 'string',
required: true,
description: 'Project ID where test will be created'
},
test_name: {
type: 'string',
required: true,
description: 'Name for your A/B test'
}
},
template_format_version: 2,
steps: [
{
id: 'create_test',
type: 'template',
name: 'Create A/B Test',
template: {
entity_type: 'experiment',
operation: 'create',
mode: 'template',
template_data: {
project_id: '${project_id}',
name: '${test_name}',
type: 'a/b'
}
}
}
]
},
explanations: {
'parameters': 'Define the inputs your template will accept',
'steps': 'List of operations to execute in order',
'entity_type': 'Specifies the type of entity to create',
'template_data': 'Contains the entity creation data',
'${variable}': 'Variable substitution from parameters'
}
});
// Personalization Campaign Skeleton
this.addSample({
id: 'personalization_campaign_skeleton_1',
workflow_type: 'personalization_campaign',
sample_type: 'skeleton',
complexity: 1,
platform: 'web',
name: 'Basic Personalization Campaign Skeleton',
description: 'Minimal structure for a personalization campaign',
use_cases: ['Learning campaign structure', 'Multi-audience setup'],
template: {
id: 'skeleton_personalization',
name: 'Basic Personalization Campaign',
description: 'Skeleton for personalization workflow',
version: '1.0.0',
type: 'user',
platform: 'web',
author: 'system',
parameters: {
project_id: {
type: 'string',
required: true,
description: 'Web project ID'
},
campaign_name: {
type: 'string',
required: true,
description: 'Campaign name'
}
},
template_format_version: 2,
steps: [
{
id: 'create_campaign',
type: 'template',
name: 'Create Campaign Container',
template: {
entity_type: 'campaign',
operation: 'create',
mode: 'template',
template_data: {
project_id: '${project_id}',
name: '${campaign_name}'
}
}
},
{
id: 'create_experiment',
type: 'template',
name: 'Create Personalization Experiment',
template: {
entity_type: 'experiment',
operation: 'create',
mode: 'template',
template_data: {
project_id: '${project_id}',
name: '${campaign_name} Experience',
campaign_id: '${create_campaign.entity_id}'
}
},
depends_on: ['create_campaign']
}
]
},
explanations: {
'campaign_id': 'References the ID from previous step using ${step_id.entity_id}',
'depends_on': 'Ensures steps execute in correct order',
'entity_type': 'Specifies the type of entity to create',
'template_data': 'Contains the entity creation data'
}
});
}
/**
* Load pattern samples
*/
async loadPatternSamples() {
try {
const { entityCreationPatterns } = await import('./patterns/EntityCreationPatterns.js');
const { pluginPatterns } = await import('./patterns/PluginPatterns.js');
// Add event creation patterns
this.addSample({
id: 'event_creation_patterns_2',
workflow_type: 'multi_entity_creation',
sample_type: 'pattern',
complexity: 2,
platform: 'both',
name: 'Event Creation Patterns',
description: 'Common patterns for creating different types of events',
use_cases: [
'Conversion tracking',
'Click tracking',
'Custom event tracking',
'Multi-step funnel tracking'
],
template: {
id: 'event_patterns',
name: 'Event Creation Pattern Library',
description: 'Reusable patterns for event creation',
patterns: entityCreationPatterns.events
},
explanations: {
'${variable}': 'Variable substitution from parameters',
'${step_id.entity_id}': 'Reference created entity ID from previous step',
'entity_type': 'Specifies the type of entity to create',
'template_data': 'Contains the entity creation data'
},
best_practices: [
'Use meaningful event names that align with your analytics',
'Choose appropriate categories (conversion, other)',
'For click events, use specific CSS selectors',
'Test event firing in development environment first'
]
});
// Add attribute creation patterns
this.addSample({
id: 'attribute_creation_patterns_2',
workflow_type: 'multi_entity_creation',
sample_type: 'pattern',
complexity: 2,
platform: 'both',
name: 'Attribute Creation Patterns',
description: 'Common patterns for creating different types of attributes',
use_cases: [
'User segmentation',
'Behavioral targeting',
'Custom properties',
'List-based categorization'
],
template: {
id: 'attribute_patterns',
name: 'Attribute Creation Pattern Library',
description: 'Reusable patterns for attribute creation',
patterns: entityCreationPatterns.attributes
},
best_practices: [
'Use snake_case for attribute keys',
'Choose appropriate data types',
'For list attributes, predefine all possible values',
'Document attribute purpose clearly'
]
});
// Add audience creation patterns
this.addSample({
id: 'audience_creation_patterns_2',
workflow_type: 'multi_entity_creation',
sample_type: 'pattern',
complexity: 2,
platform: 'both',
name: 'Audience Creation Patterns',
description: 'Common patterns for creating audiences with different condition types',
use_cases: [
'Simple attribute matching',
'Complex AND conditions',
'Complex OR conditions',
'Nested condition groups'
],
template: {
id: 'audience_patterns',
name: 'Audience Creation Pattern Library',
description: 'Reusable patterns for audience creation',
patterns: entityCreationPatterns.audiences,
audience_references: entityCreationPatterns.audience_references
},
best_practices: [
'Create attributes before using them in audiences',
'Use meaningful audience names',
'Document targeting logic clearly',
'Test audience conditions thoroughly'
]
});
// Add extension creation patterns
this.addSample({
id: 'extension_creation_patterns_2',
workflow_type: 'multi_entity_creation',
sample_type: 'pattern',
complexity: 2,
platform: 'web',
name: 'Extension Creation Patterns',
description: 'Common patterns for creating custom code extensions',
use_cases: [
'Global tracking scripts',
'Custom analytics',
'Third-party integrations',
'UI enhancements'
],
template: {
id: 'extension_patterns',
name: 'Extension Creation Pattern Library',
description: 'Reusable patterns for extension creation',
patterns: entityCreationPatterns.extensions
},
best_practices: [
'Test JavaScript thoroughly before deployment',
'Use extension_point: "project_javascript" for global code',
'Keep extensions focused on single responsibility',
'Include error handling in JavaScript code'
]
});
// Add plugin patterns
this.addSample({
id: 'plugin_patterns_2',
workflow_type: 'multi_entity_creation',
sample_type: 'pattern',
complexity: 2,
platform: 'both',
name: 'Plugin (Custom Function) Patterns',
description: 'Common patterns for using custom JavaScript functions in orchestration',
use_cases: [
'Dynamic pricing calculations',
'Data validation and quality checks',
'External API integration',
'Data transformation',
'State management'
],
template: {
id: 'plugin_patterns',
name: 'Plugin Pattern Library',
description: 'Reusable patterns for custom functions',
patterns: pluginPatterns
},
best_practices: [
'Always handle errors with try-catch blocks',
'Use console.log for debugging visibility',
'Return clear success/failure indicators',
'Only request permissions you actually need',
'Set appropriate timeouts for external calls',
'Validate inputs before processing'
]
});
}
catch (error) {
// Silent fail for patterns - they're optional enhancements
}
}
/**
* Load complete examples from Orchestration Bible
*/
async loadCompleteExamples() {
// Load personalization campaign example
try {
const { personalizationCampaignComplete } = await import('./complete/PersonalizationCampaignExample.js');
this.addSample({
id: 'personalization_campaign_complete_3',
workflow_type: 'personalization_campaign',
sample_type: 'complete_example',
complexity: 3,
platform: 'web',
name: 'VIP Customer Personalization Campaign',
description: 'Production-ready personalization campaign with desktop & mobile VIP experiences',
use_cases: [
'VIP customer experiences',
'Device-specific personalization',
'Cookie-based audience targeting',
'Multi-experiment campaigns'
],
template: personalizationCampaignComplete,
best_practices: [
'Always test custom JavaScript in a development environment first',
'Use meaningful campaign and experiment names for easy identification',
'Set appropriate holdback percentages for measuring campaign impact',
'Include conversion metrics for all personalization experiments',
'Test audience conditions thoroughly before launch'
],
common_mistakes: [
{
mistake: 'Using string "true" instead of boolean true for cookie values',
example: 'cookie value: "true" (wrong) vs cookie value: true (correct)',
solution: 'Ensure cookie matching uses the correct data type'
},
{
mistake: 'Missing page_ids array in experiment creation',
example: 'page_ids: "${create_page.entity_id}" (wrong)',
solution: 'Always wrap page IDs in an array: page_ids: ["${create_page.entity_id}"]'
},
{
mistake: 'Forgetting depends_on for experiments',
example: 'Creating experiment without waiting for campaign',
solution: 'Add depends_on: ["create_campaign", "create_page", "create_audience"]'
}
],
customization_guide: [
{
path: 'parameters.vip_cookie_name',
description: 'Change the cookie used to identify VIP customers',
example: 'Set to "premium_member" or "loyalty_status"'
},
{
path: 'steps[5].template.inputs.changes[0].value',
description: 'Customize the VIP desktop experience JavaScript',
example: 'Add your own styling and DOM modifications'
},
{
path: 'steps[0].template.inputs.holdback',
description: 'Adjust campaign holdback percentage',
example: 'Change from 500 (5%) to 1000 (10%) for larger control group'
}
]
});
}
catch (error) {
// Silent fail for complete examples - they're optional
}
// Load feature flag A/B test example
try {
const { featureFlagABTestComplete } = await import('./complete/FeatureFlagABTestExample.js');
this.addSample({
id: 'feature_flag_ab_test_complete_3',
workflow_type: 'feature_flag_with_targeting',
sample_type: 'complete_example',
complexity: 3,
platform: 'feature',
name: 'Feature Flag A/B Test with Targeting',
description: 'Production-ready feature flag with A/B test for gradual rollout',
use_cases: [
'New feature testing',
'Gradual feature rollout',
'Beta user targeting',
'A/B testing with metrics'
],
template: featureFlagABTestComplete,
best_practices: [
'Create attributes before using them in audiences',
'Use meaningful flag keys that describe the feature',
'Start with low traffic percentages',
'Include both A/B test and default rollout rules',
'Use JSON variables for complex configurations'
],
customization_guide: [
{
path: 'parameters.test_percentage',
description: 'Adjust the percentage of users in the test',
example: 'Change from 50 to 20 for smaller test group'
},
{
path: 'steps[4].template.inputs.variations[1].variables.config',
description: 'Customize the treatment configuration',
example: 'Add your feature configuration JSON'
}
]
});
}
catch (error) {
// Silent fail for complete examples - they're optional
}
// Load e-commerce optimization example
try {
const { ecommerceOptimizationComplete } = await import('./complete/EcommerceOptimizationExample.js');
this.addSample({
id: 'ecommerce_optimization_complete_3',
workflow_type: 'campaign_with_experiments',
sample_type: 'complete_example',
complexity: 3,
platform: 'web',
name: 'E-commerce Checkout Optimization',
description: 'Complete workflow for optimizing checkout with A/B testing and personalization',
use_cases: [
'Checkout optimization',
'High-value customer personalization',
'Conversion tracking',
'Advanced analytics with extensions'
],
template: ecommerceOptimizationComplete,
best_practices: [
'Track multiple metrics including micro-conversions',
'Use custom attributes for dynamic segmentation',
'Create extensions for advanced tracking',
'Test JavaScript code thoroughly',
'Monitor checkout abandonment patterns'
],
common_mistakes: [
{
mistake: 'Not tracking intermediate funnel steps',
example: 'Only tracking final purchase',
solution: 'Track checkout_started, interactions, and abandonment'
},
{
mistake: 'Creating audiences before attributes',
example: 'Referencing cart_value before creating attribute',
solution: 'Always create attributes first'
}
]
});
}
catch (error) {
// Silent fail for complete examples - they're optional
}
}
/**
* Add a sample to the registry
*/
addSample(sample) {
const key = `${sample.workflow_type}_${sample.sample_type}_${sample.complexity}`;
this.samples.set(key, sample);
}
/**
* Create a minimal fallback sample
*/
createMinimalSample() {
return {
id: 'minimal_fallback',
workflow_type: 'ab_test',
sample_type: 'skeleton',
complexity: 1,
platform: 'both',
name: 'Minimal Template Structure',
description: 'Absolute minimum orchestration template',
use_cases: ['Emergency fallback'],
template: {
id: 'minimal',
name: 'Minimal Template',
parameters: {},
steps: []
}
};
}
/**
* Get typical entity count for a workflow type
*/
getEntityCount(workflowType) {
const counts = {
'personalization_campaign': '7-10 entities',
'ab_test': '3-5 entities',
'progressive_rollout': '2-4 entities',
'feature_flag_with_targeting': '4-6 entities',
'multi_entity_creation': '5-8 entities',
'campaign_with_experiments': '6-12 entities'
};
return counts[workflowType] || 'Variable';
}
/**
* Get typical duration for a workflow type
*/
getTypicalDuration(workflowType) {
const durations = {
'personalization_campaign': '5-10 minutes',
'ab_test': '2-3 minutes',
'progressive_rollout': '1-2 minutes',
'feature_flag_with_targeting': '3-5 minutes',
'multi_entity_creation': '4-7 minutes',
'campaign_with_experiments': '7-15 minutes'
};
return durations[workflowType] || 'Varies';
}
}
// Export singleton instance
export const sampleRegistry = new OrchestrationSampleRegistry();
//# sourceMappingURL=SampleRegistry.js.map