@xtest-cli/cli
Version:
CLI for xtest.ing - AI-powered test generation platform
262 lines • 12.4 kB
JavaScript
;
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