UNPKG

@dollhousemcp/mcp-server

Version:

DollhouseMCP - A Model Context Protocol (MCP) server that enables dynamic AI persona management from markdown files, allowing Claude and other compatible AI assistants to activate and switch between different behavioral personas.

462 lines 14.6 kB
/** * SerializationService - Centralized serialization for all element types * * Eliminates ~300+ lines of duplicate serialization code across SkillManager, * MemoryManager, TemplateManager, AgentManager, and EnsembleManager. * * Key Features: * - Unified YAML parsing and dumping with security validation * - Consistent JSON operations across all element types * - Comprehensive metadata cleaning utilities * - Format auto-detection * - Security event logging integration * * @example * ```typescript * // Inject via DI container * constructor(private serializationService: SerializationService) {} * * // Parse YAML with frontmatter * const result = this.serializationService.parseFrontmatter(data, { * maxYamlSize: 64 * 1024, * validateContent: true, * source: 'SkillManager.importElement' * }); * * // Create frontmatter * const markdown = this.serializationService.createFrontmatter(metadata, content, { * schema: 'failsafe', * cleanMetadata: true * }); * ``` */ import { SecurityEvent } from '../security/securityMonitor.js'; /** * YAML schema selection */ export type YamlSchema = 'failsafe' | 'default' | 'core' | 'json'; /** * Metadata cleaning strategy */ export type CleaningStrategy = 'remove-undefined' | 'remove-null' | 'remove-both' | 'none'; /** * Frontmatter creation method */ export type FrontmatterMethod = 'matter' | 'manual'; /** * Detected format type */ export type DetectedFormat = 'frontmatter' | 'yaml' | 'json' | 'unknown'; /** * Options for parsing pure YAML */ export interface YamlParseOptions { /** YAML schema to use (default: 'failsafe' for security) */ schema?: YamlSchema; /** Maximum YAML size in bytes (default: 64KB) */ maxSize?: number; /** Validate root structure is an object (default: true) */ validateStructure?: boolean; /** Source identifier for security logging */ source?: string; } /** * Options for parsing frontmatter + content */ export interface FrontmatterParseOptions { /** Maximum YAML frontmatter size in bytes (default: 64KB) */ maxYamlSize?: number; /** Maximum content size in bytes (default: 1MB) */ maxContentSize?: number; /** Enable content validation (default: false for local files) */ validateContent?: boolean; /** Source identifier for security logging */ source?: string; /** * YAML schema to use for pure YAML parsing (default: 'failsafe') * Use 'json' to preserve booleans and numbers when reading files * written with 'json' schema (e.g., MemoryManager) */ schema?: YamlSchema; } /** * Options for auto-parsing (format detection) */ export interface AutoParseOptions { /** Options to use if format is frontmatter */ frontmatterOptions?: FrontmatterParseOptions; /** Options to use if format is pure YAML */ yamlOptions?: YamlParseOptions; /** Options to use if format is JSON */ jsonOptions?: JsonParseOptions; /** Source identifier for security logging */ source?: string; } /** * Options for YAML dump */ export interface YamlDumpOptions { /** YAML schema to use (default: 'failsafe') */ schema?: YamlSchema; /** Sort keys alphabetically (default: true) */ sortKeys?: boolean; /** Skip invalid values instead of throwing (default: true) */ skipInvalid?: boolean; /** Don't create anchors/aliases (default: true for security) */ noRefs?: boolean; /** Indentation for nested elements (default: 2) */ indent?: number; /** Line width for wrapping (default: 80) */ lineWidth?: number; /** Flow level (-1 for block style, 0+ for flow style at that level) */ flowLevel?: number; } /** * Options for frontmatter creation */ export interface FrontmatterDumpOptions extends YamlDumpOptions { /** Method to use for creating frontmatter (default: 'manual') */ method?: FrontmatterMethod; /** Clean metadata before dumping (default: false) */ cleanMetadata?: boolean; /** Cleaning strategy if cleanMetadata is true */ cleaningStrategy?: CleaningStrategy; } /** * Options for JSON parsing */ export interface JsonParseOptions { /** Maximum JSON size in bytes (default: 1MB) */ maxSize?: number; /** Validate that root is an object (default: false) */ validateStructure?: boolean; /** Source identifier for security logging */ source?: string; } /** * Options for JSON stringification */ export interface JsonStringifyOptions { /** Pretty print output (default: false) */ pretty?: boolean; /** Indentation spaces (default: 2) */ indent?: number; /** Clean metadata before stringifying (default: false) */ cleanMetadata?: boolean; /** Cleaning strategy if cleanMetadata is true */ cleaningStrategy?: CleaningStrategy; } /** * Options for metadata cleaning */ export interface MetadataCleanOptions { /** Cleaning strategy (default: 'remove-undefined') */ strategy?: CleaningStrategy; /** Remove empty arrays and objects (default: false) */ removeEmpty?: boolean; } /** * Result from frontmatter parsing */ export interface ParsedFrontmatter { /** Parsed frontmatter metadata */ data: Record<string, any>; /** Markdown content after frontmatter */ content: string; } /** * Result from auto-parsing */ export interface AutoParsedResult { /** Detected format */ format: DetectedFormat; /** Parsed data (metadata for frontmatter, object for YAML/JSON) */ data: any; /** Content (only for frontmatter format) */ content?: string; } /** * Service for centralized serialization operations * * This service provides unified serialization functionality to eliminate code * duplication across element managers. Supports: * - YAML parsing and dumping * - JSON parsing and stringification * - Frontmatter creation and parsing * - Metadata cleaning * - Format detection * - Security validation */ /** * Fix #910: Canonical metadata field order for deterministic YAML output. * Fields are ordered: identity → format → content → type-specific → infrastructure. * Fields not listed appear after all listed fields, sorted alphabetically. */ export declare const METADATA_FIELD_ORDER: readonly string[]; /** * Reorder an object's keys according to METADATA_FIELD_ORDER. * Keys not in the order list appear after all ordered keys, sorted alphabetically. */ export declare function orderMetadataFields(metadata: Record<string, unknown>): Record<string, unknown>; export declare class SerializationService { private static readonly DEFAULT_MAX_YAML_SIZE; private static readonly DEFAULT_MAX_CONTENT_SIZE; constructor(); /** * Parse pure YAML with security validation * * Handles: * - Size validation * - Schema selection * - Structure validation * - Security event logging * * @param data - YAML string to parse * @param options - Parsing options * @returns Parsed object * @throws Error if size exceeds limit or structure is invalid * * @example * ```typescript * const parsed = service.parsePureYaml(yamlString, { * schema: 'failsafe', * maxSize: 64 * 1024, * validateStructure: true, * source: 'SkillManager.importElement' * }); * ``` */ parsePureYaml(data: string, options?: YamlParseOptions): any; /** * Parse frontmatter + content (Markdown with YAML) * * Auto-detects: * - Pure YAML (wraps with --- markers for parsing) * - Markdown with frontmatter (parses as-is) * * Uses SecureYamlParser for security validation. * * @param data - Markdown string with frontmatter * @param options - Parsing options * @returns Parsed frontmatter and content * * @example * ```typescript * const result = service.parseFrontmatter(markdownString, { * maxYamlSize: 64 * 1024, * validateContent: true, * source: 'TemplateManager.importElement' * }); * // result.data = { name: '...', description: '...' } * // result.content = 'Markdown content...' * ``` */ parseFrontmatter(data: string, options?: FrontmatterParseOptions): ParsedFrontmatter; /** * Auto-detect format and parse * * Detects: * - Frontmatter (starts with ---) * - Pure YAML (valid YAML object) * - JSON (starts with { or [) * * @param data - String to parse * @param options - Parsing options for each format * @returns Parsed result with detected format * * @example * ```typescript * const result = service.parseAuto(data, { * source: 'SkillManager.importElement' * }); * if (result.format === 'frontmatter') { * console.log(result.data, result.content); * } else if (result.format === 'yaml') { * console.log(result.data); * } * ``` */ parseAuto(data: string, options?: AutoParseOptions): AutoParsedResult; /** * Dump object to YAML string * * Supports: * - FAILSAFE_SCHEMA (default - strings only, most secure) * - DEFAULT_SCHEMA (for TemplateManager compatibility) * - CORE_SCHEMA (for special cases) * * @param data - Object to serialize * @param options - Dump options * @returns YAML string * * @example * ```typescript * const yamlString = service.dumpYaml(data, { * schema: 'failsafe', * sortKeys: true, * skipInvalid: true, * noRefs: true * }); * ``` */ dumpYaml(data: any, options?: YamlDumpOptions): string; /** * Create frontmatter + content (Markdown with YAML) * * Methods: * - 'matter' - Uses matter.stringify() (SkillManager pattern) * - 'manual' - Manual YAML dump + concatenation (other managers) * * @param metadata - Frontmatter metadata * @param content - Markdown content * @param options - Dump options * @returns Markdown string with frontmatter * * @example * ```typescript * const markdown = service.createFrontmatter(metadata, content, { * schema: 'failsafe', * method: 'matter', * cleanMetadata: true, * cleaningStrategy: 'remove-undefined' * }); * // Returns: ---\nmetadata...\n---\n\nContent... * ``` */ createFrontmatter(metadata: any, content: string, options?: FrontmatterDumpOptions): string; /** * Parse JSON with error handling and security logging * * @param data - JSON string * @param options - Parse options * @returns Parsed object * @throws Error if parsing fails * * @example * ```typescript * const parsed = service.parseJson(jsonString, { * source: 'TemplateManager.importElement' * }); * ``` */ parseJson<T = any>(data: string, options?: JsonParseOptions): T; /** * Stringify object to JSON * * @param data - Object to serialize * @param options - Stringify options * @returns JSON string * * @example * ```typescript * const jsonString = service.stringifyJson(data, { * indent: 2, * cleanMetadata: true, * cleaningStrategy: 'remove-undefined' * }); * ``` */ stringifyJson(data: any, options?: JsonStringifyOptions): string; /** * Clean metadata by removing undefined/null values * * Strategies: * - 'remove-undefined' - Remove undefined only (SkillManager, TemplateManager) * - 'remove-null' - Remove null only * - 'remove-both' - Remove both undefined and null (AgentManager) * - 'none' - No cleaning (MemoryManager, EnsembleManager) * * @param metadata - Metadata object to clean * @param options - Cleaning options * @returns Cleaned metadata (new object, original not modified) * * @example * ```typescript * const cleaned = service.cleanMetadata(metadata, { * strategy: 'remove-undefined' * }); * ``` */ cleanMetadata(metadata: any, options?: MetadataCleanOptions): any; /** * Detect format of input data * * Detection logic: * 1. Check for frontmatter (starts with --- after optional whitespace) * 2. Check for JSON (starts with { or [) * 3. Try to parse as YAML * 4. Return 'unknown' if none match * * @param data - String to analyze * @returns Detected format * * @example * ```typescript * const format = service.detectFormat(data); * // Returns: 'frontmatter' | 'yaml' | 'json' | 'unknown' * ``` */ detectFormat(data: string): DetectedFormat; /** * Check if data has frontmatter markers * * Checks for '---' at the start after optional whitespace * * @param data - String to check * @returns True if has frontmatter * * @example * ```typescript * if (service.hasFrontmatter(data)) { * const result = service.parseFrontmatter(data); * } * ``` */ hasFrontmatter(data: string): boolean; /** * Log security event (wrapper for SecurityMonitor) * * Provides consistent security event logging across serialization operations * * @param type - Event type * @param severity - Event severity * @param source - Event source * @param details - Event details * * @example * ```typescript * service.logSecurityEvent( * 'YAML_PARSE_SUCCESS', * 'LOW', * 'SkillManager.importElement', * 'Successfully parsed YAML content' * ); * ``` */ logSecurityEvent(type: SecurityEvent['type'], severity: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL', source: string, details: string): void; /** * Validate size limits * * Throws error if data exceeds the specified maximum size * * @param data - Data to check * @param maxSize - Maximum size in bytes * @param context - Context for error messages * @throws Error if size exceeds limit * * @example * ```typescript * service.validateSize(data, 64 * 1024, 'YAML frontmatter'); * // Throws if data > 64KB * ``` */ validateSize(data: string, maxSize: number, context: string): void; /** * Get YAML schema object from string identifier * * @param schema - Schema identifier * @returns YAML schema object */ private getYamlSchema; } //# sourceMappingURL=SerializationService.d.ts.map