Workflow Templates
Comprehensive guide to creating, managing, and sharing workflow templates in Axon OS.
Overview
Workflow templates provide a powerful way to standardize, share, and accelerate workflow development in Axon OS. Templates encapsulate best practices, common patterns, and reusable components that can be customized for specific use cases.
Key Features
- Template Library: Extensive collection of pre-built templates
- Custom Templates: Create and share your own templates
- Parameterization: Configurable templates with dynamic parameters
- Version Management: Track template versions and changes
- Template Marketplace: Community-driven template sharing
- Import/Export: Share templates across environments
Template Structure
Template Definition
interface WorkflowTemplate {
id: string;
name: string;
version: string;
description: string;
category: TemplateCategory;
tags: string[];
author: TemplateAuthor;
license: string;
// Template configuration
parameters: TemplateParameter[];
requirements: TemplateRequirement[];
// Workflow definition
workflow: WorkflowDefinition;
// Template metadata
metadata: TemplateMetadata;
// Documentation and examples
documentation: TemplateDocumentation;
examples: TemplateExample[];
// Usage and analytics
usage: TemplateUsage;
}
enum TemplateCategory {
DATA_PROCESSING = 'data_processing',
API_INTEGRATION = 'api_integration',
ETL = 'etl',
MONITORING = 'monitoring',
AUTOMATION = 'automation',
MACHINE_LEARNING = 'machine_learning',
ANALYTICS = 'analytics',
COMMUNICATION = 'communication',
DEVOPS = 'devops',
BUSINESS_PROCESS = 'business_process',
CUSTOM = 'custom'
}
interface TemplateAuthor {
name: string;
email: string;
organization?: string;
website?: string;
github?: string;
}
interface TemplateParameter {
id: string;
name: string;
type: ParameterType;
description: string;
required: boolean;
defaultValue?: any;
validation?: ParameterValidation;
group?: string;
displayOrder: number;
helpText?: string;
examples?: any[];
}
enum ParameterType {
STRING = 'string',
NUMBER = 'number',
BOOLEAN = 'boolean',
SELECT = 'select',
MULTI_SELECT = 'multi_select',
OBJECT = 'object',
ARRAY = 'array',
FILE = 'file',
URL = 'url',
EMAIL = 'email',
PASSWORD = 'password',
CONNECTION = 'connection',
NODE_REFERENCE = 'node_reference'
}
interface ParameterValidation {
min?: number;
max?: number;
minLength?: number;
maxLength?: number;
pattern?: string;
options?: ParameterOption[];
customValidator?: string;
}
interface ParameterOption {
value: any;
label: string;
description?: string;
disabled?: boolean;
}
interface TemplateRequirement {
type: 'node' | 'connection' | 'permission' | 'environment';
identifier: string;
version?: string;
optional?: boolean;
description: string;
}
interface TemplateMetadata {
created: Date;
updated: Date;
compatibility: CompatibilityInfo;
difficulty: 'beginner' | 'intermediate' | 'advanced' | 'expert';
estimatedSetupTime: number; // minutes
industryTags: string[];
useCases: string[];
maturityLevel: 'experimental' | 'beta' | 'stable' | 'deprecated';
}
interface TemplateDocumentation {
overview: string;
quickStart: string;
setupInstructions: string;
configuration: string;
troubleshooting: string;
bestPractices: string;
changelog: ChangelogEntry[];
}
interface TemplateExample {
id: string;
name: string;
description: string;
parameters: Record<string, any>;
expectedOutput?: any;
notes?: string;
}
Template Parameter System
class TemplateParameterManager {
processParameters(
template: WorkflowTemplate,
userInputs: Record<string, any>
): ProcessedParameters {
const processedParams: Record<string, any> = {};
const errors: ParameterError[] = [];
const warnings: ParameterWarning[] = [];
// Process each parameter
for (const param of template.parameters) {
try {
const value = this.processParameter(param, userInputs[param.id]);
processedParams[param.id] = value;
} catch (error) {
errors.push({
parameterId: param.id,
message: error.message,
value: userInputs[param.id]
});
}
}
// Check for required parameters
for (const param of template.parameters) {
if (param.required && !(param.id in processedParams)) {
errors.push({
parameterId: param.id,
message: 'Required parameter is missing',
value: undefined
});
}
}
return {
parameters: processedParams,
errors,
warnings,
valid: errors.length === 0
};
}
private processParameter(
param: TemplateParameter,
value: any
): any {
// Use default if no value provided
if (value === undefined || value === null) {
if (param.defaultValue !== undefined) {
value = param.defaultValue;
} else if (param.required) {
throw new Error(`Required parameter ${param.name} is missing`);
} else {
return null;
}
}
// Type conversion and validation
const convertedValue = this.convertParameterType(value, param.type);
this.validateParameter(convertedValue, param);
return convertedValue;
}
private convertParameterType(value: any, type: ParameterType): any {
switch (type) {
case ParameterType.STRING:
return String(value);
case ParameterType.NUMBER:
const num = Number(value);
if (isNaN(num)) {
throw new Error(`Cannot convert "${value}" to number`);
}
return num;
case ParameterType.BOOLEAN:
if (typeof value === 'boolean') return value;
if (typeof value === 'string') {
const lower = value.toLowerCase();
if (lower === 'true' || lower === '1' || lower === 'yes') return true;
if (lower === 'false' || lower === '0' || lower === 'no') return false;
}
throw new Error(`Cannot convert "${value}" to boolean`);
case ParameterType.ARRAY:
if (Array.isArray(value)) return value;
if (typeof value === 'string') {
try {
return JSON.parse(value);
} catch {
return value.split(',').map(s => s.trim());
}
}
throw new Error(`Cannot convert "${value}" to array`);
case ParameterType.OBJECT:
if (typeof value === 'object' && value !== null) return value;
if (typeof value === 'string') {
try {
return JSON.parse(value);
} catch {
throw new Error(`Invalid JSON format for object parameter`);
}
}
throw new Error(`Cannot convert "${value}" to object`);
default:
return value;
}
}
private validateParameter(value: any, param: TemplateParameter): void {
if (!param.validation) return;
const validation = param.validation;
// Min/Max validation
if (typeof value === 'number') {
if (validation.min !== undefined && value < validation.min) {
throw new Error(`Value ${value} is less than minimum ${validation.min}`);
}
if (validation.max !== undefined && value > validation.max) {
throw new Error(`Value ${value} is greater than maximum ${validation.max}`);
}
}
// Length validation
if (typeof value === 'string') {
if (validation.minLength && value.length < validation.minLength) {
throw new Error(`String length ${value.length} is less than minimum ${validation.minLength}`);
}
if (validation.maxLength && value.length > validation.maxLength) {
throw new Error(`String length ${value.length} is greater than maximum ${validation.maxLength}`);
}
}
// Pattern validation
if (validation.pattern && typeof value === 'string') {
const regex = new RegExp(validation.pattern);
if (!regex.test(value)) {
throw new Error(`Value "${value}" does not match required pattern`);
}
}
// Options validation
if (validation.options && validation.options.length > 0) {
const validValues = validation.options
.filter(opt => !opt.disabled)
.map(opt => opt.value);
if (param.type === ParameterType.MULTI_SELECT) {
const values = Array.isArray(value) ? value : [value];
for (const val of values) {
if (!validValues.includes(val)) {
throw new Error(`"${val}" is not a valid option`);
}
}
} else {
if (!validValues.includes(value)) {
throw new Error(`"${value}" is not a valid option`);
}
}
}
// Custom validation
if (validation.customValidator) {
try {
const isValid = this.runCustomValidator(validation.customValidator, value, param);
if (!isValid) {
throw new Error(`Custom validation failed for parameter ${param.name}`);
}
} catch (error) {
throw new Error(`Custom validation error: ${error.message}`);
}
}
}
}
Built-in Templates
Data Processing Templates
// HTTP API Integration Template
const httpApiTemplate: WorkflowTemplate = {
id: 'http-api-integration',
name: 'HTTP API Integration',
version: '1.2.0',
description: 'Complete HTTP API integration with authentication, error handling, and data transformation',
category: TemplateCategory.API_INTEGRATION,
tags: ['http', 'api', 'rest', 'integration'],
author: {
name: 'Axon OS Team',
email: 'templates@axonos.dev',
organization: 'Axon OS'
},
license: 'MIT',
parameters: [
{
id: 'api_url',
name: 'API Base URL',
type: ParameterType.URL,
description: 'The base URL of the API endpoint',
required: true,
displayOrder: 1,
helpText: 'Include the protocol (http:// or https://)',
examples: ['https://api.example.com', 'https://jsonplaceholder.typicode.com']
},
{
id: 'auth_type',
name: 'Authentication Type',
type: ParameterType.SELECT,
description: 'Type of authentication to use',
required: true,
defaultValue: 'none',
displayOrder: 2,
validation: {
options: [
{ value: 'none', label: 'No Authentication' },
{ value: 'api_key', label: 'API Key' },
{ value: 'bearer', label: 'Bearer Token' },
{ value: 'basic', label: 'Basic Auth' },
{ value: 'oauth2', label: 'OAuth 2.0' }
]
}
},
{
id: 'api_key',
name: 'API Key',
type: ParameterType.PASSWORD,
description: 'API key for authentication',
required: false,
displayOrder: 3,
helpText: 'Required when auth_type is "api_key"'
},
{
id: 'endpoints',
name: 'API Endpoints',
type: ParameterType.ARRAY,
description: 'List of API endpoints to integrate',
required: true,
defaultValue: ['/users', '/posts'],
displayOrder: 4,
helpText: 'Array of endpoint paths (without base URL)'
},
{
id: 'rate_limit',
name: 'Rate Limit (requests/minute)',
type: ParameterType.NUMBER,
description: 'Maximum requests per minute',
required: false,
defaultValue: 60,
displayOrder: 5,
validation: {
min: 1,
max: 1000
}
},
{
id: 'retry_config',
name: 'Retry Configuration',
type: ParameterType.OBJECT,
description: 'Configuration for request retries',
required: false,
defaultValue: {
maxAttempts: 3,
initialDelay: 1000,
backoffMultiplier: 2
},
displayOrder: 6
},
{
id: 'transform_response',
name: 'Transform Response Data',
type: ParameterType.BOOLEAN,
description: 'Apply data transformation to API responses',
required: false,
defaultValue: true,
displayOrder: 7
}
],
requirements: [
{
type: 'node',
identifier: 'http-request',
version: '>=1.0.0',
description: 'HTTP Request node for API calls'
},
{
type: 'node',
identifier: 'data-transformer',
version: '>=2.0.0',
description: 'Data Transformer node for response processing'
},
{
type: 'permission',
identifier: 'external_api_access',
description: 'Permission to make external API requests'
}
],
workflow: {
// This would be dynamically generated based on parameters
nodes: [],
connections: [],
settings: {}
},
metadata: {
created: new Date('2024-01-15'),
updated: new Date('2024-01-20'),
compatibility: {
minVersion: '2.0.0',
maxVersion: '3.x.x'
},
difficulty: 'intermediate',
estimatedSetupTime: 15,
industryTags: ['fintech', 'e-commerce', 'saas'],
useCases: [
'API data synchronization',
'Third-party service integration',
'Real-time data fetching',
'Microservices communication'
],
maturityLevel: 'stable'
},
documentation: {
overview: `
# HTTP API Integration Template
This template provides a complete solution for integrating with HTTP APIs, including:
- Configurable authentication methods
- Automatic retry mechanisms with exponential backoff
- Rate limiting to respect API quotas
- Response data transformation and validation
- Comprehensive error handling
Perfect for connecting to REST APIs, webhooks, and microservices.
`,
quickStart: `
## Quick Start
1. **Set API URL**: Enter your API's base URL
2. **Configure Authentication**: Select and configure your auth method
3. **Define Endpoints**: List the API endpoints you want to integrate
4. **Customize Settings**: Adjust rate limits and retry behavior
5. **Deploy**: Save and run your workflow
The template will automatically create optimized HTTP requests with proper error handling.
`,
setupInstructions: `
## Setup Instructions
### Prerequisites
- Valid API endpoint URL
- Authentication credentials (if required)
- Network access to the target API
### Configuration Steps
1. Enter the base URL of your API (e.g., https://api.example.com)
2. Select the appropriate authentication type
3. If using API key or token auth, enter your credentials
4. List the specific endpoints you want to call
5. Configure rate limiting based on your API's limits
6. Set retry behavior for handling temporary failures
### Testing
After setup, use the built-in test feature to verify:
- API connectivity
- Authentication
- Response format
- Error handling
`,
configuration: `
## Configuration Reference
### Authentication Types
- **None**: No authentication headers
- **API Key**: Adds API key to headers or query parameters
- **Bearer Token**: Adds Authorization: Bearer {token} header
- **Basic Auth**: Adds Authorization: Basic {encoded} header
- **OAuth 2.0**: Full OAuth 2.0 flow support
### Rate Limiting
- Automatic throttling based on configured limits
- Distributed rate limiting for multiple workflow instances
- Respect for API rate limit headers (X-RateLimit-*)
### Error Handling
- Automatic retries for 5xx errors and network issues
- Circuit breaker pattern for persistent failures
- Detailed error logging and monitoring
`,
troubleshooting: `
## Troubleshooting
### Common Issues
**Connection Failures**
- Verify the API URL is correct and accessible
- Check firewall and network settings
- Ensure SSL certificates are valid
**Authentication Errors**
- Verify credentials are correct and not expired
- Check if API key has proper permissions
- Ensure authentication type matches API requirements
**Rate Limit Errors**
- Reduce the rate limit setting
- Check API documentation for actual limits
- Consider implementing request queuing
**Data Format Issues**
- Verify API response format matches expectations
- Check content-type headers
- Enable response transformation if needed
`,
bestPractices: `
## Best Practices
1. **Security**
- Store credentials securely using connection management
- Use HTTPS for all API calls
- Implement proper authentication
2. **Performance**
- Set appropriate rate limits
- Use connection pooling for high-volume APIs
- Implement caching for static data
3. **Reliability**
- Configure reasonable retry policies
- Implement circuit breakers for external dependencies
- Monitor API health and response times
4. **Monitoring**
- Track API response times and error rates
- Set up alerts for API failures
- Log important request/response data
`,
changelog: [
{
version: '1.2.0',
date: new Date('2024-01-20'),
changes: [
'Added OAuth 2.0 authentication support',
'Improved error handling with circuit breakers',
'Enhanced rate limiting with burst support'
]
},
{
version: '1.1.0',
date: new Date('2024-01-10'),
changes: [
'Added response data transformation',
'Improved retry logic with jitter',
'Better parameter validation'
]
}
]
},
examples: [
{
id: 'json_placeholder',
name: 'JSONPlaceholder API',
description: 'Connect to the JSONPlaceholder testing API',
parameters: {
api_url: 'https://jsonplaceholder.typicode.com',
auth_type: 'none',
endpoints: ['/posts', '/users', '/comments'],
rate_limit: 60,
transform_response: true
},
expectedOutput: {
posts: 'Array of post objects',
users: 'Array of user objects',
comments: 'Array of comment objects'
}
},
{
id: 'github_api',
name: 'GitHub API',
description: 'Connect to GitHub API with token authentication',
parameters: {
api_url: 'https://api.github.com',
auth_type: 'bearer',
api_key: 'your_github_token',
endpoints: ['/user', '/user/repos'],
rate_limit: 60
},
notes: 'Requires a valid GitHub personal access token'
}
],
usage: {
downloadCount: 1250,
ratingAverage: 4.7,
ratingCount: 89,
lastUsed: new Date('2024-01-19'),
categories: ['popular', 'featured', 'verified']
}
};
// ETL Pipeline Template
const etlPipelineTemplate: WorkflowTemplate = {
id: 'etl-pipeline',
name: 'ETL Data Pipeline',
version: '2.1.0',
description: 'Complete Extract, Transform, Load pipeline with data quality checks and monitoring',
category: TemplateCategory.ETL,
tags: ['etl', 'data-pipeline', 'extract', 'transform', 'load'],
author: {
name: 'Data Engineering Team',
email: 'data@axonos.dev'
},
license: 'Apache-2.0',
parameters: [
{
id: 'source_type',
name: 'Data Source Type',
type: ParameterType.SELECT,
description: 'Type of data source to extract from',
required: true,
displayOrder: 1,
validation: {
options: [
{ value: 'database', label: 'Database (SQL)' },
{ value: 'api', label: 'REST API' },
{ value: 'file', label: 'File (CSV/JSON/XML)' },
{ value: 'stream', label: 'Data Stream' },
{ value: 'webhook', label: 'Webhook' }
]
}
},
{
id: 'source_config',
name: 'Source Configuration',
type: ParameterType.OBJECT,
description: 'Configuration for the data source',
required: true,
displayOrder: 2,
helpText: 'Connection details, query, or file path'
},
{
id: 'transformations',
name: 'Data Transformations',
type: ParameterType.ARRAY,
description: 'List of transformations to apply',
required: false,
defaultValue: [],
displayOrder: 3,
helpText: 'Each transformation should specify type and parameters'
},
{
id: 'destination_type',
name: 'Destination Type',
type: ParameterType.SELECT,
description: 'Where to load the transformed data',
required: true,
displayOrder: 4,
validation: {
options: [
{ value: 'database', label: 'Database' },
{ value: 'warehouse', label: 'Data Warehouse' },
{ value: 'lake', label: 'Data Lake' },
{ value: 'api', label: 'API Endpoint' },
{ value: 'file', label: 'File Export' }
]
}
},
{
id: 'destination_config',
name: 'Destination Configuration',
type: ParameterType.OBJECT,
description: 'Configuration for the destination',
required: true,
displayOrder: 5
},
{
id: 'quality_checks',
name: 'Data Quality Checks',
type: ParameterType.BOOLEAN,
description: 'Enable data quality validation',
required: false,
defaultValue: true,
displayOrder: 6
},
{
id: 'batch_size',
name: 'Batch Size',
type: ParameterType.NUMBER,
description: 'Number of records to process per batch',
required: false,
defaultValue: 1000,
displayOrder: 7,
validation: {
min: 1,
max: 100000
}
},
{
id: 'schedule',
name: 'Schedule',
type: ParameterType.STRING,
description: 'Cron expression for scheduled execution',
required: false,
displayOrder: 8,
helpText: 'Leave empty for manual execution only',
examples: ['0 0 * * *', '0 */6 * * *', '0 0 * * 1']
}
],
requirements: [
{
type: 'node',
identifier: 'data-extractor',
version: '>=2.0.0',
description: 'Data extraction capabilities'
},
{
type: 'node',
identifier: 'data-transformer',
version: '>=2.0.0',
description: 'Data transformation engine'
},
{
type: 'node',
identifier: 'data-loader',
version: '>=2.0.0',
description: 'Data loading capabilities'
},
{
type: 'node',
identifier: 'quality-checker',
version: '>=1.0.0',
optional: true,
description: 'Data quality validation'
}
],
metadata: {
created: new Date('2024-01-01'),
updated: new Date('2024-01-18'),
compatibility: {
minVersion: '2.0.0',
maxVersion: '3.x.x'
},
difficulty: 'advanced',
estimatedSetupTime: 45,
industryTags: ['data-engineering', 'analytics', 'business-intelligence'],
useCases: [
'Data warehouse loading',
'Real-time analytics pipelines',
'Data migration projects',
'Business intelligence reporting'
],
maturityLevel: 'stable'
},
workflow: {
nodes: [],
connections: [],
settings: {}
},
documentation: {
overview: `
# ETL Data Pipeline Template
A comprehensive ETL (Extract, Transform, Load) pipeline template that handles:
- Multiple data source types (databases, APIs, files, streams)
- Configurable data transformations
- Data quality validation
- Flexible destination options
- Batch processing with performance optimization
- Error handling and monitoring
- Scheduled execution support
Ideal for data engineers building reliable data pipelines.
`,
quickStart: `
## Quick Start
1. **Choose Source**: Select your data source type and provide connection details
2. **Define Transformations**: Configure data cleaning, formatting, and enrichment
3. **Set Destination**: Choose where to load the processed data
4. **Enable Quality Checks**: Configure data validation rules
5. **Set Schedule**: Define when the pipeline should run
6. **Test & Deploy**: Validate with sample data before production
The template automatically handles batching, error recovery, and monitoring.
`,
// ... additional documentation sections
setupInstructions: '',
configuration: '',
troubleshooting: '',
bestPractices: '',
changelog: []
},
examples: [
{
id: 'csv_to_database',
name: 'CSV to Database',
description: 'Load CSV files into a SQL database with transformations',
parameters: {
source_type: 'file',
source_config: {
type: 'csv',
path: '/data/input/',
pattern: '*.csv',
hasHeader: true
},
transformations: [
{ type: 'clean_nulls', strategy: 'remove' },
{ type: 'normalize_dates', format: 'ISO' },
{ type: 'validate_email', column: 'email' }
],
destination_type: 'database',
destination_config: {
connection: 'postgres_prod',
table: 'customers',
mode: 'upsert'
},
quality_checks: true,
batch_size: 5000
}
}
],
usage: {
downloadCount: 892,
ratingAverage: 4.5,
ratingCount: 67,
lastUsed: new Date('2024-01-19'),
categories: ['featured']
}
};
Template Creation
Creating Custom Templates
class TemplateBuilder {
private template: Partial<WorkflowTemplate> = {};
constructor() {
this.template = {
id: this.generateId(),
version: '1.0.0',
parameters: [],
requirements: [],
examples: [],
metadata: {
created: new Date(),
updated: new Date(),
difficulty: 'beginner',
estimatedSetupTime: 10,
industryTags: [],
useCases: [],
maturityLevel: 'experimental'
}
};
}
setBasicInfo(info: {
name: string;
description: string;
category: TemplateCategory;
tags: string[];
author: TemplateAuthor;
}): TemplateBuilder {
Object.assign(this.template, info);
return this;
}
addParameter(parameter: TemplateParameter): TemplateBuilder {
this.template.parameters!.push(parameter);
return this;
}
addRequirement(requirement: TemplateRequirement): TemplateBuilder {
this.template.requirements!.push(requirement);
return this;
}
setWorkflow(workflow: WorkflowDefinition): TemplateBuilder {
this.template.workflow = workflow;
return this;
}
addDocumentation(docs: Partial<TemplateDocumentation>): TemplateBuilder {
this.template.documentation = {
overview: '',
quickStart: '',
setupInstructions: '',
configuration: '',
troubleshooting: '',
bestPractices: '',
changelog: [],
...docs
};
return this;
}
addExample(example: TemplateExample): TemplateBuilder {
this.template.examples!.push(example);
return this;
}
setMetadata(metadata: Partial<TemplateMetadata>): TemplateBuilder {
Object.assign(this.template.metadata!, metadata);
return this;
}
build(): WorkflowTemplate {
// Validate required fields
this.validateTemplate();
return this.template as WorkflowTemplate;
}
private validateTemplate(): void {
const required = ['name', 'description', 'category', 'workflow'];
for (const field of required) {
if (!this.template[field as keyof WorkflowTemplate]) {
throw new Error(`Template field '${field}' is required`);
}
}
// Validate parameters
for (const param of this.template.parameters || []) {
if (!param.id || !param.name || !param.type) {
throw new Error('Parameter must have id, name, and type');
}
}
// Validate workflow structure
if (!this.template.workflow?.nodes || this.template.workflow.nodes.length === 0) {
throw new Error('Template must contain at least one workflow node');
}
}
// Helper method to create parameters with common patterns
createStringParameter(
id: string,
name: string,
description: string,
required: boolean = true,
defaultValue?: string
): TemplateParameter {
return {
id,
name,
type: ParameterType.STRING,
description,
required,
defaultValue,
displayOrder: this.template.parameters!.length + 1
};
}
createSelectParameter(
id: string,
name: string,
description: string,
options: ParameterOption[],
required: boolean = true,
defaultValue?: any
): TemplateParameter {
return {
id,
name,
type: ParameterType.SELECT,
description,
required,
defaultValue,
displayOrder: this.template.parameters!.length + 1,
validation: { options }
};
}
}
// Example: Creating a custom email notification template
const emailNotificationTemplate = new TemplateBuilder()
.setBasicInfo({
name: 'Email Notification System',
description: 'Automated email notifications with customizable templates and scheduling',
category: TemplateCategory.COMMUNICATION,
tags: ['email', 'notification', 'automation', 'alert'],
author: {
name: 'John Doe',
email: 'john@example.com',
organization: 'Example Corp'
}
})
.addParameter({
id: 'smtp_server',
name: 'SMTP Server',
type: ParameterType.STRING,
description: 'SMTP server hostname',
required: true,
displayOrder: 1,
examples: ['smtp.gmail.com', 'smtp.outlook.com', 'localhost']
})
.addParameter({
id: 'smtp_port',
name: 'SMTP Port',
type: ParameterType.NUMBER,
description: 'SMTP server port',
required: true,
defaultValue: 587,
displayOrder: 2,
validation: {
min: 1,
max: 65535
}
})
.addParameter(
new TemplateBuilder().createSelectParameter(
'security',
'Security Protocol',
'Email security protocol',
[
{ value: 'none', label: 'None' },
{ value: 'tls', label: 'STARTTLS' },
{ value: 'ssl', label: 'SSL/TLS' }
],
true,
'tls'
)
)
.addRequirement({
type: 'node',
identifier: 'email-sender',
version: '>=1.0.0',
description: 'Email sending capabilities'
})
.addRequirement({
type: 'permission',
identifier: 'email_send',
description: 'Permission to send emails'
})
.setMetadata({
difficulty: 'beginner',
estimatedSetupTime: 10,
industryTags: ['general', 'automation'],
useCases: [
'Alert notifications',
'Report delivery',
'User communication',
'System monitoring alerts'
],
maturityLevel: 'stable'
})
.addDocumentation({
overview: 'Simple email notification system for automated alerts and reports',
quickStart: 'Configure SMTP settings and start sending notifications in minutes',
setupInstructions: 'Enter your SMTP server details and authentication credentials'
})
.addExample({
id: 'gmail_setup',
name: 'Gmail Configuration',
description: 'Configure for Gmail SMTP',
parameters: {
smtp_server: 'smtp.gmail.com',
smtp_port: 587,
security: 'tls'
},
notes: 'Requires App Password for Gmail accounts with 2FA'
})
.build();
Template Marketplace
Template Discovery and Management
interface TemplateMarketplace {
searchTemplates(query: TemplateSearchQuery): Promise<TemplateSearchResult>;
getTemplate(id: string, version?: string): Promise<WorkflowTemplate>;
downloadTemplate(id: string, version?: string): Promise<TemplateDownload>;
publishTemplate(template: WorkflowTemplate): Promise<PublishResult>;
updateTemplate(id: string, template: WorkflowTemplate): Promise<UpdateResult>;
getTemplateAnalytics(id: string): Promise<TemplateAnalytics>;
reportTemplate(id: string, report: TemplateReport): Promise<ReportResult>;
reviewTemplate(id: string, review: TemplateReview): Promise<ReviewResult>;
}
interface TemplateSearchQuery {
keywords?: string;
category?: TemplateCategory;
tags?: string[];
author?: string;
difficulty?: 'beginner' | 'intermediate' | 'advanced' | 'expert';
rating?: number;
sortBy?: 'relevance' | 'popularity' | 'rating' | 'recent';
limit?: number;
offset?: number;
includeUnverified?: boolean;
}
interface TemplateSearchResult {
templates: TemplateSummary[];
totalCount: number;
facets: SearchFacets;
suggestions: string[];
}
interface TemplateSummary {
id: string;
name: string;
version: string;
description: string;
category: TemplateCategory;
tags: string[];
author: TemplateAuthor;
rating: number;
ratingCount: number;
downloadCount: number;
lastUpdated: Date;
verified: boolean;
featured: boolean;
thumbnail?: string;
}
class TemplateMarketplaceClient {
private apiClient: ApiClient;
private cache: TemplateCache;
constructor(apiClient: ApiClient) {
this.apiClient = apiClient;
this.cache = new TemplateCache();
}
async searchTemplates(query: TemplateSearchQuery): Promise<TemplateSearchResult> {
const cacheKey = this.generateCacheKey('search', query);
const cached = await this.cache.get(cacheKey);
if (cached) {
return cached;
}
const result = await this.apiClient.post('/marketplace/search', query);
// Cache search results for 5 minutes
await this.cache.set(cacheKey, result, 300);
return result;
}
async getTemplate(id: string, version?: string): Promise<WorkflowTemplate> {
const cacheKey = this.generateCacheKey('template', { id, version });
const cached = await this.cache.get(cacheKey);
if (cached) {
return cached;
}
const template = await this.apiClient.get(`/marketplace/templates/${id}`, {
params: { version }
});
// Cache templates for 1 hour
await this.cache.set(cacheKey, template, 3600);
return template;
}
async downloadTemplate(id: string, version?: string): Promise<TemplateDownload> {
const template = await this.getTemplate(id, version);
// Track download
await this.apiClient.post(`/marketplace/templates/${id}/download`, {
version: version || template.version
});
// Validate template requirements
const validation = await this.validateRequirements(template);
return {
template,
validation,
downloadedAt: new Date(),
downloadId: this.generateDownloadId()
};
}
async publishTemplate(template: WorkflowTemplate): Promise<PublishResult> {
// Validate template before publishing
const validation = await this.validateTemplateForPublishing(template);
if (!validation.valid) {
return {
success: false,
errors: validation.errors,
templateId: template.id
};
}
// Submit for review
const result = await this.apiClient.post('/marketplace/templates', template);
return {
success: true,
templateId: template.id,
status: 'pending_review',
reviewId: result.reviewId,
estimatedReviewTime: result.estimatedReviewTime
};
}
private async validateRequirements(template: WorkflowTemplate): Promise<RequirementValidation> {
const validation: RequirementValidation = {
valid: true,
missingRequirements: [],
warnings: []
};
for (const requirement of template.requirements) {
const available = await this.checkRequirementAvailability(requirement);
if (!available.exists) {
if (requirement.optional) {
validation.warnings.push({
type: requirement.type,
identifier: requirement.identifier,
message: `Optional ${requirement.type} not available: ${requirement.description}`
});
} else {
validation.valid = false;
validation.missingRequirements.push(requirement);
}
} else if (requirement.version && !available.versionMatches) {
validation.warnings.push({
type: requirement.type,
identifier: requirement.identifier,
message: `Version mismatch: required ${requirement.version}, found ${available.version}`
});
}
}
return validation;
}
private async validateTemplateForPublishing(template: WorkflowTemplate): Promise<PublishValidation> {
const errors: PublishError[] = [];
const warnings: PublishWarning[] = [];
// Required field validation
const requiredFields = ['name', 'description', 'category', 'author', 'workflow'];
for (const field of requiredFields) {
if (!template[field as keyof WorkflowTemplate]) {
errors.push({
field,
message: `${field} is required for publishing`
});
}
}
// Documentation validation
if (!template.documentation?.overview) {
errors.push({
field: 'documentation.overview',
message: 'Template overview documentation is required'
});
}
if (!template.documentation?.quickStart) {
warnings.push({
field: 'documentation.quickStart',
message: 'Quick start guide is recommended for better user experience'
});
}
// Parameter validation
for (const param of template.parameters) {
if (param.required && param.defaultValue === undefined) {
warnings.push({
field: `parameters.${param.id}`,
message: 'Required parameters should have default values when possible'
});
}
if (!param.description) {
errors.push({
field: `parameters.${param.id}`,
message: 'Parameter description is required'
});
}
}
// Example validation
if (template.examples.length === 0) {
warnings.push({
field: 'examples',
message: 'Adding usage examples improves template adoption'
});
}
// Workflow validation
if (template.workflow.nodes.length === 0) {
errors.push({
field: 'workflow.nodes',
message: 'Template must contain at least one workflow node'
});
}
return {
valid: errors.length === 0,
errors,
warnings
};
}
}
Template Versioning
Version Management
interface TemplateVersion {
version: string;
template: WorkflowTemplate;
changelog: ChangelogEntry;
compatibility: CompatibilityInfo;
deprecated: boolean;
deprecationReason?: string;
migrationGuide?: string;
}
interface ChangelogEntry {
version: string;
date: Date;
changes: Change[];
breakingChanges?: BreakingChange[];
migration?: MigrationInstructions;
}
interface Change {
type: 'added' | 'changed' | 'deprecated' | 'removed' | 'fixed' | 'security';
description: string;
impact: 'low' | 'medium' | 'high';
component?: string;
}
interface BreakingChange {
component: string;
description: string;
before: any;
after: any;
migrationSteps: string[];
}
class TemplateVersionManager {
async createNewVersion(
templateId: string,
newTemplate: WorkflowTemplate,
changelog: ChangelogEntry
): Promise<TemplateVersion> {
const currentVersion = await this.getCurrentVersion(templateId);
const newVersion = this.calculateNextVersion(currentVersion.version, changelog);
// Validate compatibility
const compatibility = await this.checkCompatibility(currentVersion.template, newTemplate);
// Create version entry
const templateVersion: TemplateVersion = {
version: newVersion,
template: {
...newTemplate,
version: newVersion
},
changelog,
compatibility,
deprecated: false
};
// Validate breaking changes
if (changelog.breakingChanges && changelog.breakingChanges.length > 0) {
await this.validateBreakingChanges(currentVersion.template, newTemplate, changelog.breakingChanges);
}
return templateVersion;
}
private calculateNextVersion(
currentVersion: string,
changelog: ChangelogEntry
): string {
const [major, minor, patch] = currentVersion.split('.').map(Number);
// Check for breaking changes
if (changelog.breakingChanges && changelog.breakingChanges.length > 0) {
return `${major + 1}.0.0`;
}
// Check for new features
const hasNewFeatures = changelog.changes.some(change => change.type === 'added');
if (hasNewFeatures) {
return `${major}.${minor + 1}.0`;
}
// Patch version for fixes and minor changes
return `${major}.${minor}.${patch + 1}`;
}
private async checkCompatibility(
oldTemplate: WorkflowTemplate,
newTemplate: WorkflowTemplate
): Promise<CompatibilityInfo> {
const compatibility: CompatibilityInfo = {
minVersion: newTemplate.metadata?.compatibility?.minVersion || '1.0.0',
maxVersion: newTemplate.metadata?.compatibility?.maxVersion || '99.x.x',
backwards: true,
forwards: false,
issues: []
};
// Check parameter compatibility
const parameterIssues = this.checkParameterCompatibility(oldTemplate, newTemplate);
compatibility.issues.push(...parameterIssues);
// Check requirement compatibility
const requirementIssues = this.checkRequirementCompatibility(oldTemplate, newTemplate);
compatibility.issues.push(...requirementIssues);
// Check workflow compatibility
const workflowIssues = this.checkWorkflowCompatibility(oldTemplate, newTemplate);
compatibility.issues.push(...workflowIssues);
// Determine overall compatibility
const hasBreakingIssues = compatibility.issues.some(issue => issue.severity === 'breaking');
if (hasBreakingIssues) {
compatibility.backwards = false;
}
return compatibility;
}
private checkParameterCompatibility(
oldTemplate: WorkflowTemplate,
newTemplate: WorkflowTemplate
): CompatibilityIssue[] {
const issues: CompatibilityIssue[] = [];
const oldParams = new Map(oldTemplate.parameters.map(p => [p.id, p]));
const newParams = new Map(newTemplate.parameters.map(p => [p.id, p]));
// Check for removed parameters
for (const [paramId, oldParam] of oldParams) {
if (!newParams.has(paramId)) {
issues.push({
type: 'parameter_removed',
severity: oldParam.required ? 'breaking' : 'warning',
description: `Parameter '${oldParam.name}' was removed`,
component: `parameters.${paramId}`,
mitigation: oldParam.required ?
'Add default value or make parameter optional' :
'Update workflows to remove references'
});
}
}
// Check for parameter changes
for (const [paramId, newParam] of newParams) {
const oldParam = oldParams.get(paramId);
if (oldParam) {
// Type changes
if (oldParam.type !== newParam.type) {
issues.push({
type: 'parameter_type_changed',
severity: 'breaking',
description: `Parameter '${newParam.name}' type changed from ${oldParam.type} to ${newParam.type}`,
component: `parameters.${paramId}`,
mitigation: 'Provide automatic type conversion or migration'
});
}
// Required changes
if (!oldParam.required && newParam.required) {
issues.push({
type: 'parameter_required_added',
severity: 'breaking',
description: `Parameter '${newParam.name}' is now required`,
component: `parameters.${paramId}`,
mitigation: 'Provide default value or make gradual transition'
});
}
// Validation changes
if (this.hasStricterValidation(oldParam, newParam)) {
issues.push({
type: 'parameter_validation_stricter',
severity: 'warning',
description: `Parameter '${newParam.name}' has stricter validation rules`,
component: `parameters.${paramId}`,
mitigation: 'Update documentation and provide validation examples'
});
}
} else {
// New required parameter
if (newParam.required && newParam.defaultValue === undefined) {
issues.push({
type: 'parameter_added_required',
severity: 'breaking',
description: `New required parameter '${newParam.name}' added without default value`,
component: `parameters.${paramId}`,
mitigation: 'Provide default value or make parameter optional'
});
}
}
}
return issues;
}
async generateMigrationGuide(
fromVersion: string,
toVersion: string,
templateId: string
): Promise<MigrationGuide> {
const fromTemplate = await this.getTemplateVersion(templateId, fromVersion);
const toTemplate = await this.getTemplateVersion(templateId, toVersion);
const compatibility = await this.checkCompatibility(fromTemplate, toTemplate);
return {
fromVersion,
toVersion,
templateId,
compatibility,
steps: this.generateMigrationSteps(compatibility),
automatedMigration: this.canAutoMigrate(compatibility),
estimatedEffort: this.estimateMigrationEffort(compatibility),
testing: this.generateTestingGuidance(compatibility)
};
}
private generateMigrationSteps(compatibility: CompatibilityInfo): MigrationStep[] {
const steps: MigrationStep[] = [];
for (const issue of compatibility.issues) {
if (issue.severity === 'breaking') {
steps.push({
order: steps.length + 1,
type: 'required',
title: this.generateStepTitle(issue),
description: issue.description,
action: issue.mitigation || 'Manual update required',
component: issue.component,
validation: this.generateValidationStep(issue)
});
}
}
// Add optional improvement steps
for (const issue of compatibility.issues) {
if (issue.severity === 'warning') {
steps.push({
order: steps.length + 1,
type: 'recommended',
title: this.generateStepTitle(issue),
description: issue.description,
action: issue.mitigation || 'Review and update as needed',
component: issue.component
});
}
}
return steps;
}
}