import * as plugins from './mod.plugins.js'; import * as helpers from './helpers.js'; import { logger } from '../gitzone.logging.js'; export interface IServiceConfig { PROJECT_NAME: string; MONGODB_HOST: string; MONGODB_NAME: string; MONGODB_PORT: string; MONGODB_USER: string; MONGODB_PASS: string; MONGODB_URL: string; S3_HOST: string; S3_PORT: string; S3_CONSOLE_PORT: string; S3_ACCESSKEY: string; S3_SECRETKEY: string; S3_BUCKET: string; S3_ENDPOINT: string; } export class ServiceConfiguration { private configPath: string; private config: IServiceConfig; constructor() { this.configPath = plugins.path.join(process.cwd(), '.nogit', 'env.json'); } /** * Load or create the configuration */ public async loadOrCreate(): Promise { await this.ensureNogitDirectory(); if (await this.configExists()) { await this.loadConfig(); await this.updateMissingFields(); } else { await this.createDefaultConfig(); } return this.config; } /** * Get the current configuration */ public getConfig(): IServiceConfig { return this.config; } /** * Save the configuration to file */ public async saveConfig(): Promise { await plugins.smartfile.memory.toFs( JSON.stringify(this.config, null, 2), this.configPath ); } /** * Ensure .nogit directory exists */ private async ensureNogitDirectory(): Promise { const nogitPath = plugins.path.join(process.cwd(), '.nogit'); await plugins.smartfile.fs.ensureDir(nogitPath); } /** * Check if configuration file exists */ private async configExists(): Promise { return plugins.smartfile.fs.fileExists(this.configPath); } /** * Load configuration from file */ private async loadConfig(): Promise { const configContent = await plugins.smartfile.fs.toStringSync(this.configPath); this.config = JSON.parse(configContent); } /** * Create default configuration */ private async createDefaultConfig(): Promise { const projectName = helpers.getProjectName(); const mongoPort = await helpers.getRandomAvailablePort(); const s3Port = await helpers.getRandomAvailablePort(); let s3ConsolePort = s3Port + 1; // Ensure console port is also available while (!(await helpers.isPortAvailable(s3ConsolePort))) { s3ConsolePort++; } const mongoUser = 'defaultadmin'; const mongoPass = 'defaultpass'; const mongoHost = 'localhost'; const mongoName = projectName; const mongoPortStr = mongoPort.toString(); const s3Host = 'localhost'; const s3PortStr = s3Port.toString(); this.config = { PROJECT_NAME: projectName, MONGODB_HOST: mongoHost, MONGODB_NAME: mongoName, MONGODB_PORT: mongoPortStr, MONGODB_USER: mongoUser, MONGODB_PASS: mongoPass, MONGODB_URL: `mongodb://${mongoUser}:${mongoPass}@${mongoHost}:${mongoPortStr}/${mongoName}?authSource=admin`, S3_HOST: s3Host, S3_PORT: s3PortStr, S3_CONSOLE_PORT: s3ConsolePort.toString(), S3_ACCESSKEY: 'defaultadmin', S3_SECRETKEY: 'defaultpass', S3_BUCKET: `${projectName}-documents`, S3_ENDPOINT: `http://${s3Host}:${s3PortStr}` }; await this.saveConfig(); logger.log('ok', '✅ Created .nogit/env.json with project defaults'); logger.log('info', `📍 MongoDB port: ${mongoPort}`); logger.log('info', `📍 S3 API port: ${s3Port}`); logger.log('info', `📍 S3 Console port: ${s3ConsolePort}`); } /** * Update missing fields in existing configuration */ private async updateMissingFields(): Promise { const projectName = helpers.getProjectName(); let updated = false; const fieldsAdded: string[] = []; // Check and add missing fields if (!this.config.PROJECT_NAME) { this.config.PROJECT_NAME = projectName; fieldsAdded.push('PROJECT_NAME'); updated = true; } if (!this.config.MONGODB_HOST) { this.config.MONGODB_HOST = 'localhost'; fieldsAdded.push('MONGODB_HOST'); updated = true; } if (!this.config.MONGODB_NAME) { this.config.MONGODB_NAME = projectName; fieldsAdded.push('MONGODB_NAME'); updated = true; } if (!this.config.MONGODB_PORT) { const port = await helpers.getRandomAvailablePort(); this.config.MONGODB_PORT = port.toString(); fieldsAdded.push(`MONGODB_PORT(${port})`); updated = true; } if (!this.config.MONGODB_USER) { this.config.MONGODB_USER = 'defaultadmin'; fieldsAdded.push('MONGODB_USER'); updated = true; } if (!this.config.MONGODB_PASS) { this.config.MONGODB_PASS = 'defaultpass'; fieldsAdded.push('MONGODB_PASS'); updated = true; } // Always update MONGODB_URL based on current settings const oldUrl = this.config.MONGODB_URL; this.config.MONGODB_URL = `mongodb://${this.config.MONGODB_USER}:${this.config.MONGODB_PASS}@${this.config.MONGODB_HOST}:${this.config.MONGODB_PORT}/${this.config.MONGODB_NAME}?authSource=admin`; if (oldUrl !== this.config.MONGODB_URL) { fieldsAdded.push('MONGODB_URL'); updated = true; } if (!this.config.S3_HOST) { this.config.S3_HOST = 'localhost'; fieldsAdded.push('S3_HOST'); updated = true; } if (!this.config.S3_PORT) { const port = await helpers.getRandomAvailablePort(); this.config.S3_PORT = port.toString(); fieldsAdded.push(`S3_PORT(${port})`); updated = true; } if (!this.config.S3_CONSOLE_PORT) { const s3Port = parseInt(this.config.S3_PORT); let consolePort = s3Port + 1; while (!(await helpers.isPortAvailable(consolePort))) { consolePort++; } this.config.S3_CONSOLE_PORT = consolePort.toString(); fieldsAdded.push(`S3_CONSOLE_PORT(${consolePort})`); updated = true; } if (!this.config.S3_ACCESSKEY) { this.config.S3_ACCESSKEY = 'defaultadmin'; fieldsAdded.push('S3_ACCESSKEY'); updated = true; } if (!this.config.S3_SECRETKEY) { this.config.S3_SECRETKEY = 'defaultpass'; fieldsAdded.push('S3_SECRETKEY'); updated = true; } if (!this.config.S3_BUCKET) { this.config.S3_BUCKET = `${projectName}-documents`; fieldsAdded.push('S3_BUCKET'); updated = true; } // Always update S3_ENDPOINT based on current settings const oldEndpoint = this.config.S3_ENDPOINT; this.config.S3_ENDPOINT = `http://${this.config.S3_HOST}:${this.config.S3_PORT}`; if (oldEndpoint !== this.config.S3_ENDPOINT) { fieldsAdded.push('S3_ENDPOINT'); updated = true; } if (updated) { await this.saveConfig(); logger.log('ok', `✅ Added missing fields: ${fieldsAdded.join(', ')}`); } else { logger.log('ok', '✅ Configuration complete'); } } /** * Get MongoDB connection string */ public getMongoConnectionString(useNetworkIp: boolean = false): string { const host = useNetworkIp ? '${networkIp}' : this.config.MONGODB_HOST; return `mongodb://${this.config.MONGODB_USER}:${this.config.MONGODB_PASS}@${host}:${this.config.MONGODB_PORT}/${this.config.MONGODB_NAME}?authSource=admin`; } /** * Get container names */ public getContainerNames() { return { mongo: `${this.config.PROJECT_NAME}-mongodb`, minio: `${this.config.PROJECT_NAME}-minio` }; } /** * Get data directories */ public getDataDirectories() { return { mongo: plugins.path.join(process.cwd(), '.nogit', 'mongodata'), minio: plugins.path.join(process.cwd(), '.nogit', 'miniodata') }; } }