/** * ServiceWorker Mock Configuration Management */ import type { SwMockConfig } from '../types'; export const DEFAULT_CONFIG: SwMockConfig = { enabled: false, debug: false, defaultDelay: 500, interceptPatterns: [ '/api/', ], excludePatterns: [ '/sw-mock-worker.js', '/mock/', '.js', '.css', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.ico', '.woff', '.woff2', '.ttf', '.eot' ], endpoints: {}, globalDelay: null, errorRate: 0, mockDataPath: '/mock', includeInterceptPrefix: true, networkFailure: { enabled: false, scenarios: { httpErrors: { enabled: false, statusCodes: [400, 401, 403, 404, 500, 502, 503, 504], rate: 0.1, distribution: 'random' }, timeout: { enabled: false, duration: 30000, rate: 0.05 }, connectionFailure: { enabled: false, rate: 0.02 }, responseDelay: { enabled: false, minDelay: 1000, maxDelay: 5000, rate: 0.3 }, intermittentFailure: { enabled: false, failureDuration: 10000, recoveryDuration: 30000, rate: 0.1 } } } }; export const PRESET_CONFIGS = { development: { enabled: true, networkFailure: { enabled: true, scenarios: { httpErrors: { enabled: true, statusCodes: [500, 502, 503], rate: 0.05, distribution: 'random' }, responseDelay: { enabled: true, minDelay: 500, maxDelay: 2000, rate: 0.2 }, timeout: { enabled: false }, connectionFailure: { enabled: false }, intermittentFailure: { enabled: false } } } } as Partial, testing: { enabled: true, networkFailure: { enabled: true, scenarios: { httpErrors: { enabled: true, statusCodes: [400, 401, 403, 404, 500, 502, 503, 504], rate: 0.15, distribution: 'weighted' }, timeout: { enabled: true, duration: 15000, rate: 0.05 }, connectionFailure: { enabled: true, rate: 0.02 }, responseDelay: { enabled: true, minDelay: 1000, maxDelay: 3000, rate: 0.25 }, intermittentFailure: { enabled: false } } } } as Partial, stress: { enabled: true, networkFailure: { enabled: true, scenarios: { httpErrors: { enabled: true, statusCodes: [400, 401, 403, 404, 500, 502, 503, 504], rate: 0.3, distribution: 'weighted' }, timeout: { enabled: true, duration: 10000, rate: 0.1 }, connectionFailure: { enabled: true, rate: 0.05 }, responseDelay: { enabled: true, minDelay: 2000, maxDelay: 8000, rate: 0.4 }, intermittentFailure: { enabled: true, failureDuration: 8000, recoveryDuration: 20000, rate: 0.1 } } } } as Partial }; /** * Ensure configuration structure integrity */ export function ensureConfigStructure(configData: Partial): SwMockConfig { const mergedConfig = { ...DEFAULT_CONFIG, ...configData }; // Ensure networkFailure structure is complete if (!mergedConfig.networkFailure) { mergedConfig.networkFailure = { ...DEFAULT_CONFIG.networkFailure }; } else { mergedConfig.networkFailure = { ...DEFAULT_CONFIG.networkFailure, ...mergedConfig.networkFailure }; // Ensure scenarios structure is complete if (!mergedConfig.networkFailure.scenarios) { mergedConfig.networkFailure.scenarios = { ...DEFAULT_CONFIG.networkFailure.scenarios }; } else { mergedConfig.networkFailure.scenarios = { ...DEFAULT_CONFIG.networkFailure.scenarios, ...mergedConfig.networkFailure.scenarios }; } } return mergedConfig; } /** * Merge configurations with deep merge for nested objects */ export function mergeConfigs(base: SwMockConfig, override: Partial): SwMockConfig { const result = { ...base, ...override }; // Deep merge networkFailure if (override.networkFailure) { result.networkFailure = { ...base.networkFailure, ...override.networkFailure }; if (override.networkFailure.scenarios) { result.networkFailure.scenarios = { ...base.networkFailure.scenarios, ...override.networkFailure.scenarios }; } } // Merge arrays if (override.interceptPatterns) { result.interceptPatterns = [...new Set([...base.interceptPatterns, ...override.interceptPatterns])]; } if (override.excludePatterns) { result.excludePatterns = [...new Set([...base.excludePatterns, ...override.excludePatterns])]; } // Merge endpoints if (override.endpoints) { result.endpoints = { ...base.endpoints, ...override.endpoints }; } return ensureConfigStructure(result); } /** * Validate configuration */ export function validateConfig(config: Partial): string[] { const errors: string[] = []; if (config.defaultDelay !== undefined && (config.defaultDelay < 0 || config.defaultDelay > 60000)) { errors.push('defaultDelay must be between 0 and 60000ms'); } if (config.globalDelay !== undefined && config.globalDelay !== null && (config.globalDelay < 0 || config.globalDelay > 60000)) { errors.push('globalDelay must be between 0 and 60000ms or null'); } if (config.errorRate !== undefined && (config.errorRate < 0 || config.errorRate > 1)) { errors.push('errorRate must be between 0 and 1'); } if (config.networkFailure?.scenarios) { const scenarios = config.networkFailure.scenarios; Object.entries(scenarios).forEach(([key, scenario]) => { if (scenario && 'rate' in scenario && (scenario.rate < 0 || scenario.rate > 1)) { errors.push(`${key}.rate must be between 0 and 1`); } }); } return errors; }