UNPKG

api-stats-logger

Version:

SDK completo de logging e monitoramento de APIs com nova estrutura de logs organizada, auto-instrumentação, dashboard em tempo real e CLI para configuração automática. Suporta logs estruturados por contexto (HTTP, business, security, system) com campos op

607 lines (506 loc) 18.5 kB
#!/usr/bin/env node const { Command } = require('commander'); const UIComponents = require('./ui-components'); const axios = require('axios'); const open = require('open'); const path = require('path'); const fs = require('fs'); class CommandManager { constructor() { this.ui = new UIComponents(); this.program = new Command(); this.baseUrl = process.env.API_STATS_URL || 'https://apistats.eway-api.com.br'; // Inicializar armazenamento seguro const SecureStorage = require('./secure-storage'); this.secureStorage = new SecureStorage(); // Migrar credenciais antigas this.secureStorage.migrateOldCredentials(); this.authData = {}; this.setupCommands(); } setupCommands() { this.program .name('api-stats-logger') .description('CLI para gerenciamento de projetos API Stats') .version('2.1.3'); // Comando principal de inicialização this.program .command('init') .description('Inicializar configuração do projeto') .action(() => this.initProject()); // Comandos após autenticação if (this.authData.token) { this.program .command('projects') .alias('p') .description('Listar todos os projetos') .action(() => this.listProjects()); this.program .command('select') .alias('s') .description('Selecionar projeto ativo') .action(() => this.selectProject()); this.program .command('status') .description('Mostrar status do usuário e projeto atual') .action(() => this.showStatus()); this.program .command('create') .alias('c') .description('Criar novo projeto') .action(() => this.createProject()); this.program .command('delete') .alias('d') .description('Deletar projeto') .argument('[project-id]', 'ID do projeto para deletar') .action((projectId) => this.deleteProject(projectId)); this.program .command('apikey') .alias('k') .description('Gerar nova API key') .argument('[project-id]', 'ID do projeto') .action((projectId) => this.generateApiKey(projectId)); this.program .command('open') .alias('o') .description('Abrir projeto no navegador') .argument('[project-id]', 'ID do projeto') .action((projectId) => this.openProject(projectId)); this.program .command('settings') .description('Abrir configurações do projeto') .argument('[project-id]', 'ID do projeto') .action((projectId) => this.openSettings(projectId)); this.program .command('logout') .description('Fazer logout da CLI') .action(() => this.logout()); this.program .command('user') .alias('u') .description('Mostrar informações do usuário') .action(() => this.showUser()); this.program .command('logs') .alias('l') .description('Visualizar logs do projeto') .argument('[project-id]', 'ID do projeto') .option('-f, --follow', 'Seguir logs em tempo real') .option('-n, --lines <number>', 'Número de linhas', '50') .action((projectId, options) => this.showLogs(projectId, options)); this.program .command('stats') .description('Mostrar estatísticas do projeto') .argument('[project-id]', 'ID do projeto') .option('-d, --days <number>', 'Número de dias', '7') .action((projectId, options) => this.showStats(projectId, options)); } else { // Comandos para usuário não autenticado this.program .command('login') .description('Fazer login na CLI') .action(() => this.login()); this.program .command('register') .description('Criar nova conta') .action(() => this.register()); } } async run() { if (process.argv.length === 2) { // Sem argumentos, mostrar interface principal if (this.authData.token) { await this.showMainMenu(); } else { await this.initProject(); } } else { // Com argumentos, executar comando específico await this.program.parseAsync(process.argv); } } async showMainMenu() { this.ui.header(); const user = await this.getCurrentUser(); if (user) { this.ui.userStatus(user); } const choices = [ { name: `${this.ui.icons.project} Gerenciar Projetos`, value: 'projects' }, { name: `${this.ui.icons.key} Gerar API Key`, value: 'apikey' }, { name: `${this.ui.icons.settings} Configurações`, value: 'settings' }, { name: `${this.ui.icons.link} Abrir Dashboard`, value: 'open' }, { name: `${this.ui.icons.user} Perfil do Usuário`, value: 'user' }, { name: `${this.ui.icons.help} Ajuda`, value: 'help' }, { name: `${this.ui.icons.logout} Logout`, value: 'logout' } ]; const { selected } = await this.ui.select('O que você deseja fazer?', choices); switch (selected) { case 'projects': await this.manageProjects(); break; case 'apikey': await this.generateApiKey(); break; case 'settings': await this.openSettings(); break; case 'open': await this.openProject(); break; case 'user': await this.showUser(); break; case 'help': await this.showHelp(); break; case 'logout': await this.logout(); break; } } async manageProjects() { this.ui.section('Gerenciamento de Projetos'); const choices = [ { name: `${this.ui.icons.project} Listar Projetos`, value: 'list' }, { name: `${this.ui.icons.arrow} Selecionar Projeto`, value: 'select' }, { name: `${this.ui.icons.project} Criar Projeto`, value: 'create' }, { name: `${this.ui.icons.delete} Deletar Projeto`, value: 'delete' }, { name: `${this.ui.icons.arrow} Voltar`, value: 'back' } ]; const { selected } = await this.ui.select('Escolha uma opção:', choices); switch (selected) { case 'list': await this.listProjects(); break; case 'select': await this.selectProject(); break; case 'create': await this.createProject(); break; case 'delete': await this.deleteProject(); break; case 'back': await this.showMainMenu(); break; } } async listProjects() { const projects = await this.ui.withProgress('Carregando projetos', async () => { const response = await axios.get(`${this.baseUrl}/projects`, { headers: { Authorization: `Bearer ${this.authData.token}` } }); return response.data; }); if (projects.length === 0) { this.ui.info('Você não possui projetos. Use "create" para criar um novo.'); return; } this.ui.section('Seus Projetos'); const rows = projects.map(project => [ project.name, project.description || 'Sem descrição', project.environment || 'production', project.createdAt ? new Date(project.createdAt).toLocaleDateString() : 'N/A' ]); this.ui.table(['Nome', 'Descrição', 'Ambiente', 'Criado em'], rows); } async selectProject() { const projects = await this.ui.withProgress('Carregando projetos', async () => { const response = await axios.get(`${this.baseUrl}/projects`, { headers: { Authorization: `Bearer ${this.authData.token}` } }); return response.data; }); if (projects.length === 0) { this.ui.error('Você não possui projetos. Use "create" para criar um novo.'); return; } const choices = projects.map(project => ({ name: `${this.ui.icons.project} ${project.name} (${project.environment})`, value: project, short: project.name })); const { selected } = await this.ui.select('Selecione um projeto:', choices); // Salvar projeto selecionado this.saveSelectedProject(selected); this.ui.success(`Projeto "${selected.name}" selecionado com sucesso!`); } async createProject() { this.ui.section('Criar Novo Projeto'); const { value: name } = await this.ui.input('Nome do projeto:', { validate: (input) => input.length > 0 || 'Nome é obrigatório' }); const { value: description } = await this.ui.input('Descrição (opcional):'); const environments = [ { name: 'Production', value: 'production' }, { name: 'Development', value: 'development' }, { name: 'Testing', value: 'testing' }, { name: 'Staging', value: 'staging' } ]; const { selected: environment } = await this.ui.select('Ambiente:', environments); const project = await this.ui.withProgress('Criando projeto', async () => { const response = await axios.post(`${this.baseUrl}/projects`, { name, description, environment }, { headers: { Authorization: `Bearer ${this.authData.token}` } }); return response.data; }); this.ui.success(`Projeto "${project.name}" criado com sucesso!`); this.ui.info(`ID do projeto: ${project._id}`); } async deleteProject(projectId) { let project; if (!projectId) { const projects = await this.ui.withProgress('Carregando projetos', async () => { const response = await axios.get(`${this.baseUrl}/projects`, { headers: { Authorization: `Bearer ${this.authData.token}` } }); return response.data; }); if (projects.length === 0) { this.ui.error('Você não possui projetos para deletar.'); return; } const choices = projects.map(p => ({ name: `${this.ui.icons.project} ${p.name} (${p.environment})`, value: p, short: p.name })); const { selected } = await this.ui.select('Selecione o projeto para deletar:', choices); project = selected; } else { project = { _id: projectId }; } const { confirmed } = await this.ui.confirm(`Tem certeza que deseja deletar o projeto "${project.name || project._id}"?`); if (!confirmed) { this.ui.info('Operação cancelada.'); return; } await this.ui.withProgress('Deletando projeto', async () => { await axios.delete(`${this.baseUrl}/projects/${project._id}`, { headers: { Authorization: `Bearer ${this.authData.token}` } }); }); this.ui.success('Projeto deletado com sucesso!'); } async generateApiKey(projectId) { let project; if (!projectId) { const projects = await this.ui.withProgress('Carregando projetos', async () => { const response = await axios.get(`${this.baseUrl}/projects`, { headers: { Authorization: `Bearer ${this.authData.token}` } }); return response.data; }); if (projects.length === 0) { this.ui.error('Você não possui projetos. Crie um projeto primeiro.'); return; } const choices = projects.map(p => ({ name: `${this.ui.icons.project} ${p.name} (${p.environment})`, value: p, short: p.name })); const { selected } = await this.ui.select('Selecione o projeto:', choices); project = selected; } else { project = { _id: projectId }; } const url = `https://apistats.eway.app.br/applications/${project._id}/configuracoes`; this.ui.info(`Abrindo página de configurações para gerar nova API key...`); this.ui.info(`URL: ${url}`); await open(url); } async openProject(projectId) { let project; if (!projectId) { const projects = await this.ui.withProgress('Carregando projetos', async () => { const response = await axios.get(`${this.baseUrl}/projects`, { headers: { Authorization: `Bearer ${this.authData.token}` } }); return response.data; }); if (projects.length === 0) { this.ui.error('Você não possui projetos.'); return; } const choices = projects.map(p => ({ name: `${this.ui.icons.project} ${p.name} (${p.environment})`, value: p, short: p.name })); const { selected } = await this.ui.select('Selecione o projeto:', choices); project = selected; } else { project = { _id: projectId }; } const url = `https://apistats.eway.app.br/applications/${project._id}`; this.ui.info(`Abrindo projeto no navegador...`); await open(url); } async openSettings(projectId) { let project; if (!projectId) { const projects = await this.ui.withProgress('Carregando projetos', async () => { const response = await axios.get(`${this.baseUrl}/projects`, { headers: { Authorization: `Bearer ${this.authData.token}` } }); return response.data; }); if (projects.length === 0) { this.ui.error('Você não possui projetos.'); return; } const choices = projects.map(p => ({ name: `${this.ui.icons.project} ${p.name} (${p.environment})`, value: p, short: p.name })); const { selected } = await this.ui.select('Selecione o projeto:', choices); project = selected; } else { project = { _id: projectId }; } const url = `https://apistats.eway.app.br/applications/${project._id}/configuracoes`; this.ui.info(`Abrindo configurações do projeto...`); await open(url); } async logout() { const { confirmed } = await this.ui.confirm('Tem certeza que deseja fazer logout?'); if (!confirmed) { this.ui.info('Operação cancelada.'); return; } await this.clearAuthData(); this.ui.success('Logout realizado com sucesso!'); this.ui.info('Use "login" para fazer login novamente.'); } async showUser() { const user = await this.ui.withProgress('Carregando informações do usuário', async () => { const response = await axios.get(`${this.baseUrl}/auth/profile`, { headers: { Authorization: `Bearer ${this.authData.token}` } }); return response.data; }); this.ui.section('Informações do Usuário'); this.ui.userStatus({ name: user.firstName ? `${user.firstName} ${user.lastName}` : user.username, email: user.email, projects: user.projects || 0 }); } async showHelp() { const commands = [ { command: 'projects, p', description: 'Listar todos os projetos' }, { command: 'select, s', description: 'Selecionar projeto ativo' }, { command: 'create, c', description: 'Criar novo projeto' }, { command: 'delete, d [id]', description: 'Deletar projeto' }, { command: 'apikey, k [id]', description: 'Gerar nova API key' }, { command: 'open, o [id]', description: 'Abrir projeto no navegador' }, { command: 'settings [id]', description: 'Abrir configurações' }, { command: 'user, u', description: 'Informações do usuário' }, { command: 'logout', description: 'Fazer logout da CLI' }, { command: 'help', description: 'Mostrar esta ajuda' } ]; this.ui.commandList(commands); } async getCurrentUser() { try { const response = await axios.get(`${this.baseUrl}/auth/profile`, { headers: { Authorization: `Bearer ${this.authData.token}` } }); return { name: response.data.firstName ? `${response.data.firstName} ${response.data.lastName}` : response.data.username, email: response.data.email, projects: response.data.projects || 0 }; } catch (error) { return null; } } async loadAuthData() { try { const credentials = await this.secureStorage.getCredentials(); if (credentials) { this.authData = { token: credentials.token, deviceId: credentials.deviceId, timestamp: Date.now() }; return this.authData; } } catch (error) { console.warn('⚠️ Erro ao carregar credenciais:', error.message); } return {}; } async saveAuthData(token, deviceId) { try { const data = { token, deviceId, timestamp: Date.now() }; this.authData = data; const success = await this.secureStorage.setCredentials(token, deviceId); if (!success) { console.warn('⚠️ Não foi possível salvar credenciais de forma segura'); } } catch (error) { console.warn('⚠️ Erro ao salvar credenciais:', error.message); } } async clearAuthData() { try { await this.secureStorage.clearCredentials(); this.authData = {}; } catch (error) { console.warn('⚠️ Erro ao limpar credenciais:', error.message); } } saveSelectedProject(project) { const projectFile = path.join(process.cwd(), '.api-stats-project'); fs.writeFileSync(projectFile, JSON.stringify(project, null, 2)); } // Métodos para implementar outros comandos async initProject() { this.ui.info('Funcionalidade de inicialização será implementada diretamente na CLI moderna.'); this.ui.info('Use os comandos disponíveis: projects, create, select, etc.'); } async login() { this.ui.info('Use o comando principal da CLI para fazer login.'); this.ui.info('Execute: npx api-stats-logger'); } async register() { this.ui.info('Use o comando principal da CLI para registrar uma conta.'); this.ui.info('Execute: npx api-stats-logger'); } async showStatus() { const user = await this.getCurrentUser(); if (user) { this.ui.userStatus(user); } const projectFile = path.join(process.cwd(), '.api-stats-project'); if (fs.existsSync(projectFile)) { try { const project = JSON.parse(fs.readFileSync(projectFile, 'utf8')); this.ui.section('Projeto Atual'); this.ui.info(`Nome: ${project.name}`); this.ui.info(`Ambiente: ${project.environment}`); this.ui.info(`ID: ${project._id}`); } catch (error) { this.ui.warning('Erro ao carregar informações do projeto atual.'); } } } async showLogs(projectId, options) { this.ui.info('Funcionalidade de logs em desenvolvimento...'); } async showStats(projectId, options) { this.ui.info('Funcionalidade de estatísticas em desenvolvimento...'); } } module.exports = CommandManager;