@feardread/fear 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/FEAR.js +459 -0
- package/FEARServer.js +280 -0
- package/controllers/agent.js +438 -0
- package/controllers/auth/index.js +345 -0
- package/controllers/auth/token.js +50 -0
- package/controllers/blog.js +105 -0
- package/controllers/brand.js +10 -0
- package/controllers/cart.js +425 -0
- package/controllers/category.js +9 -0
- package/controllers/coupon.js +63 -0
- package/controllers/crud/crud.js +508 -0
- package/controllers/crud/index.js +36 -0
- package/controllers/email.js +34 -0
- package/controllers/enquiry.js +65 -0
- package/controllers/events.js +9 -0
- package/controllers/order.js +125 -0
- package/controllers/payment.js +31 -0
- package/controllers/product.js +147 -0
- package/controllers/review.js +247 -0
- package/controllers/tag.js +10 -0
- package/controllers/task.js +10 -0
- package/controllers/upload.js +41 -0
- package/controllers/user.js +401 -0
- package/index.js +7 -0
- package/libs/agent/index.js +561 -0
- package/libs/agent/modules/ai/ai.js +285 -0
- package/libs/agent/modules/ai/chat.js +518 -0
- package/libs/agent/modules/ai/config.js +688 -0
- package/libs/agent/modules/ai/operations.js +787 -0
- package/libs/agent/modules/analyze/api.js +546 -0
- package/libs/agent/modules/analyze/dorks.js +395 -0
- package/libs/agent/modules/ccard/README.md +454 -0
- package/libs/agent/modules/ccard/audit.js +479 -0
- package/libs/agent/modules/ccard/checker.js +674 -0
- package/libs/agent/modules/ccard/payment-processors.json +16 -0
- package/libs/agent/modules/ccard/validator.js +629 -0
- package/libs/agent/modules/code/analyzer.js +303 -0
- package/libs/agent/modules/code/jquery.js +1093 -0
- package/libs/agent/modules/code/react.js +1536 -0
- package/libs/agent/modules/code/refactor.js +499 -0
- package/libs/agent/modules/crypto/exchange.js +564 -0
- package/libs/agent/modules/net/proxy.js +409 -0
- package/libs/agent/modules/security/cve.js +442 -0
- package/libs/agent/modules/security/monitor.js +360 -0
- package/libs/agent/modules/security/scanner.js +300 -0
- package/libs/agent/modules/security/vulnerability.js +506 -0
- package/libs/agent/modules/security/web.js +465 -0
- package/libs/agent/modules/utils/browser.js +492 -0
- package/libs/agent/modules/utils/colorizer.js +285 -0
- package/libs/agent/modules/utils/manager.js +478 -0
- package/libs/cloud/index.js +228 -0
- package/libs/config/db.js +21 -0
- package/libs/config/validator.js +82 -0
- package/libs/db/index.js +318 -0
- package/libs/emailer/imap.js +126 -0
- package/libs/emailer/info.js +41 -0
- package/libs/emailer/smtp.js +77 -0
- package/libs/handler/async.js +3 -0
- package/libs/handler/error.js +66 -0
- package/libs/handler/index.js +161 -0
- package/libs/logger/index.js +49 -0
- package/libs/logger/morgan.js +24 -0
- package/libs/passport/passport.js +109 -0
- package/libs/search/api.js +384 -0
- package/libs/search/features.js +219 -0
- package/libs/search/service.js +64 -0
- package/libs/swagger/config.js +18 -0
- package/libs/swagger/index.js +35 -0
- package/libs/validator/index.js +254 -0
- package/models/blog.js +31 -0
- package/models/brand.js +12 -0
- package/models/cart.js +14 -0
- package/models/category.js +11 -0
- package/models/coupon.js +9 -0
- package/models/customer.js +0 -0
- package/models/enquiry.js +29 -0
- package/models/events.js +13 -0
- package/models/order.js +94 -0
- package/models/product.js +32 -0
- package/models/review.js +14 -0
- package/models/tag.js +10 -0
- package/models/task.js +11 -0
- package/models/user.js +68 -0
- package/package.json +12 -0
- package/routes/agent.js +615 -0
- package/routes/auth.js +13 -0
- package/routes/blog.js +19 -0
- package/routes/brand.js +15 -0
- package/routes/cart.js +105 -0
- package/routes/category.js +16 -0
- package/routes/coupon.js +15 -0
- package/routes/enquiry.js +14 -0
- package/routes/events.js +16 -0
- package/routes/mail.js +170 -0
- package/routes/order.js +19 -0
- package/routes/product.js +22 -0
- package/routes/review.js +11 -0
- package/routes/task.js +12 -0
- package/routes/user.js +17 -0
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
const https = require('https');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const colorizer = require('../utils/colorizer');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Crypto Exchange Rate Checker
|
|
8
|
+
* Fetches and compares cryptocurrency exchange rates across multiple platforms
|
|
9
|
+
*/
|
|
10
|
+
class CryptoExchangeChecker {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.name = 'Crypto Exchange Checker';
|
|
13
|
+
this.cache = {
|
|
14
|
+
rates: {},
|
|
15
|
+
timestamp: null,
|
|
16
|
+
ttl: 60000 // Cache for 1 minute
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// Major cryptocurrency exchanges APIs
|
|
20
|
+
this.exchanges = {
|
|
21
|
+
coinbase: {
|
|
22
|
+
name: 'Coinbase',
|
|
23
|
+
apiUrl: 'api.coinbase.com',
|
|
24
|
+
path: '/v2/exchange-rates?currency=',
|
|
25
|
+
parseRate: (data, targetCurrency) => {
|
|
26
|
+
if (data.data && data.data.rates && data.data.rates[targetCurrency]) {
|
|
27
|
+
return parseFloat(data.data.rates[targetCurrency]);
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
kraken: {
|
|
33
|
+
name: 'Kraken',
|
|
34
|
+
apiUrl: 'api.kraken.com',
|
|
35
|
+
path: '/0/public/Ticker?pair=',
|
|
36
|
+
pairFormat: (base, quote) => `${base}${quote}`,
|
|
37
|
+
parseRate: (data) => {
|
|
38
|
+
if (data.result) {
|
|
39
|
+
const pair = Object.keys(data.result)[0];
|
|
40
|
+
if (pair && data.result[pair] && data.result[pair].c) {
|
|
41
|
+
return parseFloat(data.result[pair].c[0]);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
binance: {
|
|
48
|
+
name: 'Binance',
|
|
49
|
+
apiUrl: 'api.binance.com',
|
|
50
|
+
path: '/api/v3/ticker/price?symbol=',
|
|
51
|
+
pairFormat: (base, quote) => `${base}${quote}`,
|
|
52
|
+
parseRate: (data) => {
|
|
53
|
+
if (data.price) {
|
|
54
|
+
return parseFloat(data.price);
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// Popular cryptocurrencies
|
|
62
|
+
this.cryptos = {
|
|
63
|
+
BTC: { name: 'Bitcoin', symbol: 'BTC' },
|
|
64
|
+
ETH: { name: 'Ethereum', symbol: 'ETH' },
|
|
65
|
+
USDT: { name: 'Tether', symbol: 'USDT' },
|
|
66
|
+
BNB: { name: 'Binance Coin', symbol: 'BNB' },
|
|
67
|
+
XRP: { name: 'Ripple', symbol: 'XRP' },
|
|
68
|
+
ADA: { name: 'Cardano', symbol: 'ADA' },
|
|
69
|
+
DOGE: { name: 'Dogecoin', symbol: 'DOGE' },
|
|
70
|
+
SOL: { name: 'Solana', symbol: 'SOL' },
|
|
71
|
+
DOT: { name: 'Polkadot', symbol: 'DOT' },
|
|
72
|
+
MATIC: { name: 'Polygon', symbol: 'MATIC' }
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// Fiat currencies
|
|
76
|
+
this.fiatCurrencies = ['USD', 'EUR', 'GBP', 'JPY', 'CAD', 'AUD'];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Make HTTPS request
|
|
81
|
+
*/
|
|
82
|
+
httpsRequest(hostname, path) {
|
|
83
|
+
return new Promise((resolve, reject) => {
|
|
84
|
+
const options = {
|
|
85
|
+
hostname: hostname,
|
|
86
|
+
path: path,
|
|
87
|
+
method: 'GET',
|
|
88
|
+
headers: {
|
|
89
|
+
'User-Agent': 'SecurityAgent/2.3',
|
|
90
|
+
'Accept': 'application/json'
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const req = https.request(options, (res) => {
|
|
95
|
+
let data = '';
|
|
96
|
+
|
|
97
|
+
res.on('data', (chunk) => {
|
|
98
|
+
data += chunk;
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
res.on('end', () => {
|
|
102
|
+
try {
|
|
103
|
+
resolve(JSON.parse(data));
|
|
104
|
+
} catch (err) {
|
|
105
|
+
reject(new Error('Failed to parse JSON response'));
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
req.on('error', (err) => {
|
|
111
|
+
reject(err);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
req.setTimeout(10000, () => {
|
|
115
|
+
req.destroy();
|
|
116
|
+
reject(new Error('Request timeout'));
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
req.end();
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Fetch rate from Coinbase
|
|
125
|
+
*/
|
|
126
|
+
async fetchCoinbaseRate(baseCurrency, targetCurrency) {
|
|
127
|
+
try {
|
|
128
|
+
const exchange = this.exchanges.coinbase;
|
|
129
|
+
const path = exchange.path + baseCurrency;
|
|
130
|
+
const data = await this.httpsRequest(exchange.apiUrl, path);
|
|
131
|
+
return exchange.parseRate(data, targetCurrency);
|
|
132
|
+
} catch (err) {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Fetch rate from Kraken
|
|
139
|
+
*/
|
|
140
|
+
async fetchKrakenRate(baseCurrency, targetCurrency) {
|
|
141
|
+
try {
|
|
142
|
+
const exchange = this.exchanges.kraken;
|
|
143
|
+
const pair = exchange.pairFormat(baseCurrency, targetCurrency);
|
|
144
|
+
const path = exchange.path + pair;
|
|
145
|
+
const data = await this.httpsRequest(exchange.apiUrl, path);
|
|
146
|
+
return exchange.parseRate(data);
|
|
147
|
+
} catch (err) {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Fetch rate from Binance
|
|
154
|
+
*/
|
|
155
|
+
async fetchBinanceRate(baseCurrency, targetCurrency) {
|
|
156
|
+
try {
|
|
157
|
+
const exchange = this.exchanges.binance;
|
|
158
|
+
const pair = exchange.pairFormat(baseCurrency, targetCurrency);
|
|
159
|
+
const path = exchange.path + pair;
|
|
160
|
+
const data = await this.httpsRequest(exchange.apiUrl, path);
|
|
161
|
+
return exchange.parseRate(data);
|
|
162
|
+
} catch (err) {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Check if cache is valid
|
|
169
|
+
*/
|
|
170
|
+
isCacheValid() {
|
|
171
|
+
if (!this.cache.timestamp) return false;
|
|
172
|
+
return (Date.now() - this.cache.timestamp) < this.cache.ttl;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Compare rates across exchanges
|
|
177
|
+
*/
|
|
178
|
+
async compareRates(args) {
|
|
179
|
+
if (args.length < 2) {
|
|
180
|
+
console.log(colorizer.error('Usage: compare-rates <crypto> <fiat>'));
|
|
181
|
+
console.log(colorizer.info('Example: compare-rates BTC USD'));
|
|
182
|
+
console.log(colorizer.dim('Supported cryptos: ' + Object.keys(this.cryptos).join(', ')));
|
|
183
|
+
console.log(colorizer.dim('Supported fiat: ' + this.fiatCurrencies.join(', ')));
|
|
184
|
+
return Promise.resolve();
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const crypto = args[0].toUpperCase();
|
|
188
|
+
const fiat = args[1].toUpperCase();
|
|
189
|
+
|
|
190
|
+
if (!this.cryptos[crypto]) {
|
|
191
|
+
console.log(colorizer.error('Unsupported cryptocurrency: ' + crypto));
|
|
192
|
+
console.log(colorizer.info('Supported: ' + Object.keys(this.cryptos).join(', ')));
|
|
193
|
+
return Promise.resolve();
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (!this.fiatCurrencies.includes(fiat)) {
|
|
197
|
+
console.log(colorizer.error('Unsupported fiat currency: ' + fiat));
|
|
198
|
+
console.log(colorizer.info('Supported: ' + this.fiatCurrencies.join(', ')));
|
|
199
|
+
return Promise.resolve();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
console.log(colorizer.section(`Comparing ${crypto}/${fiat} Exchange Rates`));
|
|
203
|
+
console.log(colorizer.dim('Fetching rates from multiple exchanges...'));
|
|
204
|
+
console.log();
|
|
205
|
+
|
|
206
|
+
const rates = {};
|
|
207
|
+
|
|
208
|
+
// Fetch from Coinbase
|
|
209
|
+
process.stdout.write(colorizer.dim(' Coinbase... '));
|
|
210
|
+
rates.coinbase = await this.fetchCoinbaseRate(crypto, fiat);
|
|
211
|
+
console.log(rates.coinbase ? colorizer.green('✓') : colorizer.red('✗'));
|
|
212
|
+
|
|
213
|
+
// Fetch from Kraken
|
|
214
|
+
process.stdout.write(colorizer.dim(' Kraken... '));
|
|
215
|
+
rates.kraken = await this.fetchKrakenRate(crypto, fiat);
|
|
216
|
+
console.log(rates.kraken ? colorizer.green('✓') : colorizer.red('✗'));
|
|
217
|
+
|
|
218
|
+
// Fetch from Binance
|
|
219
|
+
process.stdout.write(colorizer.dim(' Binance... '));
|
|
220
|
+
rates.binance = await this.fetchBinanceRate(crypto, fiat);
|
|
221
|
+
console.log(rates.binance ? colorizer.green('✓') : colorizer.red('✗'));
|
|
222
|
+
|
|
223
|
+
console.log();
|
|
224
|
+
|
|
225
|
+
// Display results
|
|
226
|
+
const validRates = Object.entries(rates)
|
|
227
|
+
.filter(([_, rate]) => rate !== null)
|
|
228
|
+
.sort(([_, a], [__, b]) => a - b); // Sort by rate (best to worst for selling)
|
|
229
|
+
|
|
230
|
+
if (validRates.length === 0) {
|
|
231
|
+
console.log(colorizer.error('Failed to fetch rates from any exchange'));
|
|
232
|
+
console.log(colorizer.dim('This may be due to API rate limits or unsupported pair'));
|
|
233
|
+
return Promise.resolve();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
console.log(colorizer.cyan('Exchange Rates:'));
|
|
237
|
+
validRates.forEach(([exchange, rate], index) => {
|
|
238
|
+
const exchangeName = this.exchanges[exchange].name;
|
|
239
|
+
const badge = index === 0 ? colorizer.green(' [BEST BUY]') :
|
|
240
|
+
index === validRates.length - 1 ? colorizer.yellow(' [BEST SELL]') : '';
|
|
241
|
+
|
|
242
|
+
console.log(colorizer.bullet(
|
|
243
|
+
exchangeName.padEnd(15) +
|
|
244
|
+
colorizer.bright(this.formatPrice(rate, fiat)) +
|
|
245
|
+
badge
|
|
246
|
+
));
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
// Calculate spread
|
|
250
|
+
if (validRates.length > 1) {
|
|
251
|
+
const lowest = validRates[0][1];
|
|
252
|
+
const highest = validRates[validRates.length - 1][1];
|
|
253
|
+
const spread = highest - lowest;
|
|
254
|
+
const spreadPercent = ((spread / lowest) * 100).toFixed(2);
|
|
255
|
+
|
|
256
|
+
console.log();
|
|
257
|
+
console.log(colorizer.cyan('Arbitrage Opportunity:'));
|
|
258
|
+
console.log(colorizer.bullet('Spread: ' + this.formatPrice(spread, fiat) +
|
|
259
|
+
' (' + spreadPercent + '%)'));
|
|
260
|
+
|
|
261
|
+
if (spreadPercent > 1) {
|
|
262
|
+
console.log(colorizer.yellow(' ⚠ Significant price difference detected!'));
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Calculate average
|
|
267
|
+
const average = validRates.reduce((sum, [_, rate]) => sum + rate, 0) / validRates.length;
|
|
268
|
+
console.log();
|
|
269
|
+
console.log(colorizer.cyan('Average Rate: ') + colorizer.bright(this.formatPrice(average, fiat)));
|
|
270
|
+
console.log();
|
|
271
|
+
console.log(colorizer.dim('Note: Rates are indicative and may not reflect actual trading fees'));
|
|
272
|
+
console.log();
|
|
273
|
+
|
|
274
|
+
return Promise.resolve();
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Get current price for a cryptocurrency
|
|
279
|
+
*/
|
|
280
|
+
async getPrice(args) {
|
|
281
|
+
if (args.length === 0) {
|
|
282
|
+
console.log(colorizer.error('Usage: crypto-price <symbol> [fiat]'));
|
|
283
|
+
console.log(colorizer.info('Example: crypto-price BTC USD'));
|
|
284
|
+
console.log(colorizer.dim('Supported cryptos: ' + Object.keys(this.cryptos).join(', ')));
|
|
285
|
+
return Promise.resolve();
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const crypto = args[0].toUpperCase();
|
|
289
|
+
const fiat = (args[1] || 'USD').toUpperCase();
|
|
290
|
+
|
|
291
|
+
if (!this.cryptos[crypto]) {
|
|
292
|
+
console.log(colorizer.error('Unsupported cryptocurrency: ' + crypto));
|
|
293
|
+
return Promise.resolve();
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
console.log(colorizer.section(`${this.cryptos[crypto].name} (${crypto}) Price`));
|
|
297
|
+
console.log(colorizer.dim('Fetching current price...'));
|
|
298
|
+
console.log();
|
|
299
|
+
|
|
300
|
+
const rate = await this.fetchCoinbaseRate(crypto, fiat);
|
|
301
|
+
|
|
302
|
+
if (rate) {
|
|
303
|
+
console.log(colorizer.cyan('Current Price: ') +
|
|
304
|
+
colorizer.bright(colorizer.green(this.formatPrice(rate, fiat))));
|
|
305
|
+
console.log(colorizer.dim('Source: Coinbase'));
|
|
306
|
+
} else {
|
|
307
|
+
console.log(colorizer.error('Failed to fetch price'));
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
console.log();
|
|
311
|
+
return Promise.resolve();
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Track multiple cryptocurrencies
|
|
316
|
+
*/
|
|
317
|
+
async trackPortfolio(args) {
|
|
318
|
+
const cryptoList = args.length > 0 ?
|
|
319
|
+
args.map(c => c.toUpperCase()) :
|
|
320
|
+
['BTC', 'ETH', 'BNB', 'XRP', 'ADA'];
|
|
321
|
+
|
|
322
|
+
console.log(colorizer.section('Cryptocurrency Portfolio Tracker'));
|
|
323
|
+
console.log(colorizer.dim('Tracking: ' + cryptoList.join(', ')));
|
|
324
|
+
console.log();
|
|
325
|
+
|
|
326
|
+
const results = [];
|
|
327
|
+
|
|
328
|
+
for (const crypto of cryptoList) {
|
|
329
|
+
if (!this.cryptos[crypto]) {
|
|
330
|
+
console.log(colorizer.warning(`Skipping unsupported: ${crypto}`));
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
process.stdout.write(colorizer.dim(` Fetching ${crypto}... `));
|
|
335
|
+
const rate = await this.fetchCoinbaseRate(crypto, 'USD');
|
|
336
|
+
|
|
337
|
+
if (rate) {
|
|
338
|
+
results.push({ crypto, rate });
|
|
339
|
+
console.log(colorizer.green('✓'));
|
|
340
|
+
} else {
|
|
341
|
+
console.log(colorizer.red('✗'));
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
console.log();
|
|
346
|
+
console.log(colorizer.cyan('Current Prices (USD):'));
|
|
347
|
+
|
|
348
|
+
results.forEach(({ crypto, rate }) => {
|
|
349
|
+
const name = this.cryptos[crypto].name;
|
|
350
|
+
console.log(colorizer.bullet(
|
|
351
|
+
crypto.padEnd(8) +
|
|
352
|
+
name.padEnd(20) +
|
|
353
|
+
colorizer.bright(this.formatPrice(rate, 'USD'))
|
|
354
|
+
));
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
console.log();
|
|
358
|
+
return Promise.resolve();
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Calculate conversion between cryptocurrencies
|
|
363
|
+
*/
|
|
364
|
+
async convert(args) {
|
|
365
|
+
if (args.length < 3) {
|
|
366
|
+
console.log(colorizer.error('Usage: crypto-convert <amount> <from> <to>'));
|
|
367
|
+
console.log(colorizer.info('Example: crypto-convert 1 BTC ETH'));
|
|
368
|
+
return Promise.resolve();
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const amount = parseFloat(args[0]);
|
|
372
|
+
const fromCrypto = args[1].toUpperCase();
|
|
373
|
+
const toCrypto = args[2].toUpperCase();
|
|
374
|
+
|
|
375
|
+
if (isNaN(amount) || amount <= 0) {
|
|
376
|
+
console.log(colorizer.error('Invalid amount'));
|
|
377
|
+
return Promise.resolve();
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
if (!this.cryptos[fromCrypto] || !this.cryptos[toCrypto]) {
|
|
381
|
+
console.log(colorizer.error('Unsupported cryptocurrency'));
|
|
382
|
+
return Promise.resolve();
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
console.log(colorizer.section('Crypto Conversion'));
|
|
386
|
+
console.log(colorizer.dim('Calculating conversion rate...'));
|
|
387
|
+
console.log();
|
|
388
|
+
|
|
389
|
+
// Convert through USD as intermediate
|
|
390
|
+
const fromRate = await this.fetchCoinbaseRate(fromCrypto, 'USD');
|
|
391
|
+
const toRate = await this.fetchCoinbaseRate(toCrypto, 'USD');
|
|
392
|
+
|
|
393
|
+
if (!fromRate || !toRate) {
|
|
394
|
+
console.log(colorizer.error('Failed to fetch conversion rates'));
|
|
395
|
+
return Promise.resolve();
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const usdValue = amount * fromRate;
|
|
399
|
+
const convertedAmount = usdValue / toRate;
|
|
400
|
+
|
|
401
|
+
console.log(colorizer.cyan('Conversion:'));
|
|
402
|
+
console.log(colorizer.bullet(
|
|
403
|
+
colorizer.bright(amount.toFixed(8)) + ' ' + fromCrypto +
|
|
404
|
+
' → ' +
|
|
405
|
+
colorizer.bright(convertedAmount.toFixed(8)) + ' ' + toCrypto
|
|
406
|
+
));
|
|
407
|
+
console.log();
|
|
408
|
+
console.log(colorizer.dim('USD Equivalent: ' + this.formatPrice(usdValue, 'USD')));
|
|
409
|
+
console.log(colorizer.dim('Source: Coinbase'));
|
|
410
|
+
console.log();
|
|
411
|
+
|
|
412
|
+
return Promise.resolve();
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Show market summary
|
|
417
|
+
*/
|
|
418
|
+
async marketSummary(args) {
|
|
419
|
+
console.log(colorizer.section('Cryptocurrency Market Summary'));
|
|
420
|
+
console.log(colorizer.dim('Top cryptocurrencies by market cap'));
|
|
421
|
+
console.log();
|
|
422
|
+
|
|
423
|
+
const topCryptos = ['BTC', 'ETH', 'USDT', 'BNB', 'XRP', 'ADA', 'DOGE', 'SOL'];
|
|
424
|
+
const rates = [];
|
|
425
|
+
|
|
426
|
+
for (const crypto of topCryptos) {
|
|
427
|
+
const rate = await this.fetchCoinbaseRate(crypto, 'USD');
|
|
428
|
+
if (rate) {
|
|
429
|
+
rates.push({ crypto, rate });
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
console.log(colorizer.cyan('Current Prices (USD):'));
|
|
434
|
+
console.log(colorizer.dim('─'.repeat(60)));
|
|
435
|
+
console.log(colorizer.dim(
|
|
436
|
+
'Symbol'.padEnd(10) +
|
|
437
|
+
'Name'.padEnd(20) +
|
|
438
|
+
'Price'.padEnd(20)
|
|
439
|
+
));
|
|
440
|
+
console.log(colorizer.dim('─'.repeat(60)));
|
|
441
|
+
|
|
442
|
+
rates.forEach(({ crypto, rate }) => {
|
|
443
|
+
const name = this.cryptos[crypto].name;
|
|
444
|
+
console.log(
|
|
445
|
+
colorizer.bright(crypto.padEnd(10)) +
|
|
446
|
+
name.padEnd(20) +
|
|
447
|
+
colorizer.green(this.formatPrice(rate, 'USD').padEnd(20))
|
|
448
|
+
);
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
console.log(colorizer.dim('─'.repeat(60)));
|
|
452
|
+
console.log();
|
|
453
|
+
console.log(colorizer.dim('Data source: Coinbase'));
|
|
454
|
+
console.log();
|
|
455
|
+
|
|
456
|
+
return Promise.resolve();
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Export rates to file
|
|
461
|
+
*/
|
|
462
|
+
async exportRates(args) {
|
|
463
|
+
const outputFile = args[0] || 'crypto-rates.json';
|
|
464
|
+
|
|
465
|
+
console.log(colorizer.section('Exporting Cryptocurrency Rates'));
|
|
466
|
+
console.log(colorizer.dim('Fetching rates...'));
|
|
467
|
+
console.log();
|
|
468
|
+
|
|
469
|
+
const data = {
|
|
470
|
+
timestamp: new Date().toISOString(),
|
|
471
|
+
rates: {}
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
for (const crypto of Object.keys(this.cryptos)) {
|
|
475
|
+
const rate = await this.fetchCoinbaseRate(crypto, 'USD');
|
|
476
|
+
if (rate) {
|
|
477
|
+
data.rates[crypto] = {
|
|
478
|
+
name: this.cryptos[crypto].name,
|
|
479
|
+
usd: rate
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
fs.writeFileSync(outputFile, JSON.stringify(data, null, 2));
|
|
485
|
+
|
|
486
|
+
console.log(colorizer.green('✓ Rates exported to: ' + outputFile));
|
|
487
|
+
console.log(colorizer.dim(' Cryptocurrencies: ' + Object.keys(data.rates).length));
|
|
488
|
+
console.log(colorizer.dim(' Timestamp: ' + data.timestamp));
|
|
489
|
+
console.log();
|
|
490
|
+
|
|
491
|
+
return Promise.resolve();
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Show help for crypto commands
|
|
496
|
+
*/
|
|
497
|
+
showHelp(args) {
|
|
498
|
+
console.log(colorizer.section('Crypto Exchange Checker - Help'));
|
|
499
|
+
console.log();
|
|
500
|
+
|
|
501
|
+
const commands = [
|
|
502
|
+
{ cmd: 'compare-rates', desc: 'Compare rates across exchanges', example: 'compare-rates BTC USD' },
|
|
503
|
+
{ cmd: 'crypto-price', desc: 'Get current price for a crypto', example: 'crypto-price ETH' },
|
|
504
|
+
{ cmd: 'track-portfolio', desc: 'Track multiple cryptocurrencies', example: 'track-portfolio BTC ETH XRP' },
|
|
505
|
+
{ cmd: 'crypto-convert', desc: 'Convert between cryptocurrencies', example: 'crypto-convert 1 BTC ETH' },
|
|
506
|
+
{ cmd: 'market-summary', desc: 'Show market summary', example: 'market-summary' },
|
|
507
|
+
{ cmd: 'export-rates', desc: 'Export rates to JSON file', example: 'export-rates rates.json' }
|
|
508
|
+
];
|
|
509
|
+
|
|
510
|
+
console.log(colorizer.cyan('Available Commands:'));
|
|
511
|
+
commands.forEach(({ cmd, desc, example }) => {
|
|
512
|
+
console.log(colorizer.bullet(colorizer.bright(cmd)));
|
|
513
|
+
console.log(colorizer.dim(' ' + desc));
|
|
514
|
+
console.log(colorizer.dim(' Example: ' + example));
|
|
515
|
+
console.log();
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
console.log(colorizer.cyan('Supported Cryptocurrencies:'));
|
|
519
|
+
Object.entries(this.cryptos).forEach(([symbol, info]) => {
|
|
520
|
+
console.log(colorizer.dim(' ' + symbol + ' - ' + info.name));
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
console.log();
|
|
524
|
+
console.log(colorizer.cyan('Supported Exchanges:'));
|
|
525
|
+
Object.entries(this.exchanges).forEach(([key, exchange]) => {
|
|
526
|
+
console.log(colorizer.dim(' ' + exchange.name));
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
console.log();
|
|
530
|
+
console.log(colorizer.warning('Note: Rates are indicative and exclude trading fees'));
|
|
531
|
+
console.log(colorizer.dim('Always verify rates on the actual exchange before trading'));
|
|
532
|
+
console.log();
|
|
533
|
+
|
|
534
|
+
return Promise.resolve();
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Helper: Format price with currency symbol
|
|
539
|
+
*/
|
|
540
|
+
formatPrice(price, currency) {
|
|
541
|
+
const symbols = {
|
|
542
|
+
USD: '$',
|
|
543
|
+
EUR: '€',
|
|
544
|
+
GBP: '£',
|
|
545
|
+
JPY: '¥',
|
|
546
|
+
CAD: 'C$',
|
|
547
|
+
AUD: 'A$'
|
|
548
|
+
};
|
|
549
|
+
|
|
550
|
+
const symbol = symbols[currency] || currency + ' ';
|
|
551
|
+
|
|
552
|
+
if (price >= 1000) {
|
|
553
|
+
return symbol + price.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
|
554
|
+
} else if (price >= 1) {
|
|
555
|
+
return symbol + price.toFixed(2);
|
|
556
|
+
} else if (price >= 0.01) {
|
|
557
|
+
return symbol + price.toFixed(4);
|
|
558
|
+
} else {
|
|
559
|
+
return symbol + price.toFixed(8);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
module.exports = CryptoExchangeChecker;
|