From f7f0765434151d85d31733b420bf4bd74694f7d1 Mon Sep 17 00:00:00 2001 From: cubedro Date: Tue, 5 May 2015 06:59:48 +0300 Subject: [PATCH 1/4] added colors to output --- app.js | 7 +-- lib/node.js | 86 +++++++++++++++++-------------- lib/utils/logger.js | 120 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+), 40 deletions(-) create mode 100644 lib/utils/logger.js diff --git a/app.js b/app.js index 78a769f..1423913 100644 --- a/app.js +++ b/app.js @@ -5,13 +5,14 @@ var nodeModel = require('./lib/node'); var node = new nodeModel(); var gracefulShutdown = function() { - console.warn("Received kill signal, shutting down gracefully."); + console.log(''); + console.error("xxx", "sys", "Received kill signal, shutting down gracefully."); node.stop(); - console.info("Closed node watcher"); + console.info("xxx", "sys", "Closed node watcher"); setTimeout(function(){ - console.info("Closed out remaining connections."); + console.info("xxx", "sys", "Closed out remaining connections."); process.exit(0); }, 5*1000); } diff --git a/lib/node.js b/lib/node.js index 9c3d9fb..303efaf 100644 --- a/lib/node.js +++ b/lib/node.js @@ -1,9 +1,11 @@ 'use strict'; +require('./utils/logger.js'); + +var os = require('os'); var web3 = require('web3'); var async = require('async'); var _ = require('lodash'); -var os = require('os'); var shelljs = require('shelljs'); var debounce = require('debounce'); var registrar = require('./registrar.js'); @@ -46,6 +48,11 @@ if(process.env.NODE_ENV === 'production' && INSTANCE_NAME === "") INSTANCE_NAME = shelljs.exec('ec2metadata --instance-id', {silent: true}).output; } +console.log(''); +console.info('NET STATS CLIENT'); +console.success('v' + pjson.version); +console.log(''); +console.log(''); function Node () { @@ -111,7 +118,7 @@ function Node () Node.prototype.startWeb3Connection = function() { - console.info(chalk.blue('==>'), chalk.bold('Starting eth connection')); + console.info('Starting web3 connection'); web3.setProvider( new web3.providers.HttpProvider('http://' + (process.env.RPC_HOST || 'localhost') + ':' + (process.env.RPC_PORT || '8080')) ); @@ -129,8 +136,8 @@ Node.prototype.checkWeb3Connection = function() if( !_.isUndefined(tmp) ) { - console.log('eth', tmp); - console.info('==>', 'Ethereum connection established'); + console.log(' ', tmp); + console.success('Web3 connection established'); this._web3 = true; this.init(); @@ -140,7 +147,7 @@ Node.prototype.checkWeb3Connection = function() } catch(err) { - console.error('xx>', 'Ethereum connection attempt #' + this._called++ + ' failed;'); + console.error('Web3 connection attempt', chalk.cyan('#' + this._called++), 'failed'); process.nextTick( function() { @@ -152,7 +159,7 @@ Node.prototype.checkWeb3Connection = function() Node.prototype.startSocketConnection = function() { - console.info("==> Starting socket connection"); + console.info('wsc', 'Starting socket connection'); socket = new Socket( process.env.WS_SERVER || 'ws://localhost:3000' ); @@ -166,8 +173,8 @@ Node.prototype.setupSockets = function() // Setup events socket.on('open', function open() { - console.info('==> The connection has been opened.'); - console.info('Trying to login'); + console.info('wsc', 'The connection has been opened.'); + console.log(' ', 'Trying to login'); socket.emit('hello', { id: self.id, @@ -178,7 +185,7 @@ Node.prototype.setupSockets = function() .on('ready', function() { self._socket = true; - console.info('==> The connection has been established.'); + console.success('wsc', 'The connection has been established.'); self.updateBlock(); self.update(true); @@ -189,7 +196,7 @@ Node.prototype.setupSockets = function() }) .on('history', function (data) { - console.info('==> Getting history'); + console.info('wsc', 'Getting history'); var reqHistory = self.getHistory( data ); @@ -210,15 +217,15 @@ Node.prototype.setupSockets = function() .on('end', function end() { self._socket = false; - console.error('xx> Socket connection closed'); + console.error('wsc', 'Socket connection closed'); }) .on('error', function error(err) { - console.error("socket:", err); + console.error('wsc', 'Socket error:', err); }) .on('reconnecting', function reconnecting(opts) { - console.warn('!!!', 'We are scheduling a reconnect operation', opts); + console.warn('wsc', 'We are scheduling a reconnect operation', opts); }); } @@ -230,7 +237,7 @@ Node.prototype.emit = function(message, payload) socket.emit(message, payload); } catch (err) { - console.error("socket.emit:", err); + console.error('wsc', 'Socket emit error:', err); } } } @@ -251,9 +258,8 @@ Node.prototype.setInactive = function() Node.prototype.getInfo = function() { - var start = _.now(); - console.info('==>', 'Getting info'); + console.time('Got info'); try { this.info.coinbase = web3.eth.coinbase; @@ -262,8 +268,8 @@ Node.prototype.getInfo = function() this.info.protocol = web3.toDecimal(web3.version.ethereum); this.info.api = web3.version.api; - console.info('==>', 'Got info in', _.now() - start, 'ms'); - console.info(' i ', this.info); + console.timeEnd('Got info'); + console.info(this.info); return true; } @@ -297,7 +303,7 @@ Node.prototype.getBlock = function(number) } } catch (err) { - console.error("getBlock(" + number + "):", err); + console.error('getBlock(' + chalk.reset.cyan(number) + '):', err); return false; } @@ -349,7 +355,9 @@ Node.prototype.getStats = function(forced) if (this._web3 && (lastFetchAgo >= UPDATE_INTERVAL || forced === true)) { - console.log('==> Getting stats; last update:', lastFetchAgo, '- forced:', (forced === true)); + console.info('==>', 'Getting stats') + console.log(' ', 'last update:', chalk.reset.cyan(lastFetchAgo)); + console.log(' ', 'forced:', chalk.reset.cyan(forced === true)); async.parallel({ start: function (callback) @@ -365,7 +373,7 @@ Node.prototype.getStats = function(forced) peers = web3.toDecimal(web3.net.peerCount); } catch (err) { - console.error('xx> PeerCount failed: ', err); + console.error('xx>', 'PeerCount failed: ', err); callback(err, null); } @@ -375,13 +383,17 @@ Node.prototype.getStats = function(forced) pending: function (callback) { async.nextTick(function () { + var pending; + try { - web3.eth.getBlockTransactionCount('pending', callback); + pending = web3.eth.getBlockTransactionCount('pending'); } catch (err) { - console.error('xx> Pending failed: ', err); + console.error('xx>', 'Pending failed: ', err); callback(err, null); } + + callback(null, pending); }); }, mining: function (callback) @@ -393,7 +405,7 @@ Node.prototype.getStats = function(forced) mining = web3.eth.mining; } catch (err) { - console.error('xx> Mining failed: ', err); + console.error('xx>', 'Mining failed: ', err); callback(err, null); } @@ -409,7 +421,7 @@ Node.prototype.getStats = function(forced) hashrate = web3.eth.hashrate; } catch (err) { - console.error('xx> Hashrate failed: ', err); + console.error('xx>', 'Hashrate failed: ', err); callback(err, null); } @@ -425,7 +437,7 @@ Node.prototype.getStats = function(forced) gasPrice = web3.toBigNumber(web3.eth.gasPrice).toString(10); } catch (err) { - console.error('xx> gasPrice failed: ', err); + console.error('xx>', 'gasPrice failed: ', err); callback(err, null); } @@ -441,7 +453,7 @@ Node.prototype.getStats = function(forced) minerName = self.getMinerName(self.stats.block.miner); } catch (err) { - console.error('xx> minerName failed: ', err); + console.error('xx>', 'minerName failed: ', err); callback(err, null); } @@ -454,7 +466,7 @@ Node.prototype.getStats = function(forced) self._tries++; if (err) { - console.error('xx> getStats error: ', err); + console.error('xx>', 'getStats error: ', err); self.setInactive(); @@ -465,7 +477,7 @@ Node.prototype.getStats = function(forced) results.diff = results.end - results.start; // console.log('==> Got getStats results: ', results); - console.log('==> Got getStats results in', results.diff, 'ms'); + console.success('==>', 'Got getStats results in', chalk.reset.cyan(results.diff, 'ms')); if(results.peers !== null) { @@ -500,12 +512,12 @@ Node.prototype.getStatsBlock = function () if( !_.isUndefined(block) && !_.isUndefined(block.number) && !_.isUndefined(block.hash) && block.hash !== '?' ) { - console.log("==> Got block:", block.number, 'in', end - start, 'ms'); + console.success("==>", "Got block:", chalk.reset.cyan(block.number), 'in', chalk.reset.cyan(end - start, 'ms')); this.stats.block = block; } else { - console.error("xx> getStatsBlock: couldn't fetch block..."); + console.error("xx>", "eth", "getStatsBlock: couldn't fetch block..."); } } @@ -517,7 +529,7 @@ Node.prototype.getHistory = function (range) var history = []; var interv = {}; - console.time('=== Got history in'); + console.time('=H=', 'his', 'Got history in'); if( _.isUndefined(range) || range === null) { @@ -545,7 +557,7 @@ Node.prototype.getHistory = function (range) } } - console.timeEnd('=== Got history in'); + console.timeEnd('=H=', 'his', 'Got history in'); return history.reverse(); } @@ -603,7 +615,7 @@ Node.prototype.setWatches = function() var time = now - self._lastChainLog; self._lastChainLog = now; - console.log('>>> Chain Filter triggered: ', now, '- last trigger:', time); + console.info('>>>', 'Chain Filter triggered: ', chalk.reset.cyan(now), '- last trigger:', chalk.reset.cyan(time)); if(time > 50) { @@ -631,7 +643,7 @@ Node.prototype.setWatches = function() var time = now - self._lastPendingLog; self._lastPendingLog = now; - console.log('>>> Pending Filter triggered: ', now, '- last trigger:', time); + console.info('>>>', 'Pending Filter triggered', chalk.reset.cyan(now), '- last trigger:', chalk.reset.cyan(time)); if(time > 50) { @@ -668,11 +680,11 @@ Node.prototype.installContract = function() Contract = web3.eth.contract( registrar.desc ); this._Registrar = new Contract( registrar.address ); - console.log('==>', 'Installed Registrar contract in', _.now() - start, 'ms'); + console.success('Installed Registrar contract in', chalk.reset.cyan(_.now() - start, 'ms')); } catch (err) { - console.error("!!!", "Couldn't set up registrar contract"); + console.error("!!!", "eth", "Couldn't set up registrar contract"); console.error(err); } } diff --git a/lib/utils/logger.js b/lib/utils/logger.js new file mode 100644 index 0000000..fc2d736 --- /dev/null +++ b/lib/utils/logger.js @@ -0,0 +1,120 @@ +'use strict'; + +var util = require('util'); +var chalk = require('chalk'); + +var signs = [ + '==>', + '!!!', + 'xx>', + '===', + '>>>', + 'xxx' +]; + +var types = [ + 'eth', + 'wsc', + 'sys', + 'his' +]; + +[ + { + name: "info", + sign: '=i=', + signColor: chalk.blue, + messageColor: chalk.bold, + formatter: function (sign, message) + { + return [sign, message]; + } + }, + { + name: "success", + inherit: 'log', + sign: '=s=', + signColor: chalk.green, + messageColor: chalk.bold.green, + formatter: function (sign, message) + { + return [sign, message]; + } + }, + { + name: "warn", + sign: '=!=', + signColor: chalk.yellow, + messageColor: chalk.bold.yellow, + formatter: function (sign, message) + { + return [sign, message]; + } + }, + { + name: "error", + sign: '=x=', + signColor: chalk.red, + messageColor: chalk.bold.red, + formatter: function (sign, message) + { + return [sign, message]; + } + }, + { + name: "time", + sign: '=T=', + signColor: chalk.cyan, + messageColor: chalk.bold, + formatter: function (sign, message) + { + return [util.format.apply(util, [sign, message])]; + } + }, + { + name: "timeEnd", + sign: '=T=', + signColor: chalk.cyan, + messageColor: chalk.bold, + formatter: function (sign, message) + { + return [util.format.apply(util, [sign, message])]; + } + } +].forEach( function (item) +{ + if(item.inherit !== undefined) + console[item.name] = console[item.inherit]; + + var fn = console[item.name]; + + console[item.name] = function () + { + var args = Array.prototype.slice.call(arguments); + var sign = item.sign; + var section = 'eth'; + var message = ''; + + if (signs.indexOf(args[0]) >= 0) + { + sign = args.splice(0, 1); + } + + if (types.indexOf(args[0]) >= 0) + { + section = args.splice(0, 1); + } + + sign = item.signColor( '[' + section + '] ' + sign ); + + if (typeof args[0] === 'object') + { + message = util.inspect( args[0], { depth: null, colors: true } ); + } + else { + message = item.messageColor( util.format.apply(util, args) ); + } + + return fn.apply( this, item.formatter(sign, message) ); + } +}); \ No newline at end of file From 592cd235002a87055c305029599dac7281d99620 Mon Sep 17 00:00:00 2001 From: cubedro Date: Tue, 5 May 2015 09:04:27 +0300 Subject: [PATCH 2/4] refactoring --- lib/node.js | 237 ++++++++++++++++++++++---------------------- lib/utils/logger.js | 3 +- 2 files changed, 120 insertions(+), 120 deletions(-) diff --git a/lib/node.js b/lib/node.js index 303efaf..03e4117 100644 --- a/lib/node.js +++ b/lib/node.js @@ -129,7 +129,7 @@ Node.prototype.checkWeb3Connection = function() { var self = this; - if(!this._web3) + if (!this._web3) { try { var tmp = web3.version.client; @@ -145,11 +145,11 @@ Node.prototype.checkWeb3Connection = function() return true; } } - catch(err) + catch (err) { console.error('Web3 connection attempt', chalk.cyan('#' + this._called++), 'failed'); - process.nextTick( function() + process.nextTick(function () { self.checkWeb3Connection(); }); @@ -196,7 +196,7 @@ Node.prototype.setupSockets = function() }) .on('history', function (data) { - console.info('wsc', 'Getting history'); + console.info('his', 'Got history request'); var reqHistory = self.getHistory( data ); @@ -242,20 +242,6 @@ Node.prototype.emit = function(message, payload) } } -Node.prototype.setInactive = function() -{ - this.stats.active = false; - this.stats.peers = 0; - this.stats.pending = 0; - this.stats.mining = false; - this.stats.hashrate = 0; - this.stats.gasPrice = 0; - this.stats.miner = false; - this._down++; - - return this; -} - Node.prototype.getInfo = function() { console.info('==>', 'Getting info'); @@ -280,6 +266,25 @@ Node.prototype.getInfo = function() return false; } +Node.prototype.setInactive = function() +{ + this.stats.active = false; + this.stats.peers = 0; + this.stats.pending = 0; + this.stats.mining = false; + this.stats.hashrate = 0; + this.stats.gasPrice = 0; + this.stats.minerName = false; + this._down++; + + return this; +} + +Node.prototype.setUptime = function() +{ + this.stats.uptime = ((this._tries - this._down) / this._tries) * 100; +} + Node.prototype.getBlock = function(number) { var block = { @@ -294,13 +299,7 @@ Node.prototype.getBlock = function(number) number = "latest"; try { - block = web3.eth.getBlock(number, true); - - if( block.hash != '?' && !_.isUndefined(block.difficulty) && !_.isUndefined(block.totalDifficulty) ) - { - block.difficulty = web3.toDecimal( block.difficulty ); - block.totalDifficulty = web3.toDecimal( block.totalDifficulty ); - } + block = this.formatBlock( web3.eth.getBlock(number, true) ); } catch (err) { console.error('getBlock(' + chalk.reset.cyan(number) + '):', err); @@ -311,36 +310,42 @@ Node.prototype.getBlock = function(number) return block; } -Node.prototype.getMinerName = function(miner) +Node.prototype.formatBlock = function (block) { - var result = _.find(this._knownMiners, { miner: miner }); - - if (result !== undefined) + if( !_.isUndefined(block) && !_.isUndefined(block.number) && block.number >= 0 && !_.isUndefined(block.difficulty) && !_.isUndefined(block.totalDifficulty) ) { - return result.name; - } - else - { - if (this._Registrar !== null) - { - var name = this._Registrar.name(miner); + block.difficulty = web3.toDecimal( block.difficulty ); + block.totalDifficulty = web3.toDecimal( block.totalDifficulty ); - if(name.length > 0) - { - this._knownMiners.push({ miner: miner, name: name }); - return name; - } - } - - this._knownMiners.push({ miner: miner, name: false }); + return block; } return false; } -Node.prototype.uptime = function() +Node.prototype.getStatsBlock = function () { - this.stats.uptime = ((this._tries - this._down) / this._tries) * 100; + if(this._socket) + this._lastStats = JSON.stringify(this.stats); + + if(this._web3) + { + var start = _.now(); + var block = this.getBlock(); + + if( block ) + { + this.stats.block = block; + console.success("==>", "Got block:", chalk.reset.cyan(block.number), 'in', chalk.reset.cyan(_.now() - start, 'ms')); + + this.sendUpdate(); + } + else + { + console.error("xx>", "getStatsBlock couldn't fetch block..."); + console.log(block); + } + } } Node.prototype.getStats = function(forced) @@ -383,17 +388,13 @@ Node.prototype.getStats = function(forced) pending: function (callback) { async.nextTick(function () { - var pending; - try { - pending = web3.eth.getBlockTransactionCount('pending'); + web3.eth.getBlockTransactionCount('pending', callback); } catch (err) { console.error('xx>', 'Pending failed: ', err); callback(err, null); } - - callback(null, pending); }); }, mining: function (callback) @@ -414,19 +415,24 @@ Node.prototype.getStats = function(forced) }, hashrate: function (callback) { - async.nextTick(function () { - var hashrate; + if(self.stats.mining) { + async.nextTick(function () { + var hashrate; - try { - hashrate = web3.eth.hashrate; - } - catch (err) { - console.error('xx>', 'Hashrate failed: ', err); - callback(err, null); - } + try { + hashrate = web3.eth.hashrate; + } + catch (err) { + console.error('xx>', 'Hashrate failed: ', err); + callback(err, null); + } - callback(null, hashrate); - }); + callback(null, hashrate); + }); + } + else { + callback(null, 0); + } }, gasPrice: function (callback) { @@ -444,22 +450,22 @@ Node.prototype.getStats = function(forced) callback(null, gasPrice); }); }, - minerName: function (callback) - { - async.nextTick(function () { - var minerName; + // minerName: function (callback) + // { + // async.nextTick(function () { + // var minerName; - try { - minerName = self.getMinerName(self.stats.block.miner); - } - catch (err) { - console.error('xx>', 'minerName failed: ', err); - callback(err, null); - } + // try { + // minerName = self.getMinerName(self.stats.block.miner); + // } + // catch (err) { + // console.error('xx>', 'minerName failed: ', err); + // callback(err, null); + // } - callback(null, minerName); - }); - } + // callback(null, minerName); + // }); + // } }, function (err, results) { @@ -476,7 +482,6 @@ Node.prototype.getStats = function(forced) results.end = _.now(); results.diff = results.end - results.start; - // console.log('==> Got getStats results: ', results); console.success('==>', 'Got getStats results in', chalk.reset.cyan(results.diff, 'ms')); if(results.peers !== null) @@ -492,38 +497,13 @@ Node.prototype.getStats = function(forced) self.setInactive(); } - self.uptime(); + self.setUptime(); self.sendUpdate(); }); } } -Node.prototype.getStatsBlock = function () -{ - if(this._socket) - this._lastStats = JSON.stringify(this.stats); - - if(this._web3) - { - var start = _.now(); - var block = this.getBlock(); - var end = _.now(); - - if( !_.isUndefined(block) && !_.isUndefined(block.number) && !_.isUndefined(block.hash) && block.hash !== '?' ) - { - console.success("==>", "Got block:", chalk.reset.cyan(block.number), 'in', chalk.reset.cyan(end - start, 'ms')); - this.stats.block = block; - } - else - { - console.error("xx>", "eth", "getStatsBlock: couldn't fetch block..."); - } - } - - this.sendUpdate(); -} - Node.prototype.getHistory = function (range) { var history = []; @@ -531,25 +511,17 @@ Node.prototype.getHistory = function (range) console.time('=H=', 'his', 'Got history in'); - if( _.isUndefined(range) || range === null) - { - interv = { - min: this.stats.block.number - MAX_HISTORY_UPDATE, - max: this.stats.block.number - 1 - }; - } + if ( _.isUndefined(range) || range === null) + interv = _.range(this.stats.block.number - 1, MAX_HISTORY_UPDATE); - if( !_.isUndefined(range.list) ) - { - interv = { - min: 0, - max: range.list.length - 1 - }; - } + if (!_.isUndefined(range.list)) + interv = range.list; - for (var i = interv.min; i <= interv.max; i++) + console.info('his', 'Getting history from', chalk.reset.cyan(interv[0]), 'to', chalk.reset.cyan(interv[interv.length - 1])); + + for (var i = 0; i < interv.length; i++) { - var block = this.getBlock(( !_.isUndefined(range.list) ? range.list[i] : i)); + var block = this.getBlock( interv[i] ); if( block !== null && !_.isUndefined(block.number) ) { @@ -562,6 +534,33 @@ Node.prototype.getHistory = function (range) return history.reverse(); } +Node.prototype.getMinerName = function(miner) +{ + var result = _.find(this._knownMiners, { miner: miner }); + + if (result !== undefined) + { + return result.name; + } + else + { + if (this._Registrar !== null) + { + var name = this._Registrar.name(miner); + + if(name.length > 0) + { + this._knownMiners.push({ miner: miner, name: name }); + return name; + } + } + + this._knownMiners.push({ miner: miner, name: false }); + } + + return false; +} + Node.prototype.updateBlock = function() { this.getStatsBlock(); diff --git a/lib/utils/logger.js b/lib/utils/logger.js index fc2d736..371e9bc 100644 --- a/lib/utils/logger.js +++ b/lib/utils/logger.js @@ -9,7 +9,8 @@ var signs = [ 'xx>', '===', '>>>', - 'xxx' + 'xxx', + '=H=' ]; var types = [ From 66aad76047da0641651fc0c2e2fea87ea3d16e25 Mon Sep 17 00:00:00 2001 From: cubedro Date: Tue, 5 May 2015 09:24:27 +0300 Subject: [PATCH 3/4] made history call async --- lib/node.js | 46 +++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/lib/node.js b/lib/node.js index 03e4117..b2b50c2 100644 --- a/lib/node.js +++ b/lib/node.js @@ -198,12 +198,7 @@ Node.prototype.setupSockets = function() { console.info('his', 'Got history request'); - var reqHistory = self.getHistory( data ); - - socket.emit('history', { - id: self.id, - history: reqHistory - }); + self.getHistory( data ); }) .on('node-pong', function(data) { @@ -506,6 +501,8 @@ Node.prototype.getStats = function(forced) Node.prototype.getHistory = function (range) { + var self = this; + var history = []; var interv = {}; @@ -519,19 +516,38 @@ Node.prototype.getHistory = function (range) console.info('his', 'Getting history from', chalk.reset.cyan(interv[0]), 'to', chalk.reset.cyan(interv[interv.length - 1])); - for (var i = 0; i < interv.length; i++) + async.mapSeries(interv, function (number, callback) { - var block = this.getBlock( interv[i] ); - - if( block !== null && !_.isUndefined(block.number) ) + async.nextTick(function () { - history.push( block ); + var block; + + try { + block = self.formatBlock(web3.eth.getBlock(number, true)); + } + catch (err) { + console.error('xx>', 'history block failed: ', err); + callback(err, null); + } + + callback(null, block); + }); + }, + function (err, results) + { + console.timeEnd('=H=', 'his', 'Got history in'); + + if (err) { + console.error('his', 'history fetch failed:', err); + + results = false; } - } - console.timeEnd('=H=', 'his', 'Got history in'); - - return history.reverse(); + socket.emit('history', { + id: self.id, + history: results.reverse() + }); + }); } Node.prototype.getMinerName = function(miner) From 7c192acebdeb788b88bffdf5607cb922cdd2f9a3 Mon Sep 17 00:00:00 2001 From: cubedro Date: Tue, 5 May 2015 09:25:07 +0300 Subject: [PATCH 4/4] version 0.0.8 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e2772ad..9aa8ca5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "eth-net-intelligence-api", "description": "Ethereum Network Intelligence API", - "version": "0.0.7", + "version": "0.0.8", "private": true, "main": "./app.js", "directories": {