import { InquiryType } from '../common/enums/inquiry-type.enum'; import { ProviderName } from '../common/enums/provider-name.enum'; export type AuthMethod = 'AMITIS' | 'SOAP' | 'OAUTH2' | 'NONE'; export interface InquiryConfig { url: string; username: string; password: string; apiKey: string; authMethod: AuthMethod; } export interface ProviderEnvConfig { enabled: boolean; timeout: number; maxRetries: number; inquiries: Partial>; } export interface AmitisAuthServiceConfig { baseUrl: string; loginPath: string; refreshPath: string; tokenTimeZone: string; timeout: number; enabled: boolean; } export interface TejaratNouConfig { enabled: boolean; timeout: number; maxRetries: number; authUrl: string; clientId: string; clientSecret: string; username: string; password: string; inquiries: Partial>; } export interface InquiryRoutingConfig { defaultProvider: ProviderName; fallbackEnabled: boolean; fallbackProviders: ProviderName[]; } /** * Central configuration factory — maps environment variables to typed config. * Provider routing is deployment-specific and lives under inquiryRouting. */ export default () => ({ app: { port: parseInt(process.env.PORT ?? '8085', 10), nodeEnv: process.env.NODE_ENV ?? 'development', }, mongodb: { uri: process.env.MONGODB_URI ?? 'mongodb://localhost:27017/inquiry-gateway', }, auth: { apiKey: process.env.API_KEY ?? '', jwtSecret: process.env.JWT_SECRET ?? 'change-me-in-production', jwtRefreshSecret: process.env.JWT_REFRESH_SECRET ?? process.env.JWT_SECRET ?? 'change-me-refresh', jwtAccessExpiresIn: process.env.JWT_ACCESS_EXPIRES_IN ?? '15m', jwtRefreshExpiresIn: process.env.JWT_REFRESH_EXPIRES_IN ?? '7d', jwtEnabled: process.env.JWT_ENABLED !== 'false', bcryptSaltRounds: parseInt(process.env.BCRYPT_SALT_ROUNDS ?? '12', 10), }, throttle: { ttl: parseInt(process.env.THROTTLE_TTL ?? '60', 10), limit: parseInt(process.env.THROTTLE_LIMIT ?? '100', 10), }, amitis: { baseUrl: process.env.AMITIS_BASE_URL ?? 'https://auth.services.centinsur.ir', loginPath: process.env.AMITIS_LOGIN_PATH ?? '/api/security/login', refreshPath: process.env.AMITIS_REFRESH_PATH ?? '/api/security/RefreshToken', tokenTimeZone: process.env.AMITIS_TOKEN_TIME_ZONE ?? 'Asia/Tehran', timeout: parseInt(process.env.AMITIS_TIMEOUT ?? '10000', 10), enabled: process.env.AMITIS_ENABLED !== 'false', } satisfies AmitisAuthServiceConfig, hamta: buildProviderConfig('HAMTA'), moallem: buildProviderConfig('MOALLEM'), parsian: buildProviderConfig('PARSIAN'), tejaratnou: { enabled: process.env.TEJARATNOU_ENABLED !== 'false', timeout: parseInt(process.env.TEJARATNOU_TIMEOUT ?? '15000', 10), maxRetries: parseInt(process.env.TEJARATNOU_MAX_RETRIES ?? '2', 10), authUrl: process.env.TEJARATNOU_AUTH_URL ?? 'https://accounts.tejaratnoins.ir', clientId: process.env.TEJARATNOU_CLIENT_ID ?? 'api-gateway', clientSecret: process.env.TEJARATNOU_CLIENT_SECRET ?? '', username: process.env.TEJARATNOU_USERNAME ?? '', password: process.env.TEJARATNOU_PASSWORD ?? '', inquiries: { [InquiryType.PERSON]: buildInquiryConfig('TEJARATNOU', 'PERSON'), }, } satisfies TejaratNouConfig, inquiryRouting: { [InquiryType.PERSON]: buildInquiryRoutingConfig('PERSON', ProviderName.PARSIAN, [ ProviderName.HAMTA, ProviderName.TEJARATNOU, ]), [InquiryType.REAL_ESTATE]: buildInquiryRoutingConfig('REAL_ESTATE', ProviderName.HAMTA, [ ProviderName.MOALLEM, ]), [InquiryType.SHEBA]: buildInquiryRoutingConfig('SHEBA', ProviderName.PARSIAN, [ ProviderName.HAMTA, ]), [InquiryType.SHAHKAR]: buildInquiryRoutingConfig('SHAHKAR', ProviderName.PARSIAN, [ ProviderName.HAMTA, ]), [InquiryType.POSTAL_CODE]: buildInquiryRoutingConfig('POSTAL_CODE', ProviderName.MOALLEM, [ ProviderName.HAMTA, ]), [InquiryType.LEGAL_PERSON]: buildInquiryRoutingConfig('LEGAL_PERSON', ProviderName.HAMTA, [ ProviderName.MOALLEM, ]), [InquiryType.CAR_PLATE]: buildInquiryRoutingConfig('CAR_PLATE', ProviderName.HAMTA, []), [InquiryType.POLICY_BY_CHASSIS]: buildInquiryRoutingConfig( 'POLICY_BY_CHASSIS', ProviderName.PARSIAN, [], ), [InquiryType.POLICY_BY_PLATE]: buildInquiryRoutingConfig( 'POLICY_BY_PLATE', ProviderName.PARSIAN, [], ), [InquiryType.POLICY_BY_NATIONAL_CODE]: buildInquiryRoutingConfig( 'POLICY_BY_NATIONAL_CODE', ProviderName.PARSIAN, [], ), } satisfies Record, }); function buildProviderConfig(prefix: string): ProviderEnvConfig { const inquiryTypes = [ InquiryType.PERSON, InquiryType.REAL_ESTATE, InquiryType.SHAHKAR, InquiryType.SHEBA, InquiryType.POSTAL_CODE, InquiryType.LEGAL_PERSON, InquiryType.CAR_PLATE, InquiryType.POLICY_BY_CHASSIS, InquiryType.POLICY_BY_PLATE, InquiryType.POLICY_BY_NATIONAL_CODE, ]; const inquiries: Partial> = {}; for (const inquiryType of inquiryTypes) { const inquiryConfig = buildInquiryConfig(prefix, inquiryTypeToEnvName(inquiryType)); if (inquiryConfig.url || inquiryConfig.username) { inquiries[inquiryType] = inquiryConfig; } } return { enabled: process.env[`${prefix}_ENABLED`] !== 'false', timeout: parseInt(process.env[`${prefix}_TIMEOUT`] ?? '10000', 10), maxRetries: parseInt(process.env[`${prefix}_MAX_RETRIES`] ?? '2', 10), inquiries, }; } function buildInquiryConfig(providerPrefix: string, inquiryPrefix: string): InquiryConfig { return { url: process.env[`${providerPrefix}_${inquiryPrefix}_URL`] ?? '', username: process.env[`${providerPrefix}_${inquiryPrefix}_USERNAME`] ?? '', password: process.env[`${providerPrefix}_${inquiryPrefix}_PASSWORD`] ?? '', apiKey: process.env[`${providerPrefix}_${inquiryPrefix}_API_KEY`] ?? '', authMethod: (process.env[`${providerPrefix}_${inquiryPrefix}_AUTH_METHOD`] ?? 'NONE') as AuthMethod, }; } function inquiryTypeToEnvName(inquiryType: InquiryType): string { const mapping: Record = { [InquiryType.PERSON]: 'PERSON', [InquiryType.REAL_ESTATE]: 'REAL_ESTATE', [InquiryType.SHAHKAR]: 'SHAHKAR', [InquiryType.SHEBA]: 'SHEBA', [InquiryType.POSTAL_CODE]: 'POSTAL_CODE', [InquiryType.LEGAL_PERSON]: 'LEGAL_PERSON', [InquiryType.CAR_PLATE]: 'CAR_PLATE', [InquiryType.POLICY_BY_CHASSIS]: 'POLICY_BY_CHASSIS', [InquiryType.POLICY_BY_PLATE]: 'POLICY_BY_PLATE', [InquiryType.POLICY_BY_NATIONAL_CODE]: 'POLICY_BY_NATIONAL_CODE', }; return mapping[inquiryType]; } function buildInquiryRoutingConfig( prefix: string, defaultProvider: ProviderName, fallbackProviders: ProviderName[], ): InquiryRoutingConfig { return { defaultProvider: (process.env[`${prefix}_DEFAULT_PROVIDER`] ?? defaultProvider) as ProviderName, fallbackEnabled: parseBoolean(process.env[`${prefix}_FALLBACK_ENABLED`], false), fallbackProviders: parseProviderList( process.env[`${prefix}_FALLBACK_PROVIDERS`] ?? fallbackProviders.join(','), ), }; } function parseProviderList(value: string): ProviderName[] { if (!value.trim()) return []; return value.split(',').map((p) => p.trim() as ProviderName); } function parseBoolean(value: string | undefined, defaultValue: boolean): boolean { if (value === undefined) return defaultValue; return value.toLowerCase() === 'true'; } // Made with Bob