├── .gitignore ├── LICENSE ├── README.md ├── config.json ├── index.js ├── lib ├── actions.js ├── eosApi.js └── pushers.js ├── package.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | .lastblock 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Leo Ribeiro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EOS Node Watcher 2 | 3 | The goal of this watcher is to easily replay chains from the desired block (let's 4 | say after you deploy your contract is what usually matters), filter the block actions 5 | related to your desired contracts and submit it to your desired channel: message 6 | queues, websockets, databases etc. 7 | 8 | ## Setup 9 | 10 | ``` 11 | cd ~ 12 | git clone https://github.com/leordev/eos-node-watcher 13 | cd eos-node-watcher 14 | npm install 15 | vi config.json # here you will customize the setup to your needs 16 | node index.js 17 | ``` 18 | 19 | ## Configuration 20 | 21 | Here's the default configuration example 22 | 23 | ``` 24 | { 25 | "watchInterval": 500, 26 | "eosApi": "http://mainnet.eoscalgary.io/v1", 27 | "eosHistoryApi": "http://api.cypherglass.com/v1", 28 | "apiTimeout": 3000, 29 | "initialBlock": 1293913, 30 | "accounts": { 31 | "monstereosio": [], # leave an empty array to listen to all the actions 32 | "eosio.token": [ # here you can filter all the actions 33 | { 34 | "name": "transfer", 35 | "data": { "to": "monstereosio" } # (optional) if you set the data, it 36 | } # will filter the actions parameters 37 | ] 38 | }, 39 | "mongodb": { 40 | "isActive": true, 41 | "address": "mongodb://localhost:27017", 42 | "database": "eos_node_watcher", 43 | "prefix": "enw_" 44 | }, 45 | "zeromq": { 46 | "isActive": false, 47 | "address": "tcp://*:60400" 48 | }, 49 | "amqp": { 50 | "isActive": true, 51 | "address": "amqp://localhost", 52 | "channel": "eosnodewatcher" 53 | } 54 | } 55 | ``` 56 | 57 | ## Next Steps 58 | 59 | 1. Add more "pusher" options and possibily split that file to single pusher per file 60 | 2. Improve the action filters (test for vectors and add some "sql-style" options eg. LIKE `%` etc.) 61 | 3. ??? Accepting ideas! :) 62 | 63 | Feel free to fork, collaborate and add ideas! 64 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "watchInterval": 500, 3 | "eosApi": "http://mainnet.eoscalgary.io/v1", 4 | "eosHistoryApi": [ 5 | "https://api.cypherglass.com/v1", 6 | "http://fn.eossweden.se/v1", 7 | "http://api.hkeos.com/v1", 8 | "https://api1.eosasia.one/v1" 9 | ], 10 | "apiTimeout": 3000, 11 | "initialBlock": 1293913, 12 | "accounts": { 13 | "monstereosio": [], 14 | "eosio.token": [ 15 | { 16 | "name": "transfer", 17 | "data": { "to": "monstereosio" } 18 | } 19 | ] 20 | }, 21 | "mongodb": { 22 | "isActive": true, 23 | "address": "mongodb://localhost:27017", 24 | "database": "eos_node_watcher", 25 | "prefix": "enw_" 26 | }, 27 | "zeromq": { 28 | "isActive": false, 29 | "address": "tcp://*:60400" 30 | }, 31 | "amqp": { 32 | "isActive": true, 33 | "address": "amqp://localhost", 34 | "channel": "eosnodewatcher" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const logger = require('simple-node-logger').createSimpleLogger() 4 | const nconf = require('nconf') 5 | const fs = require('fs') 6 | 7 | const LAST_BLOCK_FILE = '.lastblock' 8 | 9 | let pushers = null 10 | 11 | nconf.argv().env('__') 12 | nconf.defaults({conf: `${__dirname}/config.json`}) 13 | nconf.file(nconf.get('conf')) 14 | 15 | const api = require('./lib/eosApi')(nconf.get('eosApi'), nconf.get('eosHistoryApi'), nconf.get('apiTimeout')) 16 | const actions = require('./lib/actions')(nconf.get('accounts')) 17 | 18 | const watchInterval = nconf.get('watchInterval') 19 | 20 | let lastChainInfo = null 21 | let nextSyncBlock = nconf.get('initialBlock') 22 | let isSyncing = true 23 | 24 | const mainLoop = async () => { 25 | 26 | if (!pushers) 27 | pushers = await require('./lib/pushers')(logger, nconf.get('zeromq'), nconf.get('mongodb'), nconf.get('amqp')) 28 | 29 | const currentBlock = nextSyncBlock 30 | logger.info(`Syncing block ${currentBlock}`) 31 | 32 | try { 33 | if (lastChainInfo == null || nextSyncBlock <= lastChainInfo.head_block_num) { 34 | lastChainInfo = await api.getChainInfo() 35 | } 36 | 37 | if (lastChainInfo && lastChainInfo.head_block_num >= nextSyncBlock) { 38 | const blockInfo = await api.getBlockInfo(nextSyncBlock) 39 | const transactionsIds = actions.filteredTransactionsIds(blockInfo) 40 | const transactions = transactionsIds && transactionsIds.length ? 41 | await api.getBulkTransactions(transactionsIds) : null 42 | 43 | if (transactions && transactions.length) { 44 | pushTransactions(transactions) 45 | } 46 | 47 | await saveLastBlock() 48 | nextSyncBlock++ 49 | } 50 | } catch (err) { 51 | const { message } = err 52 | logger.error(`Sync failed on block ${currentBlock} >>> `, 53 | message || err || 'Unknown Error') 54 | } 55 | 56 | isSyncing = !lastChainInfo || lastChainInfo.head_block_num > nextSyncBlock 57 | 58 | isSyncing ? setImmediate(mainLoop) 59 | : setTimeout(mainLoop, watchInterval) 60 | } 61 | 62 | const saveLastBlock = () => { 63 | return new Promise((resolve, reject) => { 64 | fs.writeFile(LAST_BLOCK_FILE, nextSyncBlock, (err) => { 65 | if (err) 66 | reject(err) 67 | else 68 | resolve(true) 69 | }); 70 | }) 71 | } 72 | 73 | const pushTransactions = transactions => { 74 | return Promise.all(pushers.map(p => p(transactions))) 75 | } 76 | 77 | fs.readFile(LAST_BLOCK_FILE, (err,data) => { 78 | if (err) { 79 | logger.info(`Blocks were never synced, starting from ${nextSyncBlock}`) 80 | } else { 81 | nextSyncBlock = Number(data) + 1 82 | logger.info(`Last synced block: ${nextSyncBlock} - resyncing...`) 83 | } 84 | mainLoop() 85 | }) 86 | 87 | -------------------------------------------------------------------------------- /lib/actions.js: -------------------------------------------------------------------------------- 1 | let accounts = {} 2 | 3 | const actionFiltered = (listeningActions, action) => { 4 | const listeningAction = listeningActions.find(a => a.name === action.name) 5 | 6 | if (!listeningAction) 7 | return false 8 | 9 | if (listeningAction && listeningAction.data) { 10 | let valids = 0, total = 0 11 | for (const key in listeningAction.data) { 12 | total++ 13 | if (listeningAction.data[key] === action.data[key]) 14 | valids++ 15 | } 16 | 17 | return valids === total 18 | } else { 19 | return true 20 | } 21 | 22 | } 23 | 24 | const isValidAction = action => { 25 | const contractActions = accounts[action.account] 26 | return contractActions && 27 | (contractActions.length === 0 || 28 | actionFiltered(contractActions, action)) 29 | } 30 | 31 | const filteredTransactionsIds = block => { 32 | if (!block || !block.transactions || !block.transactions.length) 33 | return 34 | 35 | const { transactions, block_num } = block 36 | 37 | return transactions 38 | .filter(transaction => { 39 | return transaction.trx && transaction.trx.transaction && 40 | transaction.trx.transaction.actions && 41 | transaction.trx.transaction.actions.length > 0 && 42 | transaction.trx.transaction.actions.filter(isValidAction).length > 0 43 | }).map(t => t.trx.id) 44 | } 45 | 46 | module.exports = (accountsParam) => { 47 | accounts = accountsParam 48 | return { filteredTransactionsIds } 49 | } 50 | -------------------------------------------------------------------------------- /lib/eosApi.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios') 2 | 3 | let apiUrl = '' 4 | let historyApiUrl = '' 5 | let timeout = 0 6 | 7 | const getChainInfo = () => { 8 | return axios.get(apiUrl + '/chain/get_info', {timeout}) 9 | .then(res => res.data) 10 | } 11 | 12 | const getBlockInfo = blockNum => { 13 | return axios.post( 14 | apiUrl + '/chain/get_block', 15 | {block_num_or_id: blockNum}, 16 | {timeout} 17 | ).then(res => res.data) 18 | } 19 | 20 | const getTransaction = id => { 21 | randomApi = historyApiUrl[Math.floor(Math.random()*historyApiUrl.length)] 22 | return axios.post( 23 | randomApi + '/history/get_transaction', 24 | {id}, 25 | {timeout} 26 | ).then(res => res.data) 27 | } 28 | 29 | const getBulkTransactions = ids => { 30 | const transactionsPromises = ids.map(getTransaction) 31 | return Promise.all(transactionsPromises) 32 | } 33 | 34 | module.exports = (url, historyUrl, apiTimeout = 3000) => { 35 | apiUrl = url 36 | historyApiUrl = historyUrl 37 | timeout = apiTimeout 38 | return { getChainInfo, getBlockInfo, getTransaction, getBulkTransactions } 39 | } 40 | -------------------------------------------------------------------------------- /lib/pushers.js: -------------------------------------------------------------------------------- 1 | const zeromq = require('zeromq') 2 | const amqp = require('amqplib/callback_api') 3 | const mongodb = require('mongodb') 4 | 5 | module.exports = async (logger, zmqConf, mongoConf, amqpConf) => { 6 | const pushers = [] 7 | 8 | if (zmqConf.isActive) { 9 | const zmqPublisher = zeromq.socket('pub') 10 | zmqPublisher.bind(zmqConf.address, err => { 11 | if (err) throw err; 12 | logger.info('Listening for zmq subscribers...'); 13 | }) 14 | 15 | pushers.push(transactions => { 16 | transactions.forEach(transaction => { 17 | zmqPublisher.send(JSON.stringify(transaction)) 18 | }) 19 | logger.info(`${transactions.length} transaction(s) pushed to ZeroMQ`) 20 | }) 21 | 22 | } 23 | 24 | if (amqpConf.isActive) { 25 | const amqpSetup = new Promise((resolve, reject) => { 26 | amqp.connect(amqpConf.address, (err, conn) => { 27 | if (err) reject(err) 28 | conn.createChannel(function(err, ch) { 29 | if (err) reject(err) 30 | resolve(ch) 31 | }) 32 | }) 33 | }) 34 | 35 | const channel = await amqpSetup 36 | 37 | pushers.push(transactions => { 38 | transactions.forEach(t => channel.sendToQueue(amqpConf.channel, new Buffer(JSON.stringify(t)))) 39 | logger.info(`${transactions.length} transaction(s) pushed to AMQP`) 40 | }) 41 | } 42 | 43 | if (mongoConf.isActive) { 44 | const mongoClient = mongodb.MongoClient 45 | 46 | const mongoSetup = new Promise((resolve, reject) => { 47 | mongoClient.connect(mongoConf.address, (err, client) => { 48 | if (err) reject(err) 49 | 50 | const db = client.db(mongoConf.database) 51 | 52 | pushers.push(transactions => { 53 | return new Promise((resolve, reject) => { 54 | db.collection(`${mongoConf.prefix || ''}transactions`) 55 | .insertMany(transactions, (err, res) => { 56 | if (err) { 57 | reject(err) 58 | } else { 59 | logger.info(`${res.result.n} transaction(s) inserted to MongoDB`) 60 | resolve(true) 61 | } 62 | }) 63 | }) 64 | }) 65 | resolve(true) 66 | }) 67 | }) 68 | 69 | await mongoSetup 70 | } 71 | 72 | return pushers 73 | } 74 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eos-node-watcher", 3 | "version": "0.1.0", 4 | "description": "Watches EOS Blocks and Serve/Persist", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Leo Ribeiro", 10 | "license": "MIT", 11 | "dependencies": { 12 | "amqplib": "^0.5.2", 13 | "axios": "^0.18.0", 14 | "mongodb": "^3.1.1", 15 | "nconf": "^0.10.0", 16 | "simple-node-logger": "^0.93.37", 17 | "zeromq": "^4.6.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | amqplib@^0.5.2: 6 | version "0.5.2" 7 | resolved "https://registry.yarnpkg.com/amqplib/-/amqplib-0.5.2.tgz#d2d7313c7ffaa4d10bcf1e6252de4591b6cc7b63" 8 | dependencies: 9 | bitsyntax "~0.0.4" 10 | bluebird "^3.4.6" 11 | buffer-more-ints "0.0.2" 12 | readable-stream "1.x >=1.1.9" 13 | safe-buffer "^5.0.1" 14 | 15 | ansi-regex@^2.0.0: 16 | version "2.1.1" 17 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 18 | 19 | ansi-regex@^3.0.0: 20 | version "3.0.0" 21 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" 22 | 23 | aproba@^1.0.3: 24 | version "1.2.0" 25 | resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" 26 | 27 | are-we-there-yet@~1.1.2: 28 | version "1.1.5" 29 | resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" 30 | dependencies: 31 | delegates "^1.0.0" 32 | readable-stream "^2.0.6" 33 | 34 | async@^1.4.0: 35 | version "1.5.2" 36 | resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" 37 | 38 | axios@^0.18.0: 39 | version "0.18.0" 40 | resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.0.tgz#32d53e4851efdc0a11993b6cd000789d70c05102" 41 | dependencies: 42 | follow-redirects "^1.3.0" 43 | is-buffer "^1.1.5" 44 | 45 | bitsyntax@~0.0.4: 46 | version "0.0.4" 47 | resolved "https://registry.yarnpkg.com/bitsyntax/-/bitsyntax-0.0.4.tgz#eb10cc6f82b8c490e3e85698f07e83d46e0cba82" 48 | dependencies: 49 | buffer-more-ints "0.0.2" 50 | 51 | bl@^1.0.0: 52 | version "1.2.2" 53 | resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" 54 | dependencies: 55 | readable-stream "^2.3.5" 56 | safe-buffer "^5.1.1" 57 | 58 | bluebird@^3.4.6: 59 | version "3.5.1" 60 | resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" 61 | 62 | bson@~1.0.4: 63 | version "1.0.9" 64 | resolved "https://registry.yarnpkg.com/bson/-/bson-1.0.9.tgz#12319f8323b1254739b7c6bef8d3e89ae05a2f57" 65 | 66 | buffer-alloc-unsafe@^1.1.0: 67 | version "1.1.0" 68 | resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" 69 | 70 | buffer-alloc@^1.1.0: 71 | version "1.2.0" 72 | resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" 73 | dependencies: 74 | buffer-alloc-unsafe "^1.1.0" 75 | buffer-fill "^1.0.0" 76 | 77 | buffer-fill@^1.0.0: 78 | version "1.0.0" 79 | resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" 80 | 81 | buffer-more-ints@0.0.2: 82 | version "0.0.2" 83 | resolved "https://registry.yarnpkg.com/buffer-more-ints/-/buffer-more-ints-0.0.2.tgz#26b3885d10fa13db7fc01aae3aab870199e0124c" 84 | 85 | camelcase@^2.0.1: 86 | version "2.1.1" 87 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" 88 | 89 | chownr@^1.0.1: 90 | version "1.0.1" 91 | resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" 92 | 93 | cliui@^3.0.3: 94 | version "3.2.0" 95 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" 96 | dependencies: 97 | string-width "^1.0.1" 98 | strip-ansi "^3.0.1" 99 | wrap-ansi "^2.0.0" 100 | 101 | code-point-at@^1.0.0: 102 | version "1.1.0" 103 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" 104 | 105 | console-control-strings@^1.0.0, console-control-strings@~1.1.0: 106 | version "1.1.0" 107 | resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" 108 | 109 | core-util-is@~1.0.0: 110 | version "1.0.2" 111 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 112 | 113 | debug@^3.1.0: 114 | version "3.1.0" 115 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" 116 | dependencies: 117 | ms "2.0.0" 118 | 119 | decamelize@^1.1.1: 120 | version "1.2.0" 121 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" 122 | 123 | decompress-response@^3.3.0: 124 | version "3.3.0" 125 | resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" 126 | dependencies: 127 | mimic-response "^1.0.0" 128 | 129 | deep-extend@^0.6.0: 130 | version "0.6.0" 131 | resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" 132 | 133 | delegates@^1.0.0: 134 | version "1.0.0" 135 | resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" 136 | 137 | detect-libc@^1.0.3: 138 | version "1.0.3" 139 | resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" 140 | 141 | end-of-stream@^1.0.0, end-of-stream@^1.1.0: 142 | version "1.4.1" 143 | resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" 144 | dependencies: 145 | once "^1.4.0" 146 | 147 | expand-template@^1.0.2: 148 | version "1.1.1" 149 | resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-1.1.1.tgz#981f188c0c3a87d2e28f559bc541426ff94f21dd" 150 | 151 | follow-redirects@^1.3.0: 152 | version "1.5.1" 153 | resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.1.tgz#67a8f14f5a1f67f962c2c46469c79eaec0a90291" 154 | dependencies: 155 | debug "^3.1.0" 156 | 157 | fs-constants@^1.0.0: 158 | version "1.0.0" 159 | resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" 160 | 161 | gauge@~2.7.3: 162 | version "2.7.4" 163 | resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" 164 | dependencies: 165 | aproba "^1.0.3" 166 | console-control-strings "^1.0.0" 167 | has-unicode "^2.0.0" 168 | object-assign "^4.1.0" 169 | signal-exit "^3.0.0" 170 | string-width "^1.0.1" 171 | strip-ansi "^3.0.1" 172 | wide-align "^1.1.0" 173 | 174 | github-from-package@0.0.0: 175 | version "0.0.0" 176 | resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" 177 | 178 | has-unicode@^2.0.0: 179 | version "2.0.1" 180 | resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" 181 | 182 | inherits@~2.0.1, inherits@~2.0.3: 183 | version "2.0.3" 184 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 185 | 186 | ini@^1.3.0, ini@~1.3.0: 187 | version "1.3.5" 188 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" 189 | 190 | invert-kv@^1.0.0: 191 | version "1.0.0" 192 | resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" 193 | 194 | is-buffer@^1.1.5: 195 | version "1.1.6" 196 | resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" 197 | 198 | is-fullwidth-code-point@^1.0.0: 199 | version "1.0.0" 200 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" 201 | dependencies: 202 | number-is-nan "^1.0.0" 203 | 204 | is-fullwidth-code-point@^2.0.0: 205 | version "2.0.0" 206 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" 207 | 208 | isarray@0.0.1: 209 | version "0.0.1" 210 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" 211 | 212 | isarray@~1.0.0: 213 | version "1.0.0" 214 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 215 | 216 | lcid@^1.0.0: 217 | version "1.0.0" 218 | resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" 219 | dependencies: 220 | invert-kv "^1.0.0" 221 | 222 | lodash@^4.17.2: 223 | version "4.17.10" 224 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" 225 | 226 | mimic-response@^1.0.0: 227 | version "1.0.1" 228 | resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" 229 | 230 | minimist@0.0.8: 231 | version "0.0.8" 232 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 233 | 234 | minimist@^1.2.0: 235 | version "1.2.0" 236 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" 237 | 238 | mkdirp@^0.5.1: 239 | version "0.5.1" 240 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 241 | dependencies: 242 | minimist "0.0.8" 243 | 244 | moment@^2.20.1: 245 | version "2.22.2" 246 | resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66" 247 | 248 | mongodb-core@3.1.0: 249 | version "3.1.0" 250 | resolved "https://registry.yarnpkg.com/mongodb-core/-/mongodb-core-3.1.0.tgz#af91f36fd560ed785f4e61e694432df4d3698aad" 251 | dependencies: 252 | bson "~1.0.4" 253 | require_optional "^1.0.1" 254 | optionalDependencies: 255 | saslprep "^1.0.0" 256 | 257 | mongodb@^3.1.1: 258 | version "3.1.1" 259 | resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-3.1.1.tgz#c018c4b277614e8b1e08426d5bcbe1a7e5cdbd74" 260 | dependencies: 261 | mongodb-core "3.1.0" 262 | 263 | ms@2.0.0: 264 | version "2.0.0" 265 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 266 | 267 | nan@^2.6.2: 268 | version "2.10.0" 269 | resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" 270 | 271 | nconf@^0.10.0: 272 | version "0.10.0" 273 | resolved "https://registry.yarnpkg.com/nconf/-/nconf-0.10.0.tgz#da1285ee95d0a922ca6cee75adcf861f48205ad2" 274 | dependencies: 275 | async "^1.4.0" 276 | ini "^1.3.0" 277 | secure-keys "^1.0.0" 278 | yargs "^3.19.0" 279 | 280 | node-abi@^2.2.0: 281 | version "2.4.3" 282 | resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.4.3.tgz#43666b7b17e57863e572409edbb82115ac7af28b" 283 | dependencies: 284 | semver "^5.4.1" 285 | 286 | noop-logger@^0.1.1: 287 | version "0.1.1" 288 | resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" 289 | 290 | npmlog@^4.0.1: 291 | version "4.1.2" 292 | resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" 293 | dependencies: 294 | are-we-there-yet "~1.1.2" 295 | console-control-strings "~1.1.0" 296 | gauge "~2.7.3" 297 | set-blocking "~2.0.0" 298 | 299 | number-is-nan@^1.0.0: 300 | version "1.0.1" 301 | resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" 302 | 303 | object-assign@^4.1.0: 304 | version "4.1.1" 305 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 306 | 307 | once@^1.3.1, once@^1.4.0: 308 | version "1.4.0" 309 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 310 | dependencies: 311 | wrappy "1" 312 | 313 | os-homedir@^1.0.1: 314 | version "1.0.2" 315 | resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" 316 | 317 | os-locale@^1.4.0: 318 | version "1.4.0" 319 | resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" 320 | dependencies: 321 | lcid "^1.0.0" 322 | 323 | prebuild-install@^2.2.2: 324 | version "2.5.3" 325 | resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-2.5.3.tgz#9f65f242782d370296353710e9bc843490c19f69" 326 | dependencies: 327 | detect-libc "^1.0.3" 328 | expand-template "^1.0.2" 329 | github-from-package "0.0.0" 330 | minimist "^1.2.0" 331 | mkdirp "^0.5.1" 332 | node-abi "^2.2.0" 333 | noop-logger "^0.1.1" 334 | npmlog "^4.0.1" 335 | os-homedir "^1.0.1" 336 | pump "^2.0.1" 337 | rc "^1.1.6" 338 | simple-get "^2.7.0" 339 | tar-fs "^1.13.0" 340 | tunnel-agent "^0.6.0" 341 | which-pm-runs "^1.0.0" 342 | 343 | process-nextick-args@~2.0.0: 344 | version "2.0.0" 345 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" 346 | 347 | pump@^1.0.0: 348 | version "1.0.3" 349 | resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954" 350 | dependencies: 351 | end-of-stream "^1.1.0" 352 | once "^1.3.1" 353 | 354 | pump@^2.0.1: 355 | version "2.0.1" 356 | resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" 357 | dependencies: 358 | end-of-stream "^1.1.0" 359 | once "^1.3.1" 360 | 361 | rc@^1.1.6: 362 | version "1.2.8" 363 | resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" 364 | dependencies: 365 | deep-extend "^0.6.0" 366 | ini "~1.3.0" 367 | minimist "^1.2.0" 368 | strip-json-comments "~2.0.1" 369 | 370 | "readable-stream@1.x >=1.1.9": 371 | version "1.1.14" 372 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" 373 | dependencies: 374 | core-util-is "~1.0.0" 375 | inherits "~2.0.1" 376 | isarray "0.0.1" 377 | string_decoder "~0.10.x" 378 | 379 | readable-stream@^2.0.6, readable-stream@^2.3.0, readable-stream@^2.3.5: 380 | version "2.3.6" 381 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" 382 | dependencies: 383 | core-util-is "~1.0.0" 384 | inherits "~2.0.3" 385 | isarray "~1.0.0" 386 | process-nextick-args "~2.0.0" 387 | safe-buffer "~5.1.1" 388 | string_decoder "~1.1.1" 389 | util-deprecate "~1.0.1" 390 | 391 | require_optional@^1.0.1: 392 | version "1.0.1" 393 | resolved "https://registry.yarnpkg.com/require_optional/-/require_optional-1.0.1.tgz#4cf35a4247f64ca3df8c2ef208cc494b1ca8fc2e" 394 | dependencies: 395 | resolve-from "^2.0.0" 396 | semver "^5.1.0" 397 | 398 | resolve-from@^2.0.0: 399 | version "2.0.0" 400 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" 401 | 402 | safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: 403 | version "5.1.2" 404 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 405 | 406 | saslprep@^1.0.0: 407 | version "1.0.0" 408 | resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.0.tgz#2c4968a0bfbf249530cd597bc62870ccd4b41a24" 409 | 410 | secure-keys@^1.0.0: 411 | version "1.0.0" 412 | resolved "https://registry.yarnpkg.com/secure-keys/-/secure-keys-1.0.0.tgz#f0c82d98a3b139a8776a8808050b824431087fca" 413 | 414 | semver@^5.1.0, semver@^5.4.1: 415 | version "5.5.0" 416 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" 417 | 418 | set-blocking@~2.0.0: 419 | version "2.0.0" 420 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" 421 | 422 | signal-exit@^3.0.0: 423 | version "3.0.2" 424 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" 425 | 426 | simple-concat@^1.0.0: 427 | version "1.0.0" 428 | resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6" 429 | 430 | simple-get@^2.7.0: 431 | version "2.8.1" 432 | resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.1.tgz#0e22e91d4575d87620620bc91308d57a77f44b5d" 433 | dependencies: 434 | decompress-response "^3.3.0" 435 | once "^1.3.1" 436 | simple-concat "^1.0.0" 437 | 438 | simple-node-logger@^0.93.37: 439 | version "0.93.37" 440 | resolved "https://registry.yarnpkg.com/simple-node-logger/-/simple-node-logger-0.93.37.tgz#4e1235917b3b4a8d6cc10e0208d157189afb2106" 441 | dependencies: 442 | lodash "^4.17.2" 443 | moment "^2.20.1" 444 | 445 | string-width@^1.0.1: 446 | version "1.0.2" 447 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" 448 | dependencies: 449 | code-point-at "^1.0.0" 450 | is-fullwidth-code-point "^1.0.0" 451 | strip-ansi "^3.0.0" 452 | 453 | "string-width@^1.0.2 || 2": 454 | version "2.1.1" 455 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" 456 | dependencies: 457 | is-fullwidth-code-point "^2.0.0" 458 | strip-ansi "^4.0.0" 459 | 460 | string_decoder@~0.10.x: 461 | version "0.10.31" 462 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" 463 | 464 | string_decoder@~1.1.1: 465 | version "1.1.1" 466 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" 467 | dependencies: 468 | safe-buffer "~5.1.0" 469 | 470 | strip-ansi@^3.0.0, strip-ansi@^3.0.1: 471 | version "3.0.1" 472 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 473 | dependencies: 474 | ansi-regex "^2.0.0" 475 | 476 | strip-ansi@^4.0.0: 477 | version "4.0.0" 478 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" 479 | dependencies: 480 | ansi-regex "^3.0.0" 481 | 482 | strip-json-comments@~2.0.1: 483 | version "2.0.1" 484 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 485 | 486 | tar-fs@^1.13.0: 487 | version "1.16.3" 488 | resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.16.3.tgz#966a628841da2c4010406a82167cbd5e0c72d509" 489 | dependencies: 490 | chownr "^1.0.1" 491 | mkdirp "^0.5.1" 492 | pump "^1.0.0" 493 | tar-stream "^1.1.2" 494 | 495 | tar-stream@^1.1.2: 496 | version "1.6.1" 497 | resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.1.tgz#f84ef1696269d6223ca48f6e1eeede3f7e81f395" 498 | dependencies: 499 | bl "^1.0.0" 500 | buffer-alloc "^1.1.0" 501 | end-of-stream "^1.0.0" 502 | fs-constants "^1.0.0" 503 | readable-stream "^2.3.0" 504 | to-buffer "^1.1.0" 505 | xtend "^4.0.0" 506 | 507 | to-buffer@^1.1.0: 508 | version "1.1.1" 509 | resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" 510 | 511 | tunnel-agent@^0.6.0: 512 | version "0.6.0" 513 | resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" 514 | dependencies: 515 | safe-buffer "^5.0.1" 516 | 517 | util-deprecate@~1.0.1: 518 | version "1.0.2" 519 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 520 | 521 | which-pm-runs@^1.0.0: 522 | version "1.0.0" 523 | resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" 524 | 525 | wide-align@^1.1.0: 526 | version "1.1.3" 527 | resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" 528 | dependencies: 529 | string-width "^1.0.2 || 2" 530 | 531 | window-size@^0.1.4: 532 | version "0.1.4" 533 | resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" 534 | 535 | wrap-ansi@^2.0.0: 536 | version "2.1.0" 537 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" 538 | dependencies: 539 | string-width "^1.0.1" 540 | strip-ansi "^3.0.1" 541 | 542 | wrappy@1: 543 | version "1.0.2" 544 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 545 | 546 | xtend@^4.0.0: 547 | version "4.0.1" 548 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" 549 | 550 | y18n@^3.2.0: 551 | version "3.2.1" 552 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" 553 | 554 | yargs@^3.19.0: 555 | version "3.32.0" 556 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.32.0.tgz#03088e9ebf9e756b69751611d2a5ef591482c995" 557 | dependencies: 558 | camelcase "^2.0.1" 559 | cliui "^3.0.3" 560 | decamelize "^1.1.1" 561 | os-locale "^1.4.0" 562 | string-width "^1.0.1" 563 | window-size "^0.1.4" 564 | y18n "^3.2.0" 565 | 566 | zeromq@^4.6.0: 567 | version "4.6.0" 568 | resolved "https://registry.yarnpkg.com/zeromq/-/zeromq-4.6.0.tgz#7b1ca19cf740f484abfb9358430728f1339f03db" 569 | dependencies: 570 | nan "^2.6.2" 571 | prebuild-install "^2.2.2" 572 | --------------------------------------------------------------------------------