UNPKG

@simonecoelhosfo/optimizely-mcp-server

Version:

Optimizely MCP Server for AI assistants with integrated CLI tools

146 lines 5.01 kB
import { FIELDS } from '../generated/fields.generated'; import { getLogger } from '../logging/Logger.js'; /** * Field Serialization Helper * * Utilities for handling object/array field serialization before SQLite storage * to prevent "SQLite3 can only bind numbers, strings, bigints, buffers, and null" errors */ // Types that require JSON serialization before database storage const SERIALIZABLE_TYPES = ['object', 'array', 'any']; // Types that can be stored directly in SQLite const DIRECT_TYPES = ['string', 'integer', 'boolean', 'number']; /** * High-risk field name patterns that commonly cause serialization issues */ const HIGH_RISK_PATTERNS = [ 'conditions', // Audience/page targeting conditions 'audience_conditions', // Experiment audience logic 'url_targeting', // URL matching rules 'environments', // Per-environment configurations 'variable_values', // Feature flag variable assignments 'actions', // DOM manipulation actions 'metrics', // Conversion tracking definitions 'variations', // Experiment variation configurations 'rules', // Targeting rule definitions 'traffic_allocation' // Traffic distribution settings ]; /** * Check if a field requires serialization for a specific entity */ export function requiresSerialization(entityType, fieldName) { // Type guard to check if entityType is valid if (!(entityType in FIELDS)) return false; const entitySchema = FIELDS[entityType]; const fieldType = entitySchema.fieldTypes[fieldName]; return fieldType ? SERIALIZABLE_TYPES.includes(fieldType) : false; } /** * Serialize a value for database storage if needed */ export function serializeForDatabase(entityType, fieldName, value) { if (value === null || value === undefined) { return null; } if (requiresSerialization(entityType, fieldName)) { try { return JSON.stringify(value); } catch (error) { getLogger().warn({ entityType, fieldName, error: String(error) }, `Failed to serialize field`); return value; } } return value; } /** * Deserialize a value from database if needed */ export function deserializeFromDatabase(entityType, fieldName, value) { if (value === null || value === undefined) { return null; } if (requiresSerialization(entityType, fieldName) && typeof value === 'string') { try { return JSON.parse(value); } catch (error) { // If parsing fails, return the original value getLogger().warn({ entityType, fieldName, error: String(error) }, `Failed to deserialize field`); return value; } } return value; } /** * Get all complex fields for an entity type */ export function getComplexFieldsForEntity(entityType) { const entitySchema = FIELDS[entityType]; if (!entitySchema) return []; return Object.entries(entitySchema.fieldTypes) .filter(([_, fieldType]) => SERIALIZABLE_TYPES.includes(fieldType)) .map(([fieldName, _]) => fieldName); } /** * Serialize an entire entity object for database storage */ export function serializeEntityForDatabase(entityType, entityData) { const serialized = {}; for (const [fieldName, value] of Object.entries(entityData)) { serialized[fieldName] = serializeForDatabase(entityType, fieldName, value); } return serialized; } /** * Deserialize an entire entity object from database storage */ export function deserializeEntityFromDatabase(entityType, entityData) { const deserialized = {}; for (const [fieldName, value] of Object.entries(entityData)) { deserialized[fieldName] = deserializeFromDatabase(entityType, fieldName, value); } return deserialized; } /** * Check if a field is high-risk for serialization issues */ export function isHighRiskField(fieldName) { return HIGH_RISK_PATTERNS.some(pattern => fieldName.includes(pattern)); } /** * Generate serialization matrix for debugging */ export function generateSerializationMatrix() { const matrix = {}; for (const [entityName, entitySchema] of Object.entries(FIELDS)) { const complexFields = {}; const criticalFields = []; for (const [fieldName, fieldType] of Object.entries(entitySchema.fieldTypes)) { if (SERIALIZABLE_TYPES.includes(fieldType)) { complexFields[fieldName] = fieldType; if (isHighRiskField(fieldName)) { criticalFields.push(fieldName); } } } if (Object.keys(complexFields).length > 0) { matrix[entityName] = { complexFields, criticalFields }; } } return matrix; } /** * Export constants for external use */ export const SERIALIZATION_CONSTANTS = { SERIALIZABLE_TYPES, DIRECT_TYPES, HIGH_RISK_PATTERNS }; //# sourceMappingURL=FieldSerializationHelper.js.map