UNPKG

moshai-cli

Version:

A modern, fast Node.js CLI powered by arasadrahman

125 lines (104 loc) • 4.17 kB
const axios = require('axios'); const chalk = require('chalk').default; const fs = require('fs'); const path = require('path'); const Table = require('cli-table3'); const CACHE_DIR = path.resolve(__dirname, 'cache'); const CACHE_FILE = path.join(CACHE_DIR, 'crypto_cache.json'); const CACHE_TTL = 24 * 60 * 60 * 1000; const API_KEY = 'b35ef9c9aa3f714b9b952f997e7b29e492c648b53c8bbe3dc31b8ef06d18703c'; function formatPriceBDT(price) { const num = Number(price); return isNaN(num) ? 'N/A' : `ą§³${num.toFixed(2)}`; } function formatPriceUSD(price) { const num = Number(price); return isNaN(num) ? 'N/A' : `$${num.toFixed(2)}`; } function formatChangePercent(pct) { const num = Number(pct); if (isNaN(num)) return chalk.gray('N/A'); const fixed = `${Math.abs(num).toFixed(2)}%`; return num > 0 ? chalk.green(`+${fixed}`) : num < 0 ? chalk.red(`-${fixed}`) : chalk.gray(fixed); } async function fetchUsdToBdtRate() { try { const res = await axios.get('https://open.er-api.com/v6/latest/USD'); return Number(res.data.rates.BDT) || 105; } catch { return 105; } } async function fetchCryptoData() { const res = await axios.get('https://rest.coincap.io/v3/assets?limit=5', { headers: { Authorization: `Bearer ${API_KEY}` }, }); return res.data.data; } async function loadCache() { if (!fs.existsSync(CACHE_FILE)) return null; const stat = fs.statSync(CACHE_FILE); if (Date.now() - stat.mtimeMs > CACHE_TTL) return null; try { const data = fs.readFileSync(CACHE_FILE, 'utf8'); return JSON.parse(data); } catch { return null; } } async function saveCache(data) { if (!fs.existsSync(CACHE_DIR)) fs.mkdirSync(CACHE_DIR, { recursive: true }); fs.writeFileSync(CACHE_FILE, JSON.stringify(data, null, 2)); } module.exports = class CryptoPriceCommand { static signature = 'crypto'; static description = 'Show top 5 crypto prices in BDT and USD with 24h change'; async handle() { if (!this.startSpinner) this.startSpinner = () => { }; if (!this.stopSpinner) this.stopSpinner = () => { }; this.startSpinner('Fetching crypto prices...'); try { let data = await loadCache(); if (!data) { const [coins, usdToBdt] = await Promise.all([ fetchCryptoData(), fetchUsdToBdtRate(), ]); data = coins.map(coin => { const usd = Number(coin.priceUsd); const bdt = usd * usdToBdt; return { Name: coin.name || '', Symbol: (coin.symbol || '').toUpperCase(), 'Price (BDT)': formatPriceBDT(bdt), 'Price (USD)': formatPriceUSD(usd), 'Change 24h': formatChangePercent(coin.changePercent24Hr), }; }); await saveCache(data); } this.stopSpinner(); console.log(chalk.green('\nšŸ“Š Top 5 Crypto Prices in BDT and USD (Cached 5 mins max)\n')); // Create CLI table with custom headers and column widths const table = new Table({ head: ['Name', 'Symbol', 'Price (BDT)', 'Price (USD)', 'Change 24h'], colWidths: [15, 10, 18, 15, 12], style: { head: ['cyan'] }, }); // Push rows into table (colors will render properly) for (const row of data) { table.push([ row.Name, row.Symbol, row['Price (BDT)'], row['Price (USD)'], row['Change 24h'], ]); } console.log(table.toString()); } catch (err) { this.stopSpinner(); console.error(chalk.red('āŒ Failed to fetch crypto prices:'), err.message); } } };