UNPKG

@xtest-cli/cli

Version:

CLI for xtest.ing - AI-powered test generation platform

262 lines 12.4 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.authCommand = void 0; const commander_1 = require("commander"); const inquirer_1 = __importDefault(require("inquirer")); const chalk_1 = __importDefault(require("chalk")); const ora_1 = __importDefault(require("ora")); const config_1 = require("../utils/config"); const axios_1 = __importDefault(require("axios")); // Welcome banner const showWelcomeBanner = () => { console.log('\n' + chalk_1.default.cyan('═'.repeat(60))); console.log(chalk_1.default.cyan.bold(' Welcome to xtest CLI - Browser Automation Made Simple')); console.log(chalk_1.default.cyan('═'.repeat(60)) + '\n'); }; // Helper to mask sensitive data const maskToken = (token) => { if (token.length <= 20) return '•'.repeat(token.length); return token.substring(0, 10) + '•'.repeat(20) + '...' + token.substring(token.length - 10); }; exports.authCommand = new commander_1.Command('auth') .description('Login to xtest.ing with your account') .option('-e, --email <email>', 'Your account email') .option('-p, --password <password>', 'Your account password') .option('-u, --url <url>', 'xtest.ing server URL', 'https://xtest.ing') .action(async (options) => { try { showWelcomeBanner(); let email = options.email; let password = options.password; let serverUrl = options.url; // Check if already authenticated const existingConfig = await (0, config_1.getConfig)(); if (existingConfig.apiKey) { console.log(chalk_1.default.yellow('📌 You are already logged in')); console.log(chalk_1.default.gray(` Server: ${existingConfig.serverUrl}`)); console.log(chalk_1.default.gray(` Token: ${maskToken(existingConfig.apiKey)}`)); const { continueAuth } = await inquirer_1.default.prompt([ { type: 'confirm', name: 'continueAuth', message: 'Do you want to login with different credentials?', default: false, }, ]); if (!continueAuth) { console.log(chalk_1.default.gray('\n👍 Using existing session')); return; } } // If no credentials provided, show interactive prompts if (!email || !password) { console.log(); console.log(chalk_1.default.white.bold('Login to xtest.ing\n')); console.log(chalk_1.default.gray(' Note: You need an active subscription to use the CLI')); console.log(chalk_1.default.gray(' Sign up at: ') + chalk_1.default.cyan('https://xtest.ing/pricing\n')); // Prompt for server URL first (with default) const serverUrlPrompt = await inquirer_1.default.prompt([ { type: 'input', name: 'serverUrl', message: 'Server URL:', default: options.url || existingConfig.serverUrl || 'https://xtest.ing', validate: (input) => { try { new URL(input); return true; } catch { return 'Please enter a valid URL'; } }, }, ]); serverUrl = serverUrlPrompt.serverUrl; // Prompt for credentials const credentials = await inquirer_1.default.prompt([ { type: 'input', name: 'email', message: 'Email:', validate: (input) => { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(input)) { return 'Please enter a valid email address'; } return true; }, }, { type: 'password', name: 'password', message: 'Password:', mask: '•', validate: (input) => { if (input.length < 6) { return 'Password must be at least 6 characters'; } return true; }, }, ]); email = credentials.email; password = credentials.password; } // Login with spinner const spinner = (0, ora_1.default)({ text: 'Logging in...', color: 'cyan', }).start(); try { // First, login to get JWT token const loginResponse = await axios_1.default.post(`${serverUrl}/api/auth/login`, { email, password, }, { timeout: 10000, }); if (loginResponse.status === 200 && loginResponse.data.token) { const { token, user } = loginResponse.data; // Check subscription status if (!user.hasActiveSubscription) { spinner.fail(chalk_1.default.red('No active subscription')); console.error(chalk_1.default.red('\n❌ Subscription required')); console.error(chalk_1.default.gray(' You need an active subscription to use the CLI')); console.error(chalk_1.default.gray(' Visit https://xtest.ing/pricing to subscribe')); process.exit(1); } spinner.succeed(chalk_1.default.green('Login successful!')); // Save the token as "apiKey" for backward compatibility await (0, config_1.saveConfig)({ apiKey: token, serverUrl }); // Show success message with user info console.log('\n' + chalk_1.default.green.bold('✓ Login successful!')); console.log(chalk_1.default.green.bold('Welcome back, ' + (user.name || user.email) + '!')); console.log(chalk_1.default.gray(' Subscription: ') + chalk_1.default.green(user.hasActiveSubscription ? 'Active' : 'Inactive')); console.log(chalk_1.default.white('\nNext steps:')); console.log(chalk_1.default.gray(' - Start a browser: ') + chalk_1.default.cyan('xtest browser')); console.log(chalk_1.default.gray(' - List sessions: ') + chalk_1.default.cyan('xtest sessions')); console.log(chalk_1.default.gray(' - Interactive mode: ') + chalk_1.default.cyan('xtest interactive')); } } catch (error) { spinner.fail(chalk_1.default.red('Login failed')); if (error.response?.status === 401) { console.error(chalk_1.default.red('✗ Authentication expired')); console.error(chalk_1.default.gray('\nPlease login again: ') + chalk_1.default.cyan('xtest auth')); // Clear invalid token await (0, config_1.saveConfig)({ apiKey: '', serverUrl }); } else if (error.response?.status === 403) { console.error(chalk_1.default.red('\n❌ Account disabled')); console.error(chalk_1.default.gray(' Please contact support')); } else if (error.code === 'ECONNREFUSED' || error.code === 'ENOTFOUND') { console.error(chalk_1.default.yellow('Warning: Authenticated but cannot reach server')); console.error(chalk_1.default.gray('Server: ') + chalk_1.default.white(serverUrl)); console.error(chalk_1.default.gray('\nPossible issues:')); console.error(chalk_1.default.gray(' - Check your internet connection')); console.error(chalk_1.default.gray(' - Verify the server URL is correct')); console.error(chalk_1.default.gray(' - The server might be temporarily down')); } else if (error.code === 'ETIMEDOUT') { console.error(chalk_1.default.red('\n❌ Connection timeout')); console.error(chalk_1.default.gray(' The server took too long to respond')); } else { console.error(chalk_1.default.red('\n❌ Connection failed')); console.error(chalk_1.default.gray(` ${error.message}`)); } process.exit(1); } } catch (error) { console.error(chalk_1.default.red('❌ Unexpected error:'), error); process.exit(1); } }); // Add logout subcommand exports.authCommand .command('logout') .description('Remove stored credentials') .action(async () => { try { const config = await (0, config_1.getConfig)(); if (!config.apiKey) { console.log(chalk_1.default.yellow('⚠️ You are not logged in')); return; } const { confirmLogout } = await inquirer_1.default.prompt([ { type: 'confirm', name: 'confirmLogout', message: 'Are you sure you want to logout?', default: false, }, ]); if (confirmLogout) { await (0, config_1.saveConfig)({ apiKey: '', serverUrl: '' }); console.log(chalk_1.default.green('✅ Logged out successfully')); } else { console.log(chalk_1.default.gray('Logout cancelled')); } } catch (error) { console.error(chalk_1.default.red('❌ Failed to logout:'), error); } }); // Add status subcommand exports.authCommand .command('status') .description('Check authentication status') .action(async () => { try { const config = await (0, config_1.getConfig)(); console.log('\n' + chalk_1.default.cyan('═'.repeat(50))); console.log(chalk_1.default.cyan.bold(' Authentication Status')); console.log(chalk_1.default.cyan('═'.repeat(50)) + '\n'); if (config.apiKey) { const spinner = (0, ora_1.default)({ text: 'Checking connection...', color: 'cyan', }).start(); try { const response = await axios_1.default.get(`${config.serverUrl}/api/health`, { headers: { 'Authorization': `Bearer ${config.apiKey}`, }, timeout: 5000, }); if (response.status === 200) { spinner.succeed(chalk_1.default.green('Connected')); console.log('\n' + chalk_1.default.green('✅ Authenticated')); console.log(chalk_1.default.white(' Server: ') + chalk_1.default.cyan(config.serverUrl)); console.log(chalk_1.default.white(' Token: ') + chalk_1.default.gray(maskToken(config.apiKey))); console.log(chalk_1.default.white(' Status: ') + chalk_1.default.green('Active')); } } catch (error) { spinner.fail(chalk_1.default.red('Connection failed')); console.log('\n' + chalk_1.default.yellow('⚠️ Authenticated but cannot reach server')); console.log(chalk_1.default.white(' Server: ') + chalk_1.default.cyan(config.serverUrl)); console.log(chalk_1.default.white(' Token: ') + chalk_1.default.gray(maskToken(config.apiKey))); console.log(chalk_1.default.white(' Status: ') + chalk_1.default.red('Offline')); } } else { console.log(chalk_1.default.yellow('⚠️ Not authenticated')); console.log(chalk_1.default.gray('\n To authenticate, run:')); console.log(chalk_1.default.cyan(' xtest auth')); } console.log('\n' + chalk_1.default.cyan('═'.repeat(50)) + '\n'); } catch (error) { console.error(chalk_1.default.red('❌ Failed to check status:'), error); } }); //# sourceMappingURL=auth.js.map