/home/techb158/cosmic.abdallabala.com/src/config
Edit: /home/techb158/cosmic.abdallabala.com/src/config/runtimeConfig.js (4129B)
const path = require("path");
function boolFromEnv(value, fallback = false) {
if (value === undefined || value === null || value === "") return fallback;
return ["1", "true", "yes", "on"].includes(String(value).toLowerCase());
}
function splitCsv(value) {
if (!value) return [];
return String(value).split(",").map(item => item.trim()).filter(Boolean);
}
function getRuntimeConfig(env = process.env, rootDir = process.cwd()) {
const nodeEnv = env.NODE_ENV || "development";
const production = nodeEnv === "production";
const port = Number(env.PORT || 8090);
const databaseFile = env.COSMIC_DB_FILE || path.join(rootDir, "data", "database.json");
const backupDir = env.COSMIC_BACKUP_DIR || path.join(rootDir, "backups");
const allowedOrigins = splitCsv(env.COSMIC_ALLOWED_ORIGINS || "");
const frameAncestors = splitCsv(env.COSMIC_FRAME_ANCESTORS || "'self'");
return {
appName: "cosmic-ai-risk-dashboard",
version: "2.0.0",
nodeEnv,
production,
port,
rootDir,
publicDir: path.join(rootDir, "public"),
legacyDataFile: path.join(rootDir, "data", "sample-project.json"),
databaseFile,
backupDir,
defaultProjectId: env.COSMIC_PROJECT_ID || "cosmic-ai-risk-001",
livePmEnabled: boolFromEnv(env.COSMIC_LIVE_PM_ENABLED, false),
tokenEncryptionConfigured: Boolean(env.COSMIC_TOKEN_ENCRYPTION_KEY && env.COSMIC_TOKEN_ENCRYPTION_KEY.length >= 16),
tokenEncryptionKeyLength: env.COSMIC_TOKEN_ENCRYPTION_KEY ? env.COSMIC_TOKEN_ENCRYPTION_KEY.length : 0,
trustProxy: boolFromEnv(env.COSMIC_TRUST_PROXY, production),
forceHttps: boolFromEnv(env.COSMIC_FORCE_HTTPS, production),
hstsEnabled: boolFromEnv(env.COSMIC_HSTS_ENABLED, production),
securityHeadersEnabled: boolFromEnv(env.COSMIC_SECURITY_HEADERS_ENABLED, true),
maxBodyBytes: Number(env.COSMIC_MAX_BODY_BYTES || 1048576),
allowedOrigins,
frameAncestors,
requestLogEnabled: boolFromEnv(env.COSMIC_REQUEST_LOG_ENABLED, production),
backupRetention: Number(env.COSMIC_BACKUP_RETENTION || 10)
};
}
function validateRuntimeConfig(config) {
const warnings = [];
const errors = [];
if (!Number.isFinite(config.port) || config.port <= 0) {
errors.push("PORT must be a positive number.");
}
if (!config.databaseFile) {
errors.push("COSMIC_DB_FILE is required.");
}
if (config.production && !config.tokenEncryptionConfigured) {
warnings.push("COSMIC_TOKEN_ENCRYPTION_KEY should be set to at least 16 characters before storing OAuth tokens in production.");
}
if (config.livePmEnabled && !config.tokenEncryptionConfigured) {
warnings.push("Live PM integrations are enabled but COSMIC_TOKEN_ENCRYPTION_KEY is not configured. OAuth token storage will be unsafe for production.");
}
if (config.production && !config.hstsEnabled) {
warnings.push("HSTS is disabled in production. Enable COSMIC_HSTS_ENABLED=true behind HTTPS.");
}
if (config.forceHttps && !config.trustProxy) {
warnings.push("COSMIC_FORCE_HTTPS is enabled but COSMIC_TRUST_PROXY is false. HTTPS detection may fail behind a reverse proxy.");
}
if (config.maxBodyBytes > 5 * 1024 * 1024) {
warnings.push("COSMIC_MAX_BODY_BYTES is above 5 MB. Keep API payload limits small unless there is a clear need.");
}
return {
ok: errors.length === 0,
errors,
warnings
};
}
function publicRuntimeSummary(config) {
const validation = validateRuntimeConfig(config);
return {
service: config.appName,
version: config.version,
nodeEnv: config.nodeEnv,
production: config.production,
storage: "json-file",
database: path.basename(config.databaseFile),
livePmEnabled: config.livePmEnabled,
tokenEncryptionConfigured: config.tokenEncryptionConfigured,
securityHeadersEnabled: config.securityHeadersEnabled,
forceHttps: config.forceHttps,
hstsEnabled: config.hstsEnabled,
allowedOrigins: config.allowedOrigins,
frameAncestors: config.frameAncestors,
validation
};
}
module.exports = {
boolFromEnv,
splitCsv,
getRuntimeConfig,
validateRuntimeConfig,
publicRuntimeSummary
};