UNPKG

@ddex-workbench/sdk

Version:

Official SDK for DDEX Workbench - Open-source DDEX validation and processing tools

1 lines 45.4 kB
{"version":3,"sources":["../src/client.ts","../src/errors.ts","../src/validator.ts"],"sourcesContent":["// packages/sdk/src/client.ts\nimport axios, { AxiosInstance, AxiosError } from \"axios\";\nimport {\n DDEXClientConfig,\n ValidationResult,\n ValidationOptions,\n ApiKey,\n SupportedFormats,\n HealthStatus,\n BatchValidationOptions,\n BatchValidationResult,\n FileValidationOptions,\n URLValidationOptions,\n} from \"./types\";\nimport {\n DDEXError,\n RateLimitError,\n AuthenticationError,\n ValidationError,\n NetworkError,\n} from \"./errors\";\nimport { DDEXValidator } from \"./validator\";\n\n/**\n * DDEX Workbench API Client\n *\n * @example\n * ```typescript\n * import { DDEXClient } from '@ddex-workbench/sdk';\n *\n * const client = new DDEXClient({\n * apiKey: 'ddex_your-api-key',\n * environment: 'production'\n * });\n *\n * const result = await client.validate(xmlContent, {\n * version: '4.3',\n * profile: 'AudioAlbum'\n * });\n * ```\n */\nexport class DDEXClient {\n private readonly client: AxiosInstance;\n private readonly config: DDEXClientConfig;\n public readonly validator: DDEXValidator;\n\n constructor(config: Partial<DDEXClientConfig> = {}) {\n this.config = {\n baseURL: config.baseURL || \"https://api.ddex-workbench.org/v1\",\n apiKey: config.apiKey,\n timeout: config.timeout || 30000,\n environment: config.environment || \"production\",\n maxRetries: config.maxRetries || 3,\n retryDelay: config.retryDelay || 1000,\n ...config,\n };\n\n // Create axios instance\n this.client = axios.create({\n baseURL: this.config.baseURL,\n timeout: this.config.timeout,\n headers: {\n \"Content-Type\": \"application/json\",\n \"User-Agent\": `ddex-workbench-sdk/1.1.0 (${this.getEnvironment()})`,\n ...this.config.headers,\n },\n });\n\n // Add API key if provided\n if (this.config.apiKey) {\n this.client.defaults.headers.common[\"X-API-Key\"] = this.config.apiKey;\n }\n\n // Add request interceptor for retry logic\n this.setupInterceptors();\n\n // Create validator instance\n this.validator = new DDEXValidator(this);\n }\n\n /**\n * Validate DDEX XML content\n *\n * @param content - XML content as string\n * @param options - Validation options\n * @returns Validation result with errors and metadata\n *\n * @example\n * ```typescript\n * const result = await client.validate(xmlContent, {\n * version: '4.3',\n * profile: 'AudioAlbum',\n * generateSVRL: true\n * });\n * ```\n */\n async validate(\n content: string,\n options: ValidationOptions,\n ): Promise<ValidationResult> {\n try {\n const response = await this.retryableRequest(() =>\n this.client.post<ValidationResult>(\"/validate\", {\n content,\n type: \"ERN\",\n version: options.version,\n profile: options.profile,\n generateSVRL: options.generateSVRL,\n verbose: options.verbose,\n customRules: options.customRules,\n }),\n );\n\n return response.data;\n } catch (error) {\n throw this.handleError(error);\n }\n }\n\n /**\n * Validate with SVRL report generation\n *\n * @param content - XML content as string\n * @param options - Validation options\n * @returns Validation result with SVRL report\n *\n * @example\n * ```typescript\n * const result = await client.validateWithSVRL(xmlContent, {\n * version: '4.3',\n * profile: 'AudioAlbum'\n * });\n * \n * if (result.svrl) {\n * console.log('SVRL report generated');\n * }\n * ```\n */\n async validateWithSVRL(\n content: string,\n options: ValidationOptions,\n ): Promise<ValidationResult> {\n return this.validate(content, {\n ...options,\n generateSVRL: true,\n });\n }\n\n /**\n * Validate a file\n *\n * @param filePath - Path to XML file\n * @param options - Validation options\n * @returns Validation result\n */\n async validateFile(\n filePath: string,\n options: FileValidationOptions,\n ): Promise<ValidationResult> {\n try {\n // In browser environment, this would need to be handled differently\n if (typeof window !== \"undefined\") {\n throw new Error(\"File validation is not supported in browser environment\");\n }\n\n // Use dynamic imports for Node.js modules\n const fs = await import(\"fs/promises\");\n const path = await import(\"path\");\n \n const content = await fs.readFile(filePath, options.encoding || \"utf-8\");\n const stats = await fs.stat(filePath);\n \n const result = await this.validate(content.toString(), options);\n \n // Add file metadata\n result.metadata.fileInfo = {\n name: path.basename(filePath),\n size: stats.size,\n };\n \n if (options.includeHash) {\n const crypto = await import(\"crypto\");\n const hash = crypto\n .createHash(\"sha256\")\n .update(content)\n .digest(\"hex\");\n result.metadata.fileInfo.hash = hash;\n }\n \n return result;\n } catch (error) {\n throw this.handleError(error);\n }\n }\n\n /**\n * Validate XML from URL\n *\n * @param url - URL to fetch XML from\n * @param options - Validation options\n * @returns Validation result\n */\n async validateURL(\n url: string,\n options: URLValidationOptions,\n ): Promise<ValidationResult> {\n try {\n const response = await axios.get(url, {\n timeout: options.fetchTimeout || this.config.timeout,\n headers: options.headers,\n responseType: \"text\",\n });\n\n return this.validate(response.data, options);\n } catch (error) {\n throw this.handleError(error);\n }\n }\n\n /**\n * Batch validate multiple XML contents\n *\n * @param items - Array of XML contents with their options\n * @param batchOptions - Batch processing options\n * @returns Batch validation results\n */\n async validateBatch(\n items: Array<{ content: string; options: ValidationOptions; filename?: string }>,\n batchOptions: BatchValidationOptions = {},\n ): Promise<BatchValidationResult> {\n const startTime = Date.now();\n const concurrency = batchOptions.concurrency || 3;\n const results: Array<{ filename: string; result: ValidationResult }> = [];\n \n let validFiles = 0;\n let completed = 0;\n\n // Process in chunks for concurrency control\n for (let i = 0; i < items.length; i += concurrency) {\n const chunk = items.slice(i, i + concurrency);\n \n const chunkResults = await Promise.all(\n chunk.map(async (item) => {\n try {\n const result = await this.validate(item.content, item.options);\n if (result.valid) validFiles++;\n \n completed++;\n if (batchOptions.onProgress) {\n batchOptions.onProgress(completed, items.length);\n }\n \n return {\n filename: item.filename || `file_${completed}`,\n result,\n };\n } catch (error) {\n completed++;\n if (batchOptions.onProgress) {\n batchOptions.onProgress(completed, items.length);\n }\n \n if (batchOptions.stopOnError) {\n throw error;\n }\n \n // Create error result\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n return {\n filename: item.filename || `file_${completed}`,\n result: {\n valid: false,\n errors: [{\n line: 0,\n column: 0,\n message: errorMessage,\n severity: \"fatal\" as const,\n }],\n warnings: [],\n metadata: {\n processingTime: 0,\n schemaVersion: item.options.version,\n validatedAt: new Date().toISOString(),\n errorCount: 1,\n warningCount: 0,\n validationSteps: [],\n },\n },\n };\n }\n }),\n );\n \n results.push(...chunkResults);\n }\n\n return {\n totalFiles: items.length,\n validFiles,\n invalidFiles: items.length - validFiles,\n results,\n processingTime: Date.now() - startTime,\n };\n }\n\n /**\n * Get supported formats and versions\n *\n * @returns Supported formats information\n */\n async getSupportedFormats(): Promise<SupportedFormats> {\n try {\n const response = await this.client.get<SupportedFormats>(\"/formats\");\n return response.data;\n } catch (error) {\n throw this.handleError(error);\n }\n }\n\n /**\n * Check API health status\n *\n * @returns Health status information\n */\n async checkHealth(): Promise<HealthStatus> {\n try {\n const startTime = Date.now();\n const response = await this.client.get<HealthStatus>(\"/health\");\n \n return {\n ...response.data,\n responseTime: Date.now() - startTime,\n };\n } catch (error) {\n throw this.handleError(error);\n }\n }\n\n /**\n * List API keys (requires authentication)\n *\n * @returns List of API keys\n */\n async listApiKeys(): Promise<ApiKey[]> {\n try {\n const response = await this.client.get<ApiKey[]>(\"/keys\");\n return response.data;\n } catch (error) {\n throw this.handleError(error);\n }\n }\n\n /**\n * Create a new API key (requires authentication)\n *\n * @param name - Name for the API key\n * @returns Created API key\n */\n async createApiKey(name: string): Promise<ApiKey> {\n try {\n const response = await this.client.post<ApiKey>(\"/keys\", { name });\n return response.data;\n } catch (error) {\n throw this.handleError(error);\n }\n }\n\n /**\n * Revoke an API key (requires authentication)\n *\n * @param keyId - ID of the key to revoke\n */\n async revokeApiKey(keyId: string): Promise<void> {\n try {\n await this.client.delete(`/keys/${keyId}`);\n } catch (error) {\n throw this.handleError(error);\n }\n }\n\n /**\n * Setup axios interceptors for retry logic\n */\n private setupInterceptors(): void {\n // Response interceptor for retry logic is handled in retryableRequest\n this.client.interceptors.response.use(\n (response) => response,\n (error) => Promise.reject(error),\n );\n }\n\n /**\n * Execute request with retry logic\n */\n private async retryableRequest<T>(\n request: () => Promise<T>,\n retries = this.config.maxRetries || 3,\n ): Promise<T> {\n try {\n return await request();\n } catch (error) {\n if (retries > 0 && this.shouldRetry(error)) {\n await this.delay(this.config.retryDelay || 1000);\n return this.retryableRequest(request, retries - 1);\n }\n throw error;\n }\n }\n\n /**\n * Check if request should be retried\n */\n private shouldRetry(error: unknown): boolean {\n if (!axios.isAxiosError(error)) return false;\n\n const status = error.response?.status;\n // Retry on network errors or 5xx status codes\n return !status || status >= 500;\n }\n\n /**\n * Delay helper for retry logic\n */\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * Handle and transform axios errors\n */\n private handleError(error: unknown): Error {\n if (!axios.isAxiosError(error)) {\n return error instanceof Error ? error : new Error(String(error));\n }\n\n const axiosError = error as AxiosError<{ error?: { message: string } }>;\n const message =\n axiosError.response?.data?.error?.message ||\n axiosError.message ||\n \"An unknown error occurred\";\n\n const status = axiosError.response?.status;\n\n switch (status) {\n case 401:\n return new AuthenticationError(message);\n case 429:\n const retryAfter = parseInt(\n axiosError.response?.headers[\"retry-after\"] || \"60\",\n );\n return new RateLimitError(message, retryAfter);\n case 422:\n return new ValidationError(message);\n case 400:\n return new ValidationError(message);\n case 404:\n return new DDEXError(`Resource not found: ${message}`);\n case 500:\n case 502:\n case 503:\n case 504:\n return new NetworkError(`Server error: ${message}`);\n default:\n if (!axiosError.response) {\n return new NetworkError(`Network error: ${message}`);\n }\n return new DDEXError(message);\n }\n }\n\n /**\n * Get current environment\n */\n private getEnvironment(): string {\n if (typeof window !== \"undefined\") {\n return `browser/${this.config.environment}`;\n }\n if (typeof process !== \"undefined\" && process.versions?.node) {\n return `node/${process.version}/${this.config.environment}`;\n }\n return this.config.environment || \"unknown\";\n }\n\n /**\n * Update API key\n *\n * @param apiKey - New API key\n */\n setApiKey(apiKey: string): void {\n this.config.apiKey = apiKey;\n this.client.defaults.headers.common[\"X-API-Key\"] = apiKey;\n }\n\n /**\n * Remove API key\n */\n clearApiKey(): void {\n this.config.apiKey = undefined;\n delete this.client.defaults.headers.common[\"X-API-Key\"];\n }\n\n /**\n * Get current configuration\n */\n getConfig(): Readonly<DDEXClientConfig> {\n return { ...this.config };\n }\n}","// packages/sdk/src/errors.ts\n\n/**\n * Base error class for DDEX SDK errors\n */\nexport class DDEXError extends Error {\n constructor(\n message: string,\n public readonly code?: string,\n public readonly details?: unknown,\n ) {\n super(message);\n this.name = \"DDEXError\";\n Object.setPrototypeOf(this, DDEXError.prototype);\n }\n}\n\n/**\n * Rate limit error\n */\nexport class RateLimitError extends DDEXError {\n constructor(\n message: string,\n public readonly retryAfter: number,\n ) {\n super(message, \"RATE_LIMIT_EXCEEDED\");\n this.name = \"RateLimitError\";\n Object.setPrototypeOf(this, RateLimitError.prototype);\n }\n\n /**\n * Get a formatted retry message\n */\n getRetryMessage(): string {\n return `Rate limit exceeded. Please retry after ${this.retryAfter} seconds.`;\n }\n}\n\n/**\n * Authentication error\n */\nexport class AuthenticationError extends DDEXError {\n constructor(message: string) {\n super(message, \"AUTHENTICATION_FAILED\");\n this.name = \"AuthenticationError\";\n Object.setPrototypeOf(this, AuthenticationError.prototype);\n }\n}\n\n/**\n * Validation error\n */\nexport class ValidationError extends DDEXError {\n constructor(\n message: string,\n public readonly validationErrors?: Array<{\n field?: string;\n message: string;\n code?: string;\n }>,\n ) {\n super(message, \"VALIDATION_ERROR\");\n this.name = \"ValidationError\";\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n\n /**\n * Get a summary of validation errors\n */\n getSummary(): string {\n if (!this.validationErrors || this.validationErrors.length === 0) {\n return this.message;\n }\n\n const errors = this.validationErrors\n .map((e) => (e.field ? `${e.field}: ${e.message}` : e.message))\n .join(\", \");\n\n return `${this.message}: ${errors}`;\n }\n}\n\n/**\n * Network error\n */\nexport class NetworkError extends DDEXError {\n constructor(\n message: string,\n public readonly statusCode?: number,\n ) {\n super(message, \"NETWORK_ERROR\");\n this.name = \"NetworkError\";\n Object.setPrototypeOf(this, NetworkError.prototype);\n }\n\n /**\n * Check if error is retryable\n */\n isRetryable(): boolean {\n if (!this.statusCode) return true;\n return this.statusCode >= 500 && this.statusCode < 600;\n }\n}\n\n/**\n * Not found error\n */\nexport class NotFoundError extends DDEXError {\n constructor(\n message: string,\n public readonly resource?: string,\n ) {\n super(message, \"NOT_FOUND\");\n this.name = \"NotFoundError\";\n Object.setPrototypeOf(this, NotFoundError.prototype);\n }\n}\n\n/**\n * Configuration error\n */\nexport class ConfigurationError extends DDEXError {\n constructor(\n message: string,\n public readonly field?: string,\n ) {\n super(message, \"CONFIGURATION_ERROR\");\n this.name = \"ConfigurationError\";\n Object.setPrototypeOf(this, ConfigurationError.prototype);\n }\n}\n\n/**\n * Timeout error\n */\nexport class TimeoutError extends DDEXError {\n constructor(\n message: string,\n public readonly timeout: number,\n ) {\n super(message, \"TIMEOUT\");\n this.name = \"TimeoutError\";\n Object.setPrototypeOf(this, TimeoutError.prototype);\n }\n}\n\n/**\n * File error\n */\nexport class FileError extends DDEXError {\n constructor(\n message: string,\n public readonly filePath?: string,\n ) {\n super(message, \"FILE_ERROR\");\n this.name = \"FileError\";\n Object.setPrototypeOf(this, FileError.prototype);\n }\n}\n\n/**\n * Parse error for XML parsing issues\n */\nexport class ParseError extends DDEXError {\n constructor(\n message: string,\n public readonly line?: number,\n public readonly column?: number,\n ) {\n super(message, \"PARSE_ERROR\");\n this.name = \"ParseError\";\n Object.setPrototypeOf(this, ParseError.prototype);\n }\n\n /**\n * Get formatted error location\n */\n getLocation(): string {\n if (this.line !== undefined && this.column !== undefined) {\n return `Line ${this.line}, Column ${this.column}`;\n }\n if (this.line !== undefined) {\n return `Line ${this.line}`;\n }\n return \"Unknown location\";\n }\n}\n\n/**\n * API error wrapper for server errors\n */\nexport class APIError extends DDEXError {\n constructor(\n message: string,\n public readonly statusCode: number,\n public readonly response?: unknown,\n ) {\n super(message, `API_ERROR_${statusCode}`);\n this.name = \"APIError\";\n Object.setPrototypeOf(this, APIError.prototype);\n }\n\n /**\n * Check if error is client error (4xx)\n */\n isClientError(): boolean {\n return this.statusCode >= 400 && this.statusCode < 500;\n }\n\n /**\n * Check if error is server error (5xx)\n */\n isServerError(): boolean {\n return this.statusCode >= 500 && this.statusCode < 600;\n }\n}","// packages/sdk/src/validator.ts\nimport { DDEXClient } from \"./client\";\nimport {\n ValidationResult,\n ValidationOptions,\n ValidationErrorDetail,\n ERNVersion,\n ERNProfile,\n PassedRule,\n SVRLStatistics,\n ValidationSummary,\n BatchValidationOptions,\n BatchValidationResult,\n} from \"./types\";\n\n/**\n * DDEX Validator - High-level validation helper\n *\n * @example\n * ```typescript\n * const validator = client.validator;\n * \n * // Auto-detect version\n * const version = validator.detectVersion(xmlContent);\n * \n * // Validate with SVRL\n * const result = await validator.validateWithSVRL(xmlContent, {\n * version: '4.3',\n * profile: 'AudioAlbum'\n * });\n * ```\n */\nexport class DDEXValidator {\n constructor(private readonly client: DDEXClient) {}\n\n /**\n * Validate with automatic version detection\n *\n * @param content - XML content\n * @param profile - Optional profile\n * @returns Validation result\n */\n async validateAuto(\n content: string,\n profile?: ERNProfile,\n ): Promise<ValidationResult> {\n const version = this.detectVersion(content);\n if (!version) {\n throw new Error(\"Could not detect ERN version from XML content\");\n }\n\n return this.client.validate(content, { version, profile });\n }\n\n /**\n * Validate with SVRL report generation\n *\n * @param content - XML content\n * @param options - Validation options\n * @returns Validation result with SVRL\n */\n async validateWithSVRL(\n content: string,\n options: ValidationOptions,\n ): Promise<ValidationResult> {\n return this.client.validateWithSVRL(content, options);\n }\n\n /**\n * Validate multiple files in batch\n *\n * @param items - Array of content and options\n * @param batchOptions - Batch processing options\n * @returns Batch validation results\n */\n async validateBatch(\n items: Array<{ content: string; options: ValidationOptions }>,\n batchOptions?: BatchValidationOptions,\n ): Promise<BatchValidationResult> {\n return this.client.validateBatch(items, batchOptions);\n }\n\n /**\n * Check if content is valid (simplified check)\n *\n * @param content - XML content\n * @param options - Validation options\n * @returns Boolean indicating validity\n */\n async isValid(\n content: string,\n options: ValidationOptions,\n ): Promise<boolean> {\n const result = await this.client.validate(content, options);\n return result.valid;\n }\n\n /**\n * Get only errors (no warnings)\n *\n * @param content - XML content\n * @param options - Validation options\n * @returns Array of errors\n */\n async getErrors(\n content: string,\n options: ValidationOptions,\n ): Promise<ValidationErrorDetail[]> {\n const result = await this.client.validate(content, options);\n return result.errors;\n }\n\n /**\n * Get only critical errors (severity: error or fatal)\n *\n * @param result - Validation result\n * @returns Array of critical errors\n */\n getCriticalErrors(result: ValidationResult): ValidationErrorDetail[] {\n return result.errors.filter(\n (error) => error.severity === \"error\" || error.severity === \"fatal\",\n );\n }\n\n /**\n * Get only schematron-specific errors\n *\n * @param result - Validation result\n * @returns Array of schematron errors\n */\n getSchematronErrors(result: ValidationResult): ValidationErrorDetail[] {\n return result.errors.filter(\n (error) => error.rule && error.rule.startsWith(\"Schematron-\"),\n );\n }\n\n /**\n * Get only XSD schema errors\n *\n * @param result - Validation result\n * @returns Array of XSD errors\n */\n getXSDErrors(result: ValidationResult): ValidationErrorDetail[] {\n return result.errors.filter(\n (error) => error.rule && (error.rule.startsWith(\"XSD-\") || error.rule === \"XSD\"),\n );\n }\n\n /**\n * Get only business rule errors\n *\n * @param result - Validation result\n * @returns Array of business rule errors\n */\n getBusinessRuleErrors(result: ValidationResult): ValidationErrorDetail[] {\n return result.errors.filter(\n (error) => error.rule && error.rule.startsWith(\"BusinessRule-\"),\n );\n }\n\n /**\n * Parse SVRL report to extract statistics\n *\n * @param svrl - SVRL XML string\n * @returns SVRL statistics\n */\n parseSVRL(svrl: string): SVRLStatistics {\n // Basic SVRL parsing using regex\n const assertions = (svrl.match(/<svrl:successful-report/g) || []).length;\n const failures = (svrl.match(/<svrl:failed-assert/g) || []).length;\n const warnings = (svrl.match(/role=\"warning\"/g) || []).length;\n const firedRules = (svrl.match(/<svrl:fired-rule/g) || []).length;\n\n // Extract profile and schema version if present\n const profileMatch = svrl.match(/profile=\"([^\"]+)\"/);\n const schemaMatch = svrl.match(/schemaVersion=\"([^\"]+)\"/);\n\n return {\n assertions,\n failures,\n warnings,\n firedRules,\n profile: profileMatch ? profileMatch[1] : undefined,\n schemaVersion: schemaMatch ? schemaMatch[1] : undefined,\n };\n }\n\n /**\n * Get profile compliance report\n *\n * @param content - XML content\n * @param version - ERN version\n * @param profile - ERN profile\n * @returns Detailed compliance report\n */\n async getProfileCompliance(\n content: string,\n version: ERNVersion,\n profile: ERNProfile,\n ): Promise<{\n compliant: boolean;\n profile: string;\n version: string;\n errors: number;\n warnings: number;\n passedRules: number;\n failedRules: number;\n complianceRate: number;\n svrlAvailable: boolean;\n details?: PassedRule[];\n }> {\n const result = await this.client.validate(content, {\n version,\n profile,\n generateSVRL: true,\n verbose: true,\n });\n\n const passedRulesCount = result.passedRules?.length || 0;\n const failedRulesCount = result.errors.filter(\n (e) => e.rule && e.rule.startsWith(\"Schematron-\"),\n ).length;\n const totalRules = passedRulesCount + failedRulesCount;\n const complianceRate = totalRules > 0 \n ? (passedRulesCount / totalRules) * 100 \n : 0;\n\n return {\n compliant: result.valid,\n profile,\n version,\n errors: result.errors.length,\n warnings: result.warnings.length,\n passedRules: passedRulesCount,\n failedRules: failedRulesCount,\n complianceRate: Math.round(complianceRate * 100) / 100,\n svrlAvailable: result.svrl !== undefined,\n details: result.passedRules,\n };\n }\n\n /**\n * Generate validation summary\n *\n * @param result - Validation result\n * @returns Validation summary\n */\n generateSummary(result: ValidationResult): ValidationSummary {\n const passedRules = result.passedRules?.length || 0;\n const failedRules = result.errors.filter((e) => e.rule).length;\n const totalRules = passedRules + failedRules;\n const complianceRate = totalRules > 0 \n ? (passedRules / totalRules) * 100 \n : 0;\n\n const schemaErrors = this.getXSDErrors(result).length;\n const schematronErrors = this.getSchematronErrors(result).length;\n\n return {\n totalRules,\n passedRules,\n failedRules,\n complianceRate: Math.round(complianceRate * 100) / 100,\n profileCompliant: schematronErrors === 0,\n schemaCompliant: schemaErrors === 0,\n };\n }\n\n /**\n * Format validation errors for display\n *\n * @param errors - Array of errors\n * @param options - Formatting options\n * @returns Formatted error string\n */\n formatErrors(\n errors: ValidationErrorDetail[],\n options: {\n includeContext?: boolean;\n includeSuggestions?: boolean;\n groupByRule?: boolean;\n maxErrors?: number;\n } = {},\n ): string {\n const errorsToShow = options.maxErrors \n ? errors.slice(0, options.maxErrors)\n : errors;\n\n if (options.groupByRule) {\n const grouped = this.groupErrorsByRule(errorsToShow);\n return Object.entries(grouped)\n .map(([rule, ruleErrors]) => {\n const errorList = ruleErrors\n .map((e) => this.formatSingleError(e, options))\n .join(\"\\n \");\n return `${rule} (${ruleErrors.length} errors):\\n ${errorList}`;\n })\n .join(\"\\n\\n\");\n }\n\n return errorsToShow\n .map((e) => this.formatSingleError(e, options))\n .join(\"\\n\");\n }\n\n /**\n * Format a single error\n */\n private formatSingleError(\n error: ValidationErrorDetail,\n options: {\n includeContext?: boolean;\n includeSuggestions?: boolean;\n },\n ): string {\n let formatted = `Line ${error.line}:${error.column} - ${error.message}`;\n \n if (options.includeContext && error.context) {\n formatted += ` (Context: ${error.context})`;\n }\n \n if (options.includeSuggestions && error.suggestion) {\n formatted += `\\n Suggestion: ${error.suggestion}`;\n }\n \n return formatted;\n }\n\n /**\n * Group errors by rule\n */\n private groupErrorsByRule(\n errors: ValidationErrorDetail[],\n ): Record<string, ValidationErrorDetail[]> {\n return errors.reduce((acc, error) => {\n const rule = error.rule || \"Unknown\";\n if (!acc[rule]) {\n acc[rule] = [];\n }\n acc[rule].push(error);\n return acc;\n }, {} as Record<string, ValidationErrorDetail[]>);\n }\n\n /**\n * Detect ERN version from XML content\n *\n * @param content - XML content\n * @returns Detected version or null\n */\n detectVersion(content: string): ERNVersion | null {\n // Check for ERN 4.3\n if (\n content.includes('xmlns:ern=\"http://ddex.net/xml/ern/43\"') ||\n content.includes('MessageSchemaVersionId=\"ern/43\"') ||\n content.includes('/ern/43')\n ) {\n return \"4.3\";\n }\n\n // Check for ERN 4.2\n if (\n content.includes('xmlns:ern=\"http://ddex.net/xml/ern/42\"') ||\n content.includes('MessageSchemaVersionId=\"ern/42\"') ||\n content.includes('/ern/42')\n ) {\n return \"4.2\";\n }\n\n // Check for ERN 3.8.2\n if (\n content.includes('xmlns:ern=\"http://ddex.net/xml/ern/382\"') ||\n content.includes('MessageSchemaVersionId=\"ern/382\"') ||\n content.includes('/ern/382') ||\n content.includes('xmlns:ernm=\"http://ddex.net/xml/ern/382\"')\n ) {\n return \"3.8.2\";\n }\n\n // Legacy version detection\n if (content.includes('xmlns:ern=\"http://ddex.net/xml/ern/38\"')) {\n return \"3.8.2\";\n }\n\n return null;\n }\n\n /**\n * Detect profile from XML content\n *\n * @param content - XML content\n * @returns Detected profile or null\n */\n detectProfile(content: string): ERNProfile | null {\n const profilePatterns: Record<ERNProfile, RegExp[]> = {\n AudioAlbum: [\n /ReleaseProfileVersionId=\"[^\"]*AudioAlbum/i,\n /Profile[^>]*AudioAlbum/i,\n ],\n AudioSingle: [\n /ReleaseProfileVersionId=\"[^\"]*AudioSingle/i,\n /Profile[^>]*AudioSingle/i,\n ],\n Video: [\n /ReleaseProfileVersionId=\"[^\"]*Video/i,\n /Profile[^>]*Video/i,\n ],\n Mixed: [\n /ReleaseProfileVersionId=\"[^\"]*Mixed/i,\n /Profile[^>]*Mixed/i,\n ],\n Classical: [\n /ReleaseProfileVersionId=\"[^\"]*Classical/i,\n /Profile[^>]*Classical/i,\n ],\n Ringtone: [\n /ReleaseProfileVersionId=\"[^\"]*Ringtone/i,\n /Profile[^>]*Ringtone/i,\n ],\n DJ: [\n /ReleaseProfileVersionId=\"[^\"]*DJ/i,\n /Profile[^>]*DJ/i,\n ],\n ReleaseByRelease: [\n /ReleaseProfileVersionId=\"[^\"]*ReleaseByRelease/i,\n /Profile[^>]*ReleaseByRelease/i,\n ],\n };\n\n for (const [profile, patterns] of Object.entries(profilePatterns)) {\n if (patterns.some((pattern) => pattern.test(content))) {\n return profile as ERNProfile;\n }\n }\n\n return null;\n }\n\n /**\n * Extract metadata from XML content\n *\n * @param content - XML content\n * @returns Extracted metadata\n */\n extractMetadata(content: string): {\n version?: ERNVersion;\n profile?: ERNProfile;\n messageId?: string;\n createdDate?: string;\n releaseCount?: number;\n } {\n const metadata: ReturnType<typeof this.extractMetadata> = {};\n\n // Detect version and profile\n metadata.version = this.detectVersion(content) || undefined;\n metadata.profile = this.detectProfile(content) || undefined;\n\n // Extract MessageId\n const messageIdMatch = content.match(/MessageId>([^<]+)</);\n if (messageIdMatch) {\n metadata.messageId = messageIdMatch[1];\n }\n\n // Extract CreatedDate\n const createdDateMatch = content.match(/MessageCreatedDateTime>([^<]+)</);\n if (createdDateMatch) {\n metadata.createdDate = createdDateMatch[1];\n }\n\n // Count releases\n const releaseMatches = content.match(/<Release[^>]*>/g);\n if (releaseMatches) {\n metadata.releaseCount = releaseMatches.length;\n }\n\n return metadata;\n }\n}"],"mappings":"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","names":["axios","DDEXError","_DDEXError","message","code","details","RateLimitError","_RateLimitError","retryAfter","AuthenticationError","_AuthenticationError","ValidationError","_ValidationError","validationErrors","errors","e","NetworkError","_NetworkError","statusCode","NotFoundError","_NotFoundError","resource","ConfigurationError","_ConfigurationError","field","TimeoutError","_TimeoutError","timeout","FileError","_FileError","filePath","ParseError","_ParseError","line","column","APIError","_APIError","response","DDEXValidator","client","content","profile","version","options","items","batchOptions","result","error","svrl","assertions","failures","warnings","firedRules","profileMatch","schemaMatch","_a","passedRulesCount","failedRulesCount","e","totalRules","complianceRate","passedRules","failedRules","schemaErrors","schematronErrors","errors","errorsToShow","grouped","rule","ruleErrors","errorList","formatted","acc","profilePatterns","patterns","pattern","metadata","messageIdMatch","createdDateMatch","releaseMatches","DDEXClient","config","axios","DDEXValidator","content","options","error","filePath","fs","path","stats","result","hash","url","response","items","batchOptions","startTime","concurrency","results","validFiles","completed","i","chunk","chunkResults","item","errorMessage","name","keyId","request","retries","_a","status","ms","resolve","_b","_c","_d","_e","axiosError","message","AuthenticationError","retryAfter","RateLimitError","ValidationError","DDEXError","NetworkError","apiKey"]}