import { z } from 'zod';
const ConfigSchema = z.object({
azureTenantId: z.string().optional(),
azureSubscriptionId: z.string().optional(),
operatorEmail: z.string().email().optional(),
operatorName: z.string().optional(),
logLevel: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
enableCache: z.boolean().default(true),
cacheTtlSeconds: z.number().min(0).default(300),
cacheCleanupIntervalMs: z.number().min(1000).default(60000),
enableAuditLog: z.boolean().default(true),
auditLogPath: z.string().default('./audit.log'),
maxRetries: z.number().min(0).max(10).default(3),
retryDelayMs: z.number().min(100).default(1000),
commandTimeoutMs: z.number().min(1000).default(120000),
includeProductionCredentials: z.boolean().default(false),
});
export type Config = z.infer<typeof ConfigSchema>;
const parseBool = (val: string | undefined, def: boolean): boolean =>
val === undefined ? def : val.toLowerCase() === 'true';
const parseNum = (val: string | undefined, def: number): number => {
if (val === undefined) return def;
const n = parseInt(val, 10);
return isNaN(n) ? def : n;
};
export function loadConfig(): Config {
const raw = {
azureTenantId: process.env.AZURE_TENANT_ID,
azureSubscriptionId: process.env.AZURE_SUBSCRIPTION_ID,
operatorEmail: process.env.OPERATOR_EMAIL || undefined,
operatorName: process.env.OPERATOR_NAME,
logLevel: (process.env.LOG_LEVEL as Config['logLevel']) || 'info',
enableCache: parseBool(process.env.ENABLE_CACHE, true),
cacheTtlSeconds: parseNum(process.env.CACHE_TTL_SECONDS, 300),
cacheCleanupIntervalMs: parseNum(process.env.CACHE_CLEANUP_INTERVAL_MS, 60000),
enableAuditLog: parseBool(process.env.ENABLE_AUDIT_LOG, true),
auditLogPath: process.env.AUDIT_LOG_PATH || './audit.log',
maxRetries: parseNum(process.env.MAX_RETRIES, 3),
retryDelayMs: parseNum(process.env.RETRY_DELAY_MS, 1000),
commandTimeoutMs: parseNum(process.env.COMMAND_TIMEOUT_MS, 120000),
includeProductionCredentials: parseBool(process.env.AZURE_MCP_INCLUDE_PRODUCTION_CREDENTIALS, false),
};
const result = ConfigSchema.safeParse(raw);
if (!result.success) {
const errors = result.error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');
throw new Error(`Config validation failed: ${errors}`);
}
return result.data;
}
let configInstance: Config | null = null;
export function getConfig(): Config {
if (!configInstance) configInstance = loadConfig();
return configInstance;
}
export function resetConfig(): void {
configInstance = null;
}
export function getAzureScopeArgs(): string[] {
const config = getConfig();
const args: string[] = [];
if (config.azureTenantId) args.push(`--tenant "${config.azureTenantId}"`);
if (config.azureSubscriptionId) args.push(`--subscription "${config.azureSubscriptionId}"`);
return args;
}
export function getOperatorInfo(): { email?: string; name?: string } {
const { operatorEmail: email, operatorName: name } = getConfig();
return { email, name };
}