├── .gitignore ├── bin └── algolia-upload.js ├── lib ├── import.js └── index.js ├── package.json ├── readme.md └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | node_modules/ 3 | dist/ 4 | dist-es5-module/ 5 | npm-debug.log 6 | .DS_Store 7 | -------------------------------------------------------------------------------- /bin/algolia-upload.js: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | var parseArgs = require('minimist'); 3 | var algoliaCSVTools = require('../lib'); 4 | 5 | var config = readConfig(process.argv); 6 | if(!config) return 1; 7 | 8 | algoliaCSVTools.import[config.inputType](config); 9 | 10 | function readConfig(argv) { 11 | var args = parseArgs(argv.slice(2)); 12 | var urlStartPattern = /http(?:s)*:\/\//; 13 | 14 | if( args._.length !== 4) { 15 | console.error( "Usage : algolia-upload APP_ID API_KEY indexName file|url [-d ','] [-b 10000] [--clear-index] [--parse-arrays=column] [--array-delimiter=','] [--geo-columns=lat_col,long_col]" ); 16 | return undefined; 17 | } 18 | 19 | var parseArrays; 20 | if(Array.isArray(args['parse-arrays'])) parseArrays = args['parse-arrays']; 21 | else if(typeof args['parse-arrays']) parseArrays = [args['parse-arrays']]; 22 | 23 | var geoColumns = null; 24 | if(args['geo-columns']) { 25 | var cols = args['geo-columns'].split(','); 26 | if(cols.length !== 2) { 27 | console.error('--geo-columns argument must contain the name of two columns respectively for latitude and longitude separated with a comma'); 28 | return undefined; 29 | } 30 | geoColumns = { 31 | 'lat': cols[0], 32 | 'lng': cols[1] 33 | }; 34 | } 35 | 36 | return { 37 | appId: args._[0], 38 | apiKey: args._[1], 39 | indexName: args._[2], 40 | input: args._[3], 41 | inputType: (urlStartPattern.test(args._[3]) ? 'url' : 'file'), 42 | batchSize: args['b'] || 10000, 43 | delimiter: args['d'] || ',', 44 | clearIndex: args['clear-index'] || false, 45 | parseArrays: parseArrays || false, 46 | arrayDelimiter: args['array-delimiter'] || ',', 47 | geoColumns: geoColumns 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /lib/import.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | file: uploadCSVFileToAlgolia, 3 | url: uploadCSVFromURLToAlgolia 4 | }; 5 | 6 | var HttpsAgent = require('agentkeepalive').HttpsAgent; 7 | var Algolia = require('algoliasearch'); 8 | var stream = require( 'stream' ); 9 | var request = require( 'request' ); 10 | 11 | var parse = require('csv-parse'); 12 | var fs = require('fs'); 13 | var transform = require('stream-transform'); 14 | var Batch = require( 'batch-stream' ); 15 | 16 | function uploadCSVToAlgolia(inputStream, config) { 17 | console.log('Parsing CSV'); 18 | var parser = parse({comment: '#', delimiter : config.delimiter, columns: true, auto_parse: true}); 19 | 20 | var transforms = []; 21 | if(config.parseArrays) transforms.push(transform(parseArrays.bind(undefined, config.parseArrays, config.arrayDelimiter))); 22 | if(config.geoColumns) transforms.push(transform(geoColumificater.bind(undefined, config.geoColumns))); 23 | 24 | var csvStream = transforms.reduce(function(stream, t){ 25 | return stream.pipe(t); 26 | }, inputStream.pipe(parser)); 27 | 28 | csvStream.pipe(transform(wrapWithCounter(addObjectID))) 29 | .pipe(new Batch({ size: config.batchSize})) 30 | .pipe(algoliaSaveStream(config)); 31 | } 32 | 33 | function uploadCSVFileToAlgolia(config) { 34 | console.log('Reading from file : ' + config.input); 35 | var fileStream = fs.createReadStream(config.input, { autoclose : true }); 36 | uploadCSVToAlgolia(fileStream, config); 37 | } 38 | 39 | function uploadCSVFromURLToAlgolia(config) { 40 | console.log('Reading from http : ' + config.input); 41 | var httpStream = request(config.input); 42 | uploadCSVToAlgolia(httpStream, config); 43 | } 44 | 45 | function addObjectID(i, data) { 46 | if(!data.objectID) data.objectID = i; 47 | return data; 48 | } 49 | 50 | function parseArrays(columnsToParse, arrayDelimiter, data) { 51 | var res = {}; 52 | Object.keys(data).forEach(function(k) { 53 | if(columnsToParse.indexOf(k) !== -1) res[k] = data[k].split(arrayDelimiter); 54 | else res[k] = data[k]; 55 | }); 56 | return res; 57 | } 58 | 59 | function geoColumificater(geoColumns, data) { 60 | if(!data[geoColumns.lat] || !data[geoColumns.lng]) return data; 61 | 62 | var res = Object.assign({}, data); 63 | res['_geoloc'] = { 64 | 'lat': data[geoColumns.lat], 65 | 'lng': data[geoColumns.lng] 66 | }; 67 | 68 | return res; 69 | } 70 | 71 | function wrapWithCounter(fn) { 72 | var counter = 0; 73 | return function(){ 74 | var args = [counter++].concat(Array.from(arguments)); 75 | return fn.apply(undefined, args); 76 | } 77 | } 78 | 79 | function algoliaSaveStream(config) { 80 | var appId = config.appId; 81 | var apiKey = config.apiKey; 82 | var indexName = config.indexName; 83 | 84 | var keepaliveAgent = new HttpsAgent({ 85 | maxSockets: 1, 86 | maxKeepAliveRequests: 0, // no limit on max requests per keepalive socket 87 | maxKeepAliveTime: 30000 // keepalive for 30 seconds 88 | }); 89 | 90 | var client = new Algolia(appId, apiKey, keepaliveAgent); 91 | 92 | var index = client.initIndex(indexName); 93 | if(config.clearIndex) { 94 | console.log('Clearing data in index'); 95 | index.clearIndex(); 96 | } 97 | 98 | var streamToAlgolia = new stream.Stream(); 99 | streamToAlgolia.writable = true; 100 | streamToAlgolia.write = function (data) { 101 | console.log('Saving to algolia'); 102 | index.saveObjects(data, function(error, content) { 103 | if(error) console.error("ERROR: %s", error); 104 | else console.log('Saved/updated ' + content.objectIDs.length + ' records'); 105 | } ); 106 | return true; 107 | }; 108 | streamToAlgolia.end = function(data) { 109 | }; 110 | 111 | return streamToAlgolia; 112 | } 113 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | import: require('./import.js') 3 | }; 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "algolia-csv", 3 | "version": "1.3.0", 4 | "description": "Algolia CSV toolbox CLI", 5 | "keywords": [ 6 | "algolia", 7 | "csv", 8 | "upload" 9 | ], 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/algolia/algolia-csv-js.git" 13 | }, 14 | "main": "index.js", 15 | "bin": { 16 | "algolia-upload": "bin/algolia-upload.js" 17 | }, 18 | "author": "Algolia and the poney riders ", 19 | "license": "MIT", 20 | "dependencies": { 21 | "agentkeepalive": "^2.1.0", 22 | "algoliasearch": "^3.13.1", 23 | "batch-stream": "^0.1.2", 24 | "csv-parse": "^1.0.2", 25 | "minimist": "^1.2.0", 26 | "request": "^2.72.0", 27 | "stream-transform": "0.1.1" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Algolia CSV toolbox 2 | 3 | ## What is this project about? 4 | 5 | It's a CLI and library to easily upload CSV files to Algolia in an efficient manner 6 | without limitations. 7 | 8 | Cool features: 9 | - uses the header (first line of the csv file) to set the name of the columns 10 | - automatically detects the types of the fields 11 | - adds an objectID automatically if not set (useful for public datasets) 12 | - uses batch best practices to upload to Algolia 13 | - based on streams 14 | 15 | ## Installation / usage 16 | 17 | ### Requirements 18 | 19 | - Node + npm 20 | - an algolia account and and API key that can upload (not the search API key) 21 | 22 | ### CLI 23 | 24 | ```sh 25 | npm install -g algolia-csv 26 | ``` 27 | 28 | You must have a file in which the first row contains the name of all the fields. 29 | 30 | ```sh 31 | algolia-upload $APP_ID $API_KEY $indexName $file|$url [-d $delimiter] [-b $batchSizer] [--clear-index] [--parse-arrays=$column] [--array-delimiter=$delimiter] [--geo-columns=$latCol,$longCol] 32 | ``` 33 | 34 | Mandatory parameters are the aplication id, a key with write rights, the target index name and the input CSV (locally or accessible 35 | with http/https). 36 | 37 | Other parameters: 38 | - `-d` let you set the delimiter used in your file. This should be set in quotes. Default is ','. 39 | - `-b` let you set the batch size. Default is 10000. 40 | - `--clear-index` forces the index to be cleared before uploading the new data. 41 | - `--parse-arrays=column` let you specify if a column value should be split before uploading the data. 42 | More than one column can be set using this parameter multiple times. Value will be split with `--array-delimiter`. 43 | - `--array-delimiter` let you specify the delimiter used to split the values of columns defined with `--parse-arrays`. Default is ','. 44 | - `--geo-columns=latCol,longCol` let you specify two columns that are to be used for creating the special algolia attribute `_geoloc`. 45 | 46 | ### As a library 47 | 48 | ```sh 49 | npm install --save algolia-csv 50 | ``` 51 | 52 | ```javascript 53 | var algoliaCsvTools = require('algolia-csv'); 54 | 55 | algoliaCsvTools.upload({ 56 | appId: '', 57 | apiKey: '', 58 | indexName: '', 59 | inputFile: '', 60 | batchSize: 1000, 61 | delimiter: ',', 62 | clearIndex: false, 63 | parseArrays: ['column'], 64 | arrayDelimiter: '|', 65 | geoColumns: {lat: 'latCol', 'lng': 'longColumn'} 66 | }); 67 | ``` 68 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | agentkeepalive@^2.1.0, agentkeepalive@^2.2.0: 6 | version "2.2.0" 7 | resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-2.2.0.tgz#c5d1bd4b129008f1163f236f86e5faea2026e2ef" 8 | 9 | ajv@^4.9.1: 10 | version "4.11.8" 11 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" 12 | dependencies: 13 | co "^4.6.0" 14 | json-stable-stringify "^1.0.1" 15 | 16 | algoliasearch@^3.13.1: 17 | version "3.24.0" 18 | resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-3.24.0.tgz#d0a6ac2963b781d2fb059a3a853fe18765673346" 19 | dependencies: 20 | agentkeepalive "^2.2.0" 21 | debug "^2.6.8" 22 | envify "^4.0.0" 23 | es6-promise "^4.1.0" 24 | events "^1.1.0" 25 | foreach "^2.0.5" 26 | global "^4.3.2" 27 | inherits "^2.0.1" 28 | isarray "^2.0.1" 29 | load-script "^1.0.0" 30 | object-keys "^1.0.11" 31 | querystring-es3 "^0.2.1" 32 | reduce "^1.0.1" 33 | semver "^5.1.0" 34 | tunnel-agent "^0.6.0" 35 | 36 | asn1@~0.2.3: 37 | version "0.2.3" 38 | resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" 39 | 40 | assert-plus@1.0.0, assert-plus@^1.0.0: 41 | version "1.0.0" 42 | resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" 43 | 44 | assert-plus@^0.2.0: 45 | version "0.2.0" 46 | resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" 47 | 48 | asynckit@^0.4.0: 49 | version "0.4.0" 50 | resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" 51 | 52 | aws-sign2@~0.6.0: 53 | version "0.6.0" 54 | resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" 55 | 56 | aws4@^1.2.1: 57 | version "1.6.0" 58 | resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" 59 | 60 | batch-stream@^0.1.2: 61 | version "0.1.3" 62 | resolved "https://registry.yarnpkg.com/batch-stream/-/batch-stream-0.1.3.tgz#c6c2887080e70eed71e9ed81cd0a5d0fd35fea63" 63 | dependencies: 64 | readable-stream "~1.0.2" 65 | 66 | bcrypt-pbkdf@^1.0.0: 67 | version "1.0.1" 68 | resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" 69 | dependencies: 70 | tweetnacl "^0.14.3" 71 | 72 | boom@2.x.x: 73 | version "2.10.1" 74 | resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" 75 | dependencies: 76 | hoek "2.x.x" 77 | 78 | caseless@~0.12.0: 79 | version "0.12.0" 80 | resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" 81 | 82 | co@^4.6.0: 83 | version "4.6.0" 84 | resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" 85 | 86 | combined-stream@^1.0.5, combined-stream@~1.0.5: 87 | version "1.0.5" 88 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" 89 | dependencies: 90 | delayed-stream "~1.0.0" 91 | 92 | core-util-is@~1.0.0: 93 | version "1.0.2" 94 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 95 | 96 | cryptiles@2.x.x: 97 | version "2.0.5" 98 | resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" 99 | dependencies: 100 | boom "2.x.x" 101 | 102 | csv-parse@^1.0.2: 103 | version "1.2.0" 104 | resolved "https://registry.yarnpkg.com/csv-parse/-/csv-parse-1.2.0.tgz#047b73868ab9a85746e885f637f9ed0fb645a425" 105 | 106 | dashdash@^1.12.0: 107 | version "1.14.1" 108 | resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" 109 | dependencies: 110 | assert-plus "^1.0.0" 111 | 112 | debug@^2.6.8: 113 | version "2.6.8" 114 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" 115 | dependencies: 116 | ms "2.0.0" 117 | 118 | delayed-stream@~1.0.0: 119 | version "1.0.0" 120 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" 121 | 122 | dom-walk@^0.1.0: 123 | version "0.1.1" 124 | resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" 125 | 126 | ecc-jsbn@~0.1.1: 127 | version "0.1.1" 128 | resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" 129 | dependencies: 130 | jsbn "~0.1.0" 131 | 132 | envify@^4.0.0: 133 | version "4.1.0" 134 | resolved "https://registry.yarnpkg.com/envify/-/envify-4.1.0.tgz#f39ad3db9d6801b4e6b478b61028d3f0b6819f7e" 135 | dependencies: 136 | esprima "^4.0.0" 137 | through "~2.3.4" 138 | 139 | es6-promise@^4.1.0: 140 | version "4.1.1" 141 | resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.1.1.tgz#8811e90915d9a0dba36274f0b242dbda78f9c92a" 142 | 143 | esprima@^4.0.0: 144 | version "4.0.0" 145 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" 146 | 147 | events@^1.1.0: 148 | version "1.1.1" 149 | resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" 150 | 151 | extend@~3.0.0: 152 | version "3.0.1" 153 | resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" 154 | 155 | extsprintf@1.0.2: 156 | version "1.0.2" 157 | resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" 158 | 159 | foreach@^2.0.5: 160 | version "2.0.5" 161 | resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" 162 | 163 | forever-agent@~0.6.1: 164 | version "0.6.1" 165 | resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" 166 | 167 | form-data@~2.1.1: 168 | version "2.1.4" 169 | resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" 170 | dependencies: 171 | asynckit "^0.4.0" 172 | combined-stream "^1.0.5" 173 | mime-types "^2.1.12" 174 | 175 | getpass@^0.1.1: 176 | version "0.1.7" 177 | resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" 178 | dependencies: 179 | assert-plus "^1.0.0" 180 | 181 | global@^4.3.2: 182 | version "4.3.2" 183 | resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" 184 | dependencies: 185 | min-document "^2.19.0" 186 | process "~0.5.1" 187 | 188 | har-schema@^1.0.5: 189 | version "1.0.5" 190 | resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" 191 | 192 | har-validator@~4.2.1: 193 | version "4.2.1" 194 | resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" 195 | dependencies: 196 | ajv "^4.9.1" 197 | har-schema "^1.0.5" 198 | 199 | hawk@~3.1.3: 200 | version "3.1.3" 201 | resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" 202 | dependencies: 203 | boom "2.x.x" 204 | cryptiles "2.x.x" 205 | hoek "2.x.x" 206 | sntp "1.x.x" 207 | 208 | hoek@2.x.x: 209 | version "2.16.3" 210 | resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" 211 | 212 | http-signature@~1.1.0: 213 | version "1.1.1" 214 | resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" 215 | dependencies: 216 | assert-plus "^0.2.0" 217 | jsprim "^1.2.2" 218 | sshpk "^1.7.0" 219 | 220 | inherits@^2.0.1, inherits@~2.0.1: 221 | version "2.0.3" 222 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 223 | 224 | is-typedarray@~1.0.0: 225 | version "1.0.0" 226 | resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" 227 | 228 | isarray@0.0.1: 229 | version "0.0.1" 230 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" 231 | 232 | isarray@^2.0.1: 233 | version "2.0.2" 234 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.2.tgz#5aa99638daf2248b10b9598b763a045688ece3ee" 235 | 236 | isstream@~0.1.2: 237 | version "0.1.2" 238 | resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" 239 | 240 | jsbn@~0.1.0: 241 | version "0.1.1" 242 | resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" 243 | 244 | json-schema@0.2.3: 245 | version "0.2.3" 246 | resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" 247 | 248 | json-stable-stringify@^1.0.1: 249 | version "1.0.1" 250 | resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" 251 | dependencies: 252 | jsonify "~0.0.0" 253 | 254 | json-stringify-safe@~5.0.1: 255 | version "5.0.1" 256 | resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" 257 | 258 | jsonify@~0.0.0: 259 | version "0.0.0" 260 | resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" 261 | 262 | jsprim@^1.2.2: 263 | version "1.4.0" 264 | resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918" 265 | dependencies: 266 | assert-plus "1.0.0" 267 | extsprintf "1.0.2" 268 | json-schema "0.2.3" 269 | verror "1.3.6" 270 | 271 | load-script@^1.0.0: 272 | version "1.0.0" 273 | resolved "https://registry.yarnpkg.com/load-script/-/load-script-1.0.0.tgz#0491939e0bee5643ee494a7e3da3d2bac70c6ca4" 274 | 275 | mime-db@~1.27.0: 276 | version "1.27.0" 277 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" 278 | 279 | mime-types@^2.1.12, mime-types@~2.1.7: 280 | version "2.1.15" 281 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed" 282 | dependencies: 283 | mime-db "~1.27.0" 284 | 285 | min-document@^2.19.0: 286 | version "2.19.0" 287 | resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" 288 | dependencies: 289 | dom-walk "^0.1.0" 290 | 291 | minimist@^1.2.0: 292 | version "1.2.0" 293 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" 294 | 295 | ms@2.0.0: 296 | version "2.0.0" 297 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 298 | 299 | oauth-sign@~0.8.1: 300 | version "0.8.2" 301 | resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" 302 | 303 | object-keys@^1.0.11, object-keys@~1.0.0: 304 | version "1.0.11" 305 | resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" 306 | 307 | performance-now@^0.2.0: 308 | version "0.2.0" 309 | resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" 310 | 311 | process@~0.5.1: 312 | version "0.5.2" 313 | resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" 314 | 315 | punycode@^1.4.1: 316 | version "1.4.1" 317 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" 318 | 319 | qs@~6.4.0: 320 | version "6.4.0" 321 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" 322 | 323 | querystring-es3@^0.2.1: 324 | version "0.2.1" 325 | resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" 326 | 327 | readable-stream@~1.0.2: 328 | version "1.0.34" 329 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" 330 | dependencies: 331 | core-util-is "~1.0.0" 332 | inherits "~2.0.1" 333 | isarray "0.0.1" 334 | string_decoder "~0.10.x" 335 | 336 | reduce@^1.0.1: 337 | version "1.0.1" 338 | resolved "https://registry.yarnpkg.com/reduce/-/reduce-1.0.1.tgz#14fa2e5ff1fc560703a020cbb5fbaab691565804" 339 | dependencies: 340 | object-keys "~1.0.0" 341 | 342 | request@^2.72.0: 343 | version "2.81.0" 344 | resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" 345 | dependencies: 346 | aws-sign2 "~0.6.0" 347 | aws4 "^1.2.1" 348 | caseless "~0.12.0" 349 | combined-stream "~1.0.5" 350 | extend "~3.0.0" 351 | forever-agent "~0.6.1" 352 | form-data "~2.1.1" 353 | har-validator "~4.2.1" 354 | hawk "~3.1.3" 355 | http-signature "~1.1.0" 356 | is-typedarray "~1.0.0" 357 | isstream "~0.1.2" 358 | json-stringify-safe "~5.0.1" 359 | mime-types "~2.1.7" 360 | oauth-sign "~0.8.1" 361 | performance-now "^0.2.0" 362 | qs "~6.4.0" 363 | safe-buffer "^5.0.1" 364 | stringstream "~0.0.4" 365 | tough-cookie "~2.3.0" 366 | tunnel-agent "^0.6.0" 367 | uuid "^3.0.0" 368 | 369 | safe-buffer@^5.0.1: 370 | version "5.1.1" 371 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" 372 | 373 | semver@^5.1.0: 374 | version "5.3.0" 375 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" 376 | 377 | sntp@1.x.x: 378 | version "1.0.9" 379 | resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" 380 | dependencies: 381 | hoek "2.x.x" 382 | 383 | sshpk@^1.7.0: 384 | version "1.13.1" 385 | resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" 386 | dependencies: 387 | asn1 "~0.2.3" 388 | assert-plus "^1.0.0" 389 | dashdash "^1.12.0" 390 | getpass "^0.1.1" 391 | optionalDependencies: 392 | bcrypt-pbkdf "^1.0.0" 393 | ecc-jsbn "~0.1.1" 394 | jsbn "~0.1.0" 395 | tweetnacl "~0.14.0" 396 | 397 | stream-transform@0.1.1: 398 | version "0.1.1" 399 | resolved "https://registry.yarnpkg.com/stream-transform/-/stream-transform-0.1.1.tgz#0a54a2b81eea88da55a50df2441cb63edc101c71" 400 | 401 | string_decoder@~0.10.x: 402 | version "0.10.31" 403 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" 404 | 405 | stringstream@~0.0.4: 406 | version "0.0.5" 407 | resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" 408 | 409 | through@~2.3.4: 410 | version "2.3.8" 411 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" 412 | 413 | tough-cookie@~2.3.0: 414 | version "2.3.2" 415 | resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" 416 | dependencies: 417 | punycode "^1.4.1" 418 | 419 | tunnel-agent@^0.6.0: 420 | version "0.6.0" 421 | resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" 422 | dependencies: 423 | safe-buffer "^5.0.1" 424 | 425 | tweetnacl@^0.14.3, tweetnacl@~0.14.0: 426 | version "0.14.5" 427 | resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" 428 | 429 | uuid@^3.0.0: 430 | version "3.1.0" 431 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" 432 | 433 | verror@1.3.6: 434 | version "1.3.6" 435 | resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" 436 | dependencies: 437 | extsprintf "1.0.2" 438 | --------------------------------------------------------------------------------