import dotenv from 'dotenv'; import fs from 'fs'; dotenv.config(); function envOrConfig(envKey, configValue) { const envValue = process.env[envKey]; if (envValue !== undefined && envValue !== '') { return envValue; } return configValue; } function envBool(envKey, defaultValue = false) { const envValue = process.env[envKey]; if (envValue === undefined || envValue === '') { return defaultValue; } return envValue === 'true' || envValue === '1'; } function resolveJiraHost(fileConfig) { const cloudId = envOrConfig('JIRA_CLOUD_ID', fileConfig.jiraCloud?.cloudId)?.trim(); let baseUrl = envOrConfig('JIRA_BASE_URL', fileConfig.jiraCloud?.host || 'https://aeo.atlassian.net')?.trim(); if (cloudId) { return `https://api.atlassian.com/ex/jira/${cloudId}`; } return baseUrl.replace(/\/$/, ''); } export function loadConfig() { const fileConfig = JSON.parse(fs.readFileSync('./config/config.json')); const config = { ...fileConfig, logLevel: envOrConfig('LOG_LEVEL', fileConfig.logLevel), server: { ...fileConfig.server, port: envOrConfig('PORT', fileConfig.server?.port), name: envOrConfig('SERVER_NAME', fileConfig.server?.name), }, webex: { ...fileConfig.webex, token: envOrConfig('WEBEX_TOKEN', fileConfig.webex?.token), webhookSecret: envOrConfig('WEBEX_WEBHOOK_SECRET', fileConfig.webex?.webhookSecret), webhookTargetUrl: envOrConfig( 'WEBEX_WEBHOOK_TARGET_URL', fileConfig.webex?.webhookTargetUrl || 'https://bot.joesjavajoint.com/jiracloud/webex/messages' ), inboundEnabled: envBool('WEBEX_INBOUND_ENABLED', false), inboundDryRun: envBool('WEBEX_INBOUND_DRY_RUN', true), botPersonId: envOrConfig('WEBEX_BOT_PERSON_ID', fileConfig.webex?.botPersonId), integration: { clientId: envOrConfig('WEBEX_INTEGRATION_CLIENT_ID', fileConfig.webex?.integration?.clientId), clientSecret: envOrConfig('WEBEX_INTEGRATION_CLIENT_SECRET', fileConfig.webex?.integration?.clientSecret), redirectUri: envOrConfig( 'WEBEX_INTEGRATION_REDIRECT_URI', fileConfig.webex?.integration?.redirectUri || 'https://bot.joesjavajoint.com/jiracloud/webex/oauth/callback' ), scopes: envOrConfig( 'WEBEX_INTEGRATION_SCOPES', fileConfig.webex?.integration?.scopes || 'spark:messages_read spark:webhooks_read spark:webhooks_write' ), tokenFile: envOrConfig( 'WEBEX_OAUTH_TOKEN_FILE', fileConfig.webex?.integration?.tokenFile || './config/webex-oauth.json' ), }, room: { ...fileConfig.webex?.room, id: envOrConfig('WEBEX_ROOM_ID', fileConfig.webex?.room?.id), }, }, jiraNotifier: { ...fileConfig.jiraNotifier, token: envOrConfig('JIRA_NOTIFIER_TOKEN', fileConfig.jiraNotifier?.token), }, jiraCloud: { ...fileConfig.jiraCloud, cloudId: envOrConfig('JIRA_CLOUD_ID', fileConfig.jiraCloud?.cloudId) || null, host: resolveJiraHost(fileConfig), siteUrl: (envOrConfig('JIRA_BASE_URL', fileConfig.jiraCloud?.host || 'https://aeo.atlassian.net') || '').replace(/\/$/, ''), authType: (envOrConfig('JIRA_AUTH_TYPE', fileConfig.jiraCloud?.authType) || 'basic').toLowerCase(), email: envOrConfig('JIRA_EMAIL', fileConfig.jiraCloud?.email), token: envOrConfig('JIRA_API_TOKEN', fileConfig.jiraCloud?.token), }, rooms: { approval: envOrConfig( 'APPROVAL_ROOM_ID', fileConfig.rooms?.approval || 'Y2lzY29zcGFyazovL3VzL1JPT00vZWQ4ZWY3OTAtMGE5NC0xMWVjLWExZDUtM2I5ZWNlNWFlNDI5' ), support: envOrConfig( 'SUPPORT_ROOM_ID', fileConfig.rooms?.support || 'Y2lzY29zcGFyazovL3VzL1JPT00vZWY4MmExNjAtNzYzNS0xMWU4LWFlYWMtNjNjMGMyMTExYTVm' ), }, }; return config; } export function loadRequests() { return JSON.parse(fs.readFileSync('./config/requests.json')); } export function loadWebexRooms() { const roomsPath = './config/webexRooms.json'; if (!fs.existsSync(roomsPath)) { return {}; } return JSON.parse(fs.readFileSync(roomsPath)); } export function findWebexRoomById(webexRooms, roomId) { if (!roomId || !webexRooms) { return null; } for (const [configKey, room] of Object.entries(webexRooms)) { if (room.roomId === roomId && room.enabled !== false) { return { configKey, ...room }; } } return null; } export function getMissingSecrets(config) { const missing = []; if (!config.jiraCloud?.email) missing.push('JIRA_EMAIL'); if (!config.jiraCloud?.token) missing.push('JIRA_API_TOKEN'); if (!config.webex?.token) missing.push('WEBEX_TOKEN'); if (!config.jiraNotifier?.token) missing.push('JIRA_NOTIFIER_TOKEN'); return missing; } export function describeJiraIdentity(config) { const email = config.jiraCloud?.email || '(not set)'; const host = config.jiraCloud?.host || '(not set)'; const authType = config.jiraCloud?.authType || 'basic'; const viaCloudId = config.jiraCloud?.cloudId ? `cloudId=${config.jiraCloud.cloudId}` : 'site URL'; return `${email} (${authType}, ${viaCloudId}) → ${host}`; }