Skip to main content
Glama
ThemeServiceFactory.ts3.86 kB
/** * ThemeServiceFactory * * DESIGN PATTERNS: * - Factory pattern for creating theme service instances * - Supports built-in CSS theme extraction and custom service loading * * CODING STANDARDS: * - Use async factory method for dynamic service loading * - Return typed results * - Throw descriptive errors with context * * AVOID: * - Synchronous file operations * - Hardcoded service paths */ import { BaseThemeService } from './BaseThemeService'; import { CSSThemeService } from './CSSThemeService'; import type { ThemeServiceConfig } from './types'; import { DEFAULT_THEME_SERVICE_CONFIG } from './types'; /** * Factory for creating theme service instances. * * Supports the built-in CSSThemeService and custom service implementations * loaded dynamically from user-specified paths. * * @example * ```typescript * const factory = new ThemeServiceFactory(); * * // Create default CSS-based service * const service = await factory.createService({ * themePath: 'apps/my-app/src/styles/colors.css' * }); * * // Create with custom service override * const customService = await factory.createService({ * customServicePath: './my-custom-theme-service.ts' * }); * * const themes = await service.listThemes(); * ``` */ export class ThemeServiceFactory { /** * Create a theme service based on configuration. * * Resolution order: * 1. If customServicePath is provided, load custom service dynamically * 2. Otherwise, create the default CSSThemeService * * @param config - Theme service configuration * @returns Promise resolving to a theme service instance * @throws Error if custom service cannot be loaded or is invalid */ async createService(config: Partial<ThemeServiceConfig> = {}): Promise<BaseThemeService> { const resolvedConfig: ThemeServiceConfig = { ...DEFAULT_THEME_SERVICE_CONFIG, ...config, }; // If custom service path is provided, load dynamically if (resolvedConfig.customServicePath) { return this.loadCustomService(resolvedConfig); } // Use built-in CSS theme service return new CSSThemeService(resolvedConfig); } /** * Load a custom theme service from user-specified path. * * The custom service must export a class that extends BaseThemeService. * * @param config - Configuration with customServicePath set * @returns Promise resolving to custom service instance * @throws Error if service cannot be loaded or is invalid */ private async loadCustomService(config: ThemeServiceConfig): Promise<BaseThemeService> { const servicePath = config.customServicePath; if (!servicePath) { throw new Error('customServicePath is required for custom service loading'); } try { // Dynamic import required: path is user-specified at runtime const customModule = await import(servicePath); // Look for default export or named exports that extend BaseThemeService const ServiceClass = customModule.default || customModule.ThemeService || customModule.CustomThemeService; if (!ServiceClass) { throw new Error( `Custom service module at ${servicePath} must export a default class, ` + `ThemeService, or CustomThemeService that extends BaseThemeService`, ); } const instance = new ServiceClass(config); if (!(instance instanceof BaseThemeService)) { throw new Error(`Custom service at ${servicePath} must extend BaseThemeService`); } return instance; } catch (error) { if (error instanceof Error && error.message.includes('BaseThemeService')) { throw error; } throw new Error( `Failed to load custom theme service from ${servicePath}: ${error instanceof Error ? error.message : String(error)}`, ); } } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/AgiFlow/aicode-toolkit'

If you have feedback or need assistance with the MCP directory API, please join our Discord server