codalware-auth
Version:
Complete authentication system with enterprise security, attack protection, team workspaces, waitlist, billing, UI components, 2FA, and account recovery - production-ready in 5 minutes. Enhanced CLI with verification, rollback, and App Router scaffolding.
157 lines (131 loc) • 4.89 kB
JavaScript
/**
* Rollback AuthCore Scaffold
* Removes files created by `npx authcore init`
*
* Usage:
* node scripts/undo-scaffold-auth.js
* node scripts/undo-scaffold-auth.js --dry-run
*/
const fs = require('fs');
const path = require('path');
const DRY_RUN = process.argv.includes('--dry-run');
const MANIFEST_PATH = path.join(process.cwd(), '.scaffold-auth', 'manifest.json');
const colors = {
green: '\x1b[32m',
red: '\x1b[31m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
reset: '\x1b[0m',
};
function log(message, color = 'reset') {
console.log(`${colors[color]}${message}${colors.reset}`);
}
function deleteFile(filePath) {
if (!fs.existsSync(filePath)) {
log(` ⚠️ File not found: ${filePath}`, 'yellow');
return false;
}
if (DRY_RUN) {
log(` [DRY-RUN] Would delete: ${filePath}`, 'blue');
return true;
}
try {
fs.unlinkSync(filePath);
log(` ✅ Deleted: ${filePath}`, 'green');
return true;
} catch (error) {
log(` ❌ Failed to delete: ${filePath} (${error.message})`, 'red');
return false;
}
}
function deleteEmptyDir(dirPath) {
if (!fs.existsSync(dirPath)) return;
const files = fs.readdirSync(dirPath);
if (files.length === 0) {
if (DRY_RUN) {
log(` [DRY-RUN] Would delete empty dir: ${dirPath}`, 'blue');
} else {
fs.rmdirSync(dirPath);
log(` 🗑️ Deleted empty directory: ${dirPath}`, 'green');
}
}
}
async function rollback() {
log('\n🔄 AuthCore Scaffold Rollback\n', 'blue');
if (!fs.existsSync(MANIFEST_PATH)) {
log('❌ No manifest found at .scaffold-auth/manifest.json', 'red');
log(' Cannot rollback without manifest. Files may have been created manually.\n', 'yellow');
process.exit(1);
}
const manifest = JSON.parse(fs.readFileSync(MANIFEST_PATH, 'utf-8'));
log(`📋 Manifest loaded: ${manifest.files.length} files to remove\n`, 'yellow');
log(` Created at: ${new Date(manifest.createdAt).toLocaleString()}`);
log(` Flags used: ${JSON.stringify(manifest.flags)}\n`);
if (DRY_RUN) {
log('🏃 Running in DRY-RUN mode (no files will be deleted)\n', 'yellow');
}
// Confirm before deleting
if (!DRY_RUN) {
log('⚠️ This will DELETE the following files:', 'red');
manifest.files.forEach(file => log(` - ${file}`, 'yellow'));
log('\nPress Ctrl+C to cancel, or wait 5 seconds to continue...', 'yellow');
await new Promise(resolve => setTimeout(resolve, 5000));
log('\n🗑️ Starting deletion...\n', 'red');
}
// Delete files
let deletedCount = 0;
let failedCount = 0;
for (const file of manifest.files) {
const filePath = path.join(process.cwd(), file);
const deleted = deleteFile(filePath);
if (deleted) deletedCount++;
else failedCount++;
}
// Clean up empty directories
const dirs = new Set(manifest.files.map(f => path.dirname(f)));
const sortedDirs = Array.from(dirs).sort((a, b) => b.length - a.length); // Deepest first
log('\n🧹 Cleaning up empty directories...\n', 'blue');
for (const dir of sortedDirs) {
const dirPath = path.join(process.cwd(), dir);
deleteEmptyDir(dirPath);
}
// Database migration warning
if (manifest.migrations && manifest.migrations.length > 0) {
log('\n⚠️ Database Migrations Detected:', 'yellow');
log(' The following migrations were applied:', 'yellow');
manifest.migrations.forEach(m => log(` - ${m}`, 'yellow'));
log('\n ⚠️ IMPORTANT: Migrations are NOT automatically rolled back!', 'red');
log(' To reverse database changes, you must:', 'yellow');
log(' 1. Back up your database');
log(' 2. Manually revert migrations or restore from backup');
log(' 3. Run: npx prisma migrate resolve --rolled-back <migration-name>\n');
}
// Delete manifest itself
if (!DRY_RUN) {
try {
fs.unlinkSync(MANIFEST_PATH);
log('✅ Deleted manifest file\n', 'green');
const manifestDir = path.dirname(MANIFEST_PATH);
if (fs.existsSync(manifestDir) && fs.readdirSync(manifestDir).length === 0) {
fs.rmdirSync(manifestDir);
log('✅ Deleted .scaffold-auth directory\n', 'green');
}
} catch (error) {
log(`⚠️ Could not delete manifest: ${error.message}\n`, 'yellow');
}
}
// Summary
log('📊 Summary:', 'blue');
log(` Files deleted: ${deletedCount}`);
log(` Failed: ${failedCount}`);
if (DRY_RUN) {
log('\n💡 Run without --dry-run to actually delete files\n', 'yellow');
} else {
log('\n✨ Rollback complete!\n', 'green');
}
}
rollback().catch(error => {
log(`\n❌ Rollback failed: ${error.message}\n`, 'red');
process.exit(1);
});