main #2

Open
julap wants to merge 7 commits from main into notifications
2 changed files with 184 additions and 268 deletions
Showing only changes of commit 3883e5ef20 - Show all commits

View File

@ -14,16 +14,8 @@ const gradient = require('gradient-string');
const https = require('https');
const http = require('http');
// Configuration URLs - can be updated as needed
const ENV_CONFIG_URLS = {
internal: 'https://raw.githubusercontent.com/corradaf/env-configs/main/internal.env'
};
// Internal access token for secure env access
const INTERNAL_ACCESS_TOKEN = 'corrad_internal_2024_secure_token_af';
// Function to fetch content from URL with security
function fetchFromUrl(url, token = null) {
// Function to fetch content from URL
function fetchFromUrl(url) {
return new Promise((resolve, reject) => {
const client = url.startsWith('https') ? https : http;
@ -32,15 +24,9 @@ function fetchFromUrl(url, token = null) {
hostname: urlObj.hostname,
port: urlObj.port,
path: urlObj.pathname + urlObj.search,
method: 'GET',
headers: {}
method: 'GET'
};
if (token) {
options.headers['Authorization'] = `Bearer ${token}`;
options.headers['X-Access-Token'] = token;
}
const req = client.request(options, (res) => {
let data = '';
@ -122,6 +108,30 @@ function createProgressBar(message, duration = 3000) {
});
}
// Clear screen and display ASCII art
function displayHeader() {
clearScreen();
// Show ASCII "CORRAD AF" with gradient
const asciiText = figlet.textSync('CORRAD AF', {
font: 'Big',
horizontalLayout: 'default',
verticalLayout: 'default'
});
console.log(gradient.rainbow(asciiText));
console.log(boxen(
chalk.white.bold('🚀 Welcome to CORRAD Application Framework CLI\n') +
chalk.gray('The fastest way to bootstrap your next project'),
{
padding: 1,
margin: 1,
borderStyle: 'round',
borderColor: 'cyan'
}
));
}
// Clear screen and position cursor at top
function clearScreen() {
console.clear();
@ -163,73 +173,59 @@ function extractComment(line) {
return commentMatch ? commentMatch[1].trim() : '';
}
// Prompt for environment configurations
async function promptForEnvConfig(envVars, projectName) {
const envConfig = {};
console.log(chalk.cyan.bold('\n⚙ Environment Configuration'));
console.log(chalk.gray('Configure your project environment variables:\n'));
for (const envVar of envVars) {
let message = `${envVar.key}`;
if (envVar.description) {
message += chalk.gray(` (${envVar.description})`);
}
let defaultValue = envVar.defaultValue;
// Replace placeholder values
if (defaultValue.includes('${projectName}') || defaultValue.includes('your-project')) {
defaultValue = defaultValue.replace(/\${projectName}|your-project/g, projectName);
}
const { value } = await inquirer.prompt([
{
type: 'input',
name: 'value',
message: message + ':',
default: defaultValue,
validate: function(input) {
if (envVar.key.includes('SECRET') || envVar.key.includes('PASSWORD')) {
if (input.trim().length < 8) {
return 'Security values should be at least 8 characters long';
}
}
return true;
}
}
]);
envConfig[envVar.key] = value;
// Create default .env.example file if it doesn't exist
function createDefaultEnvExample() {
const defaultEnvContent = `# Database Configuration
DATABASE_URL="mysql://username:password@localhost:3306/database_name" # Your MySQL connection string
# Authentication
JWT_SECRET="your-super-secret-jwt-key-change-this-in-production" # Secret key for JWT tokens
AUTH_ORIGIN="http://localhost:3000" # Allowed origin for authentication
# Application
NUXT_SECRET_KEY="your-nuxt-secret-key-for-session-encryption" # Nuxt secret key
APP_NAME="Your Application Name" # Your application name
APP_URL="http://localhost:3000" # Your application URL
# Email Configuration (Optional)
MAIL_HOST="smtp.example.com" # SMTP server host
MAIL_PORT="587" # SMTP server port
MAIL_USERNAME="your-email@example.com" # SMTP username
MAIL_PASSWORD="your-email-password" # SMTP password
MAIL_FROM_ADDRESS="noreply@yourapp.com" # From email address
MAIL_FROM_NAME="Your App Name" # From name
# Development
NODE_ENV="development" # Environment (development, production)
NUXT_HOST="localhost" # Nuxt host
NUXT_PORT="3000" # Nuxt port
`;
fs.writeFileSync('.env.example', defaultEnvContent);
return defaultEnvContent;
}
// Check if environment is properly configured
function isEnvConfigured() {
if (!fs.existsSync('.env')) {
return false;
}
return envConfig;
const envContent = fs.readFileSync('.env', 'utf-8');
// Check if DATABASE_URL is properly set (not empty or default)
const dbUrlMatch = envContent.match(/DATABASE_URL\s*=\s*["'](.+?)["']/);
if (!dbUrlMatch) return false;
const dbUrl = dbUrlMatch[1];
return dbUrl && !dbUrl.includes('username:password');
}
// Main CLI function
async function main() {
try {
// Clear console and show welcome screen (only once)
clearScreen();
// Step 1: Show ASCII "CORRAD AF" with gradient (only once)
const asciiText = figlet.textSync('CORRAD AF', {
font: 'Big',
horizontalLayout: 'default',
verticalLayout: 'default'
});
console.log(gradient.rainbow(asciiText));
console.log(boxen(
chalk.white.bold('🚀 Welcome to CORRAD Application Framework CLI\n') +
chalk.gray('The fastest way to bootstrap your next project'),
{
padding: 1,
margin: 1,
borderStyle: 'round',
borderColor: 'cyan'
}
));
// Show the header once at the beginning
displayHeader();
// Check for existing project files
const hasFiles = hasProjectFiles();
@ -264,18 +260,8 @@ async function main() {
process.exit(0);
}
// Clear screen and show project name prompt
clearScreen();
console.log(boxen(
chalk.white.bold('🚀 CORRAD Application Framework CLI\n') +
chalk.gray('The fastest way to bootstrap your next project'),
{
padding: 1,
margin: 1,
borderStyle: 'round',
borderColor: 'cyan'
}
));
// Display header again for consistency
displayHeader();
// Get project name (only for new projects)
let projectName = path.basename(process.cwd());
@ -302,94 +288,32 @@ async function main() {
projectName = inputProjectName;
}
// Clear screen and show project type selection
clearScreen();
console.log(boxen(
chalk.white.bold('🚀 CORRAD Application Framework CLI\n') +
chalk.gray('The fastest way to bootstrap your next project'),
{
padding: 1,
margin: 1,
borderStyle: 'round',
borderColor: 'cyan'
}
));
// Display header again for consistency
displayHeader();
// Step 3: Ask if public or internal project
console.log(chalk.cyan.bold('\n🔐 Project Type'));
const { projectType } = await inquirer.prompt([
// Step 3: Ask about environment setup
console.log(chalk.cyan.bold('\n🔐 Environment Setup'));
const { envSetupType } = await inquirer.prompt([
{
type: 'list',
name: 'projectType',
message: 'Is this a public or internal project?',
name: 'envSetupType',
message: 'How would you like to set up your environment?',
choices: [
{
name: chalk.green('🌍 Public') + chalk.gray(' - Configure environment manually'),
value: 'public'
name: chalk.green('🔧 Manual Setup') + chalk.gray(' - Configure environment later'),
value: 'manual'
},
{
name: chalk.red('🔒 Internal') + chalk.gray(' - Use company configuration'),
value: 'internal'
name: chalk.blue('🔗 Import from URL') + chalk.gray(' - Paste a configuration URL'),
value: 'url'
}
],
default: 0
}
]);
let isInternal = false;
let useCompanyEnv = false;
if (projectType === 'internal') {
isInternal = true;
// Clear screen and show password prompt
clearScreen();
console.log(boxen(
chalk.white.bold('🚀 CORRAD Application Framework CLI\n') +
chalk.gray('The fastest way to bootstrap your next project'),
{
padding: 1,
margin: 1,
borderStyle: 'round',
borderColor: 'cyan'
}
));
// Password verification for internal projects
console.log(chalk.yellow('\n🔒 Internal project detected - Password verification required'));
const { password } = await inquirer.prompt([
{
type: 'password',
name: 'password',
message: 'Enter company password:',
mask: '*'
}
]);
if (password !== 'Rahsia@123456') {
console.log(chalk.red('❌ Incorrect password. Access denied.'));
process.exit(1);
}
console.log(chalk.green('✓ Password verified. Access granted.'));
useCompanyEnv = true;
} else {
console.log(chalk.green('✓ Public project setup selected.'));
}
// Clear screen and show development tools prompt
clearScreen();
console.log(boxen(
chalk.white.bold('🚀 CORRAD Application Framework CLI\n') +
chalk.gray('The fastest way to bootstrap your next project'),
{
padding: 1,
margin: 1,
borderStyle: 'round',
borderColor: 'cyan'
}
));
// Display header again for consistency
displayHeader();
// Step 4: Ask about Cursor rules
console.log(chalk.cyan.bold('\n⚙ Development Tools'));
@ -406,18 +330,8 @@ async function main() {
}
]);
// Clear screen and show setup progress
clearScreen();
console.log(boxen(
chalk.white.bold('🚀 CORRAD Application Framework CLI\n') +
chalk.gray('The fastest way to bootstrap your next project'),
{
padding: 1,
margin: 1,
borderStyle: 'round',
borderColor: 'cyan'
}
));
// Display header again for consistency
displayHeader();
// Step 5: Show loading screen and setup project
console.log(chalk.cyan.bold('\n🚀 Setting up your project...'));
@ -467,75 +381,83 @@ async function main() {
}
// Setup environment file
if (useCompanyEnv && isInternal) {
const envSpinner = ora('Setting up company environment...').start();
if (envSetupType === 'url') {
// Display header for consistency
displayHeader();
const { envUrl } = await inquirer.prompt([
{
type: 'input',
name: 'envUrl',
message: 'Enter the URL for your environment configuration:',
validate: function(input) {
if (!input.trim() || !input.startsWith('http')) {
return 'Please enter a valid URL (starting with http:// or https://)';
}
return true;
}
}
]);
const envSpinner = ora('Fetching environment configuration from URL...').start();
try {
// Fetch .env content from secure URL
const envContent = await fetchFromUrl(ENV_CONFIG_URLS.internal, INTERNAL_ACCESS_TOKEN);
// Fetch .env content from provided URL
const envContent = await fetchFromUrl(envUrl);
const processedContent = envContent.replace(/\${projectName}/g, projectName);
fs.writeFileSync('.env', processedContent);
envSpinner.succeed('Company environment configured');
envSpinner.succeed('Environment configuration imported successfully');
// Run Prisma commands if the env is properly configured
if (isEnvConfigured()) {
const prismaSpinner = ora('Setting up Prisma database...').start();
if (fs.existsSync('prisma/schema.prisma')) {
const prismaSuccess = runCommand('npx prisma generate', { stdio: 'pipe' });
if (prismaSuccess) {
prismaSpinner.succeed('Prisma database configured');
} else {
prismaSpinner.fail('Prisma setup failed - please check your DATABASE_URL');
}
} else {
prismaSpinner.warn('No Prisma schema found - skipping database setup');
}
}
} catch (error) {
envSpinner.fail('Failed to fetch company environment config');
console.log(chalk.yellow('⚠️ Unable to access secure company environment.'));
console.log(chalk.gray('Please contact your system administrator for access.'));
process.exit(1);
envSpinner.fail('Failed to fetch environment configuration');
console.log(chalk.yellow(`⚠️ Unable to access URL: ${error.message}`));
console.log(chalk.gray('Creating a basic .env file you can edit later...'));
// Create basic .env file from .env.example
try {
let exampleContent;
if (fs.existsSync('.env.example')) {
exampleContent = fs.readFileSync('.env.example', 'utf8');
} else {
exampleContent = createDefaultEnvExample();
}
fs.copyFileSync('.env.example', '.env');
console.log(chalk.green('✓ Basic environment file created'));
console.log(chalk.yellow('⚠️ Please edit the .env file and configure your DATABASE_URL before running Prisma commands'));
} catch (error) {
console.log(chalk.red(`Error creating .env file: ${error.message}`));
}
}
} else {
// Create environment file based on .env.example
const envSpinner = ora('Setting up environment configuration...').start();
// Manual environment setup
const envSpinner = ora('Setting up environment files...').start();
try {
if (fs.existsSync('.env.example')) {
const exampleContent = fs.readFileSync('.env.example', 'utf8');
const envVars = parseEnvExample(exampleContent);
envSpinner.succeed('Environment template loaded');
// Clear screen for env configuration
clearScreen();
console.log(boxen(
chalk.white.bold('🚀 CORRAD Application Framework CLI\n') +
chalk.gray('The fastest way to bootstrap your next project'),
{
padding: 1,
margin: 1,
borderStyle: 'round',
borderColor: 'cyan'
}
));
// Prompt for each environment variable
const envConfig = await promptForEnvConfig(envVars, projectName);
// Generate .env file
let envContent = '';
for (const [key, value] of Object.entries(envConfig)) {
envContent += `${key}="${value}"\n`;
}
fs.writeFileSync('.env', envContent);
console.log(chalk.green('✓ Environment file created'));
} else {
envSpinner.warn('No .env.example found - creating basic environment');
// Fallback to basic template
const fallbackEnv = `# Basic Environment Configuration
DATABASE_URL="postgresql://username:password@localhost:5432/database_name"
JWT_SECRET="your-super-secret-jwt-key"
AUTH_ORIGIN="http://localhost:3000"
NUXT_SECRET_KEY="your-nuxt-secret-key"
APP_NAME="${projectName}"
APP_URL="http://localhost:3000"
NODE_ENV="development"
NUXT_HOST="localhost"
NUXT_PORT="3000"
`;
fs.writeFileSync('.env', fallbackEnv);
console.log(chalk.green('✓ Basic environment created'));
// Create or ensure .env.example exists
if (!fs.existsSync('.env.example')) {
createDefaultEnvExample();
}
// Copy .env.example to .env without filling in values
fs.copyFileSync('.env.example', '.env');
envSpinner.succeed('Environment files created');
console.log(chalk.green('✓ Created .env file from .env.example'));
console.log(chalk.yellow('⚠️ Please edit the .env file and configure your DATABASE_URL before running Prisma commands'));
} catch (error) {
envSpinner.fail('Failed to set up environment');
console.log(chalk.red(`Error: ${error.message}`));
@ -640,43 +562,37 @@ Security:
yarnSpinner.succeed('Dependencies installed with Yarn');
}
// Setup Prisma
const prismaSpinner = ora('Setting up Prisma database...').start();
try {
// Check if Prisma is available and generate client
if (fs.existsSync('prisma/schema.prisma')) {
const prismaSuccess = runCommand('npx prisma generate', { stdio: 'pipe' });
if (prismaSuccess) {
prismaSpinner.succeed('Prisma database configured');
} else {
prismaSpinner.warn('Prisma setup incomplete - configure manually if needed');
}
} else {
prismaSpinner.warn('No Prisma schema found - skipping database setup');
}
} catch (error) {
prismaSpinner.warn('Prisma setup skipped');
}
// Display header again for consistency at the end
displayHeader();
// Step 6: Success message and next steps
const prismaNotes = isEnvConfigured() ?
'' :
chalk.yellow('\n⚠ Important: Edit your .env file and configure your DATABASE_URL before running:\n') +
chalk.gray(' npx prisma generate\n');
const nextSteps = setupAction === 'new' ? [
` cd ${projectName}`,
' git init # Initialize git repository',
' yarn dev # Start development server',
' yarn build # Build for production',
' yarn start # Start production server'
' git init # Initialize git repository',
' # Edit your .env file with proper configuration',
' npx prisma generate # Generate Prisma client after configuring DATABASE_URL',
' yarn dev # Start development server',
' yarn build # Build for production',
' yarn start # Start production server'
] : [
' yarn dev # Start development server',
' yarn build # Build for production',
' yarn start # Start production server'
' # Edit your .env file with proper configuration',
' npx prisma generate # Generate Prisma client after configuring DATABASE_URL',
' yarn dev # Start development server',
' yarn build # Build for production',
' yarn start # Start production server'
];
console.log('\n' + boxen(
chalk.green.bold('🎉 Project setup completed successfully!\n\n') +
chalk.white(`Project: ${chalk.cyan.bold(projectName)}\n`) +
chalk.white(`Type: ${chalk.yellow.bold(projectType)}\n`) +
chalk.white(`Action: ${chalk.yellow.bold(setupAction === 'new' ? 'New Project' : 'Updated Existing')}\n`) +
chalk.white(`Location: ${chalk.gray(process.cwd())}\n\n`) +
chalk.white(`Location: ${chalk.gray(process.cwd())}\n`) +
prismaNotes +
chalk.white.bold('Next steps:\n') +
nextSteps.map(step => chalk.gray(step)).join('\n'),
{

View File

@ -1,6 +1,6 @@
{
"name": "corradaf",
"version": "1.0.0",
"version": "1.0.2",
"description": "CLI tool to quickly set up CORRAD Application Framework projects",
"main": "index.js",
"bin": {
@ -19,12 +19,12 @@
"template"
],
"dependencies": {
"figlet": "^1.7.0",
"ora": "^5.4.1",
"inquirer": "^8.2.6",
"chalk": "^4.1.2",
"boxen": "^5.1.2",
"gradient-string": "^2.0.2"
"chalk": "^4.1.2",
"figlet": "^1.8.1",
"gradient-string": "^2.0.2",
"inquirer": "^8.2.6",
"ora": "^5.4.1"
},
"author": "Corrad Team",
"license": "MIT",
@ -36,4 +36,4 @@
"engines": {
"node": ">=14.0.0"
}
}
}