175 lines
4.4 KiB
TypeScript
175 lines
4.4 KiB
TypeScript
#!/usr/bin/env bun
|
|
/* eslint-disable no-console */
|
|
import { join } from 'path';
|
|
import { parseArgs } from 'util';
|
|
import { redactSecrets } from './utils/secrets';
|
|
import {
|
|
checkRequiredEnvVars,
|
|
formatValidationResult,
|
|
validateCompleteness,
|
|
validateConfig,
|
|
} from './utils/validation';
|
|
import { ConfigManager } from './config-manager';
|
|
import { baseAppSchema } from './schemas';
|
|
import type { Environment } from './types';
|
|
|
|
interface CliOptions {
|
|
config?: string;
|
|
env?: string;
|
|
validate?: boolean;
|
|
show?: boolean;
|
|
check?: boolean;
|
|
json?: boolean;
|
|
help?: boolean;
|
|
}
|
|
|
|
const REQUIRED_PATHS = [
|
|
'service.name',
|
|
'service.port',
|
|
'database.postgres.host',
|
|
'database.postgres.database',
|
|
];
|
|
|
|
const REQUIRED_ENV_VARS = ['NODE_ENV'];
|
|
|
|
const SECRET_PATHS = [
|
|
'database.postgres.password',
|
|
'database.mongodb.uri',
|
|
'providers.quoteMedia.apiKey',
|
|
'providers.interactiveBrokers.clientId',
|
|
];
|
|
|
|
function printUsage() {
|
|
console.log(`
|
|
Stock Bot Configuration CLI
|
|
|
|
Usage: bun run config-cli [options]
|
|
|
|
Options:
|
|
--config <path> Path to config directory (default: ./config)
|
|
--env <env> Environment to use (development, test, production)
|
|
--validate Validate configuration against schema
|
|
--show Show current configuration (secrets redacted)
|
|
--check Run all configuration checks
|
|
--json Output in JSON format
|
|
--help Show this help message
|
|
|
|
Examples:
|
|
# Validate configuration
|
|
bun run config-cli --validate
|
|
|
|
# Show configuration for production
|
|
bun run config-cli --env production --show
|
|
|
|
# Run all checks
|
|
bun run config-cli --check
|
|
|
|
# Output configuration as JSON
|
|
bun run config-cli --show --json
|
|
`);
|
|
}
|
|
|
|
async function main() {
|
|
const { values } = parseArgs({
|
|
args: process.argv.slice(2),
|
|
options: {
|
|
config: { type: 'string' },
|
|
env: { type: 'string' },
|
|
validate: { type: 'boolean' },
|
|
show: { type: 'boolean' },
|
|
check: { type: 'boolean' },
|
|
json: { type: 'boolean' },
|
|
help: { type: 'boolean' },
|
|
},
|
|
}) as { values: CliOptions };
|
|
|
|
if (values.help) {
|
|
printUsage();
|
|
process.exit(0);
|
|
}
|
|
|
|
const configPath = values.config || join(process.cwd(), 'config');
|
|
const environment = values.env as Environment;
|
|
|
|
try {
|
|
const manager = new ConfigManager({
|
|
configPath,
|
|
environment,
|
|
});
|
|
|
|
const config = await manager.initialize(baseAppSchema);
|
|
|
|
if (values.validate) {
|
|
const result = validateConfig(config, baseAppSchema);
|
|
|
|
if (values.json) {
|
|
console.log(JSON.stringify(result, null, 2));
|
|
} else {
|
|
console.log(formatValidationResult(result));
|
|
}
|
|
|
|
process.exit(result.valid ? 0 : 1);
|
|
}
|
|
|
|
if (values.show) {
|
|
const redacted = redactSecrets(config, SECRET_PATHS);
|
|
|
|
if (values.json) {
|
|
console.log(JSON.stringify(redacted, null, 2));
|
|
} else {
|
|
console.log('Current Configuration:');
|
|
console.log(JSON.stringify(redacted, null, 2));
|
|
}
|
|
}
|
|
|
|
if (values.check) {
|
|
console.log('Running configuration checks...\n');
|
|
|
|
// Schema validation
|
|
console.log('1. Schema Validation:');
|
|
const schemaResult = validateConfig(config, baseAppSchema);
|
|
console.log(formatValidationResult(schemaResult));
|
|
console.log();
|
|
|
|
// Environment variables
|
|
console.log('2. Required Environment Variables:');
|
|
const envResult = checkRequiredEnvVars(REQUIRED_ENV_VARS);
|
|
console.log(formatValidationResult(envResult));
|
|
console.log();
|
|
|
|
// Required paths
|
|
console.log('3. Required Configuration Paths:');
|
|
const pathResult = validateCompleteness(config, REQUIRED_PATHS);
|
|
console.log(formatValidationResult(pathResult));
|
|
console.log();
|
|
|
|
// Overall result
|
|
const allValid = schemaResult.valid && envResult.valid && pathResult.valid;
|
|
|
|
if (allValid) {
|
|
console.log('✅ All configuration checks passed!');
|
|
process.exit(0);
|
|
} else {
|
|
console.log('❌ Some configuration checks failed');
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
if (!values.validate && !values.show && !values.check) {
|
|
console.log('No action specified. Use --help for usage information.');
|
|
process.exit(1);
|
|
}
|
|
} catch (error) {
|
|
if (values.json) {
|
|
console.error(JSON.stringify({ error: String(error) }));
|
|
} else {
|
|
console.error('Error:', error);
|
|
}
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
// Run CLI
|
|
if (import.meta.main) {
|
|
main();
|
|
}
|