From cc69fef4b7e1587a91a0603d4bd1a46d0b133dd5 Mon Sep 17 00:00:00 2001 From: Rubén Beltrán del Río Date: Tue, 13 Dec 2016 00:24:01 -0600 Subject: Initial Setup (#1) * Add basic files * Add eslint file * Add docker files * Update readme * Add circle CI Config * Use actual test ci command * Don't build on test_ci * Add a dockerignore file * Install newer version of docker compose * Install newer docker on circle CI * Restore docker services * Use docker run to propagate exit status * Copy package.json into docker * Push image on success * Push develop/master to dockerhub * Add travis file since circle env is odd * Remove circle ci config * Account for http style origins * Add docker build command to travis * Add contributing text * Add the changelog --- lib/dasein.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 lib/dasein.js (limited to 'lib/dasein.js') diff --git a/lib/dasein.js b/lib/dasein.js new file mode 100644 index 0000000..8de32c8 --- /dev/null +++ b/lib/dasein.js @@ -0,0 +1,13 @@ +'use strict'; + +const internals = {}; + +module.exports = internals.Dasein = class Dasein { + + run() { + + console.log('OK'); + + return Promise.resolve(); + } +}; -- cgit From 287fa13b3e600b2340895a5463a288bf08101bb5 Mon Sep 17 00:00:00 2001 From: Rubén Beltrán del Río Date: Thu, 19 Jan 2017 00:25:01 -0600 Subject: Add Login (#2) * Add dependencies * Add barebones app * Ignore .DS_Store * Add base static assets * Expose port on docker * Ignore env files * Add instructions to use env.dist * Add twitter configs * Use latest node version * Read env file properly * Add dependencies to start parsing twitter * Add helper for twitter login operations * Add handler for titter login routes * Use twitter handler * Add JWT related keys * Add jwt dependencies * Move index static file * Rename twitter handler to auth, add jwt support * Add new yarn lock * Add instructions for twitter * Remove twitter image * Fix return value lint errors * Ignore require-yield errors in linter --- .eslintrc | 3 +- .gitignore | 6 + Dockerfile | 2 +- README.md | 16 +++ bin/dasein.js | 8 +- config/config.js | 21 +++ config/env.dist | 4 + docker-compose.yml | 3 + lib/dasein.js | 95 ++++++++++++- lib/handlers/auth.js | 98 +++++++++++++ lib/twitter_helper.js | 78 ++++++++++ package.json | 8 ++ static/css/app.css | 42 ++++++ static/favicon.ico | Bin 0 -> 5430 bytes static/windex.html | 36 +++++ yarn.lock | 385 ++++++++++++++++++++++++++++++++++++++++++++++++-- 16 files changed, 783 insertions(+), 22 deletions(-) create mode 100644 config/config.js create mode 100644 config/env.dist create mode 100644 lib/handlers/auth.js create mode 100644 lib/twitter_helper.js create mode 100644 static/css/app.css create mode 100644 static/favicon.ico create mode 100644 static/windex.html (limited to 'lib/dasein.js') diff --git a/.eslintrc b/.eslintrc index d309053..f91f592 100644 --- a/.eslintrc +++ b/.eslintrc @@ -5,6 +5,7 @@ 2, 2 ], - "no-undef": 2 + "no-undef": 2, + "require-yield": 0 } } diff --git a/.gitignore b/.gitignore index 5148e52..ce59e98 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,9 @@ jspm_packages # Optional REPL history .node_repl_history + +# macos files +.DS_Store + +# Env files +.env diff --git a/Dockerfile b/Dockerfile index 38d991a..5e2f7f9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:6.9.2 +FROM node:6.9.4 RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - RUN echo "deb http://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list diff --git a/README.md b/README.md index 9cd6edb..584a258 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,16 @@ # dasein A social network +## Configuring + +This project usese environment variables to work. For most cases, the +defaults work but some sensitive info like keys must be overridden. Copy +the file in `config/env.dist` to `.env` in the project root and override +the values. + +When running with `make run`, it'll pick up these values automatically. +If you're doing it the hard way, you'll have to source them. + ## Running Locally You'll need [Docker][docker] to run the project. @@ -28,6 +38,12 @@ You can also do some other operations * Push and build the image with `make upload` * Clean the environment with `make clean` +## Setting up Twitter for login + +1. Create an app on https://apps.twitter.com/ +2. Make sure you check "Allow this application to be used to Sign in with Twitter" +3. Make sure you specify a callback URL (eg. http://localhost:1927/login-callback) + ## Checking the code This project uses the [Hapi Style Guide][hapi-style-guide] for diff --git a/bin/dasein.js b/bin/dasein.js index 10edfc3..b6f7944 100755 --- a/bin/dasein.js +++ b/bin/dasein.js @@ -1,18 +1,16 @@ #!/usr/bin/env node 'use strict'; +const Config = require('../config/config'); const Dasein = require('..'); const internals = {}; -internals.dasein = new Dasein(); +internals.dasein = new Dasein(Config); internals.main = () => { - internals.dasein.run().then(() => { - - process.exit(0); - }).catch((err) => { + internals.dasein.run().catch((err) => { console.error(err.stack || err.message || err); process.exit(1); diff --git a/config/config.js b/config/config.js new file mode 100644 index 0000000..1c1c8a0 --- /dev/null +++ b/config/config.js @@ -0,0 +1,21 @@ +'use strict'; + +const Getenv = require('getenv'); + +const internals = {}; + +module.exports = internals.Config = { + cookieKeys: Getenv.array('DASEIN_COOKIE_KEYS'), // Signatures for the cookies + port: Getenv.int('DASEIN_PORT', 1927), // Port to listen on + hostname: Getenv('DASEIN_HOSTNAME', 'localhost'), // Domain to listen on, used for cookies + staticDirectory: Getenv('DASEIN_STATIC_DIRECTORY', 'static'), // Location of static assets + jwt: { + cookieName: Getenv('DASEIN_JWT_COOKIE_NAME', 'dasein_jwt'), // Name of cookie where jwt is stored + duration: Getenv('DASEIN_JWT_DURATION', 86400), // Duration of JWT (24 hours) + secret: Getenv('DASEIN_JWT_SECRET') // Secret to sign JWT + }, + twitter: { + consumerKey: Getenv('DASEIN_TWITTER_CONSUMER_KEY'), // Consumer key for twitter + consumerSecret: Getenv('DASEIN_TWITTER_CONSUMER_SECRET') // Consumer secret for twitter + } +}; diff --git a/config/env.dist b/config/env.dist new file mode 100644 index 0000000..ee23ee1 --- /dev/null +++ b/config/env.dist @@ -0,0 +1,4 @@ +DASEIN_COOKIE_KEYS=comma,separated,keys +DASEIN_TWITTER_CONSUMER_KEY=your_twitter_key +DASEIN_TWITTER_CONSUMER_SECRET=your_twitter_secret +DASEIN_JWT_SECRET=some_random_string diff --git a/docker-compose.yml b/docker-compose.yml index d442e69..92205a9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,4 +3,7 @@ version: '2' services: dasein: build: . + env_file: .env image: rbdr/dasein + ports: + - "1927:1927" diff --git a/lib/dasein.js b/lib/dasein.js index 8de32c8..38654a4 100644 --- a/lib/dasein.js +++ b/lib/dasein.js @@ -1,13 +1,106 @@ 'use strict'; +const Koa = require('koa'); +const KoaJwt = require('koa-jwt'); +const KoaStatic = require('koa-static'); +const KoaRoute = require('koa-route'); + +const AuthHandler = require('./handlers/auth'); + const internals = {}; +internals.k401Location = '/401.html'; +internals.kMainLocation = '/'; + module.exports = internals.Dasein = class Dasein { + constructor(config) { + + Object.assign(this, config); + } + run() { - console.log('OK'); + this._initializeServer(); + this._startServer(); + this._printBanner(); return Promise.resolve(); } + + _initializeServer() { + + this._app = Koa(); + + this._app.keys = this.cookieKeys; + + this._app.use(KoaStatic(this.staticDirectory)); + + // Redirect all 401s to the 401 static page + + this._app.use(function * (next) { + + try { + yield next; + } + catch (err) { + if (err.status === 401) { + return this.redirect(internals.k401Location); + } + + throw err; + } + }); + + this._app.use(KoaJwt({ + secret: this.jwt.secret, + passthrough: true, + cookie: this.jwt.cookieName + })); + + // Handlers for Twitter Auth Related Routes + + const authHandler = new AuthHandler({ + hostname: this.hostname, + jwt: this.jwt, + twitter: this.twitter + }); + this._app.use(KoaRoute.get('/login', authHandler.login())); + this._app.use(KoaRoute.get('/login-callback', authHandler.callback())); + this._app.use(KoaRoute.get('/logout', authHandler.logout())); + + // The index + + this._app.use(function * () { + + if (this.state.user) { + this.body = ` Hello ${this.state.user.screen_name}`; + return; + } + + this.body = 'Go to /login to login'; + return; + }); + } + + _startServer() { + + this._app.listen(this.port); + } + + // Prints the banner. + _printBanner() { + + console.log(' .'); + console.log(' /'); + console.log(' +-----+'); + console.log(` | o o | - Listening Gladly, Try me on port: ${this.port}`); + console.log(' +-----+'); + console.log(' +---------+'); + console.log(' /| [][] |\\'); + console.log(' || | |'); + console.log(' || | \\c'); + console.log(' ^+---------+'); + console.log(' (.) '); + } }; diff --git a/lib/handlers/auth.js b/lib/handlers/auth.js new file mode 100644 index 0000000..d16e15d --- /dev/null +++ b/lib/handlers/auth.js @@ -0,0 +1,98 @@ +'use strict'; + +const Co = require('co'); +const TwitterHelper = require('../twitter_helper'); +const JsonWebToken = require('jsonwebtoken'); +const Pify = require('pify'); + +const internals = {}; + +internals.kRedirectUrl = 'https://api.twitter.com/oauth/authenticate?oauth_token='; +internals.kMainLocation = '/'; + +internals.signJsonWebToken = Pify(JsonWebToken.sign); + +module.exports = internals.AuthHandler = class AuthHandler { + + constructor(config) { + + this._twitterHelper = new TwitterHelper(config.twitter); + this._jwtConfig = config.jwt; + this._hostname = config.hostname; + } + + login() { + + const twitterHelper = this._twitterHelper; + + return function *handleLogin() { + + if (this.state.user) { + return this.redirect(internals.kMainLocation); + } + + const requestToken = yield twitterHelper.getRequestToken(); + this.redirect(`${internals.kRedirectUrl}${requestToken.oAuthToken}`); + }; + } + + callback() { + + const self = this; + + return function *handleCallback() { + + if (this.request.query.denied) { + return this.throw(401); + } + + const oAuthToken = this.request.query.oauth_token; + const oAuthVerifier = this.request.query.oauth_verifier; + let user; + + try { + const accessToken = yield self._twitterHelper.getAccessToken(oAuthToken, oAuthVerifier); + user = yield self._twitterHelper.getUser(accessToken.oAuthAccessToken, accessToken.oAuthAccessTokenSecret); + } + catch (err) { + console.error(err.stack || err.message || err); + return this.throw(401); + } + + yield self._setJWT(user, this); + + this.redirect(internals.kMainLocation); + }; + } + + logout() { + + const self = this; + + return function * () { + + this.cookies.set(self._jwtConfig.cookieName, null); + this.redirect(internals.kMainLocation); + }; + } + + // Sets a JSON Web Token Cookie + _setJWT(payload, context) { + + const self = this; + + return Co(function * () { + + const token = yield internals.signJsonWebToken(payload, self._jwtConfig.secret, { + expiresIn: self._jwtConfig.duration + }); + + context.cookies.set(self._jwtConfig.cookieName, token, { + maxAge: self._jwtConfig.duration * 1000, + signed: true, + domain: self._hostname, + overwrite: true + }); + }); + } +}; diff --git a/lib/twitter_helper.js b/lib/twitter_helper.js new file mode 100644 index 0000000..3ab51fa --- /dev/null +++ b/lib/twitter_helper.js @@ -0,0 +1,78 @@ +'use strict'; + +const Co = require('co'); +const OAuth = require('oauth'); +const Pify = require('pify'); + +const internals = {}; + +internals.kRequestTokenUrl = 'https://api.twitter.com/oauth/request_token'; +internals.kAccessTokenUrl = 'https://api.twitter.com/oauth/access_token'; +internals.kVerifyCredentialsUrl = 'https://api.twitter.com/1.1/account/verify_credentials.json'; +internals.kOauthVersion = '1.0A'; +internals.kOauthSignatureMethod = 'HMAC-SHA1'; + +module.exports = internals.TwitterHelper = class TwitterHelper { + + constructor(config) { + + this._oAuth = new OAuth.OAuth( + internals.kRequestTokenUrl, + internals.kAccessTokenUrl, + config.consumerKey, + config.consumerSecret, + internals.kOauthVersion, + null, + internals.kOauthSignatureMethod + ); + } + + getRequestToken() { + + const self = this; + + return Co(function * () { + + const getOAuthRequestToken = Pify(self._oAuth.getOAuthRequestToken.bind(self._oAuth), { multiArgs: true }); + const [oAuthToken, oAuthTokenSecret] = yield getOAuthRequestToken(); + + return { + oAuthToken, + oAuthTokenSecret + }; + }); + } + + getAccessToken(oAuthToken, oAuthVerifier) { + + const self = this; + + return Co(function * () { + + const getOAuthAccessToken = Pify(self._oAuth.getOAuthAccessToken.bind(self._oAuth), { multiArgs: true }); + const [oAuthAccessToken, oAuthAccessTokenSecret] = yield getOAuthAccessToken(oAuthToken, + '', + oAuthVerifier); + + return { + oAuthAccessToken, + oAuthAccessTokenSecret + }; + }); + } + + getUser(oAuthAccessToken, oAuthAccessTokenSecret) { + + const self = this; + + return Co(function * () { + + const get = Pify(self._oAuth.get.bind(self._oAuth), { multiArgs: true }); + const [userResponse] = yield get(internals.kVerifyCredentialsUrl, + oAuthAccessToken, + oAuthAccessTokenSecret); + + return JSON.parse(userResponse); + }); + } +}; diff --git a/package.json b/package.json index 6e8d9f1..ba898d2 100644 --- a/package.json +++ b/package.json @@ -23,5 +23,13 @@ "eslint-plugin-hapi": "^4.0.0" }, "dependencies": { + "getenv": "^0.7.0", + "jsonwebtoken": "^7.2.1", + "koa": "^1.2.4", + "koa-jwt": "^1.2.0", + "koa-route": "^2.4.2", + "koa-static": "^2.0.0", + "oauth": "^0.9.15", + "pify": "^2.3.0" } } diff --git a/static/css/app.css b/static/css/app.css new file mode 100644 index 0000000..956a281 --- /dev/null +++ b/static/css/app.css @@ -0,0 +1,42 @@ +* { + margin: 0; + padding: 0; +} + +/* General styles */ + +body { + font-family: "VT323", sans-serif; +} + +a { + color: #00e; +} + +a:active { + color: #e00; +} + +a:visited { + color: #551a8b; +} + +h1 { + font-size: 48px; +} + +section { + padding: 24px; +} + +/* Header */ + +#dasein .dasein-header { + text-align: center; +} + +#dasein .dasein-header a { + font-size: 96px; +} + +/* The stream */ diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000..24318f3 Binary files /dev/null and b/static/favicon.ico differ diff --git a/static/windex.html b/static/windex.html new file mode 100644 index 0000000..f4a6ac5 --- /dev/null +++ b/static/windex.html @@ -0,0 +1,36 @@ + + + + + + + ✨ dasein ✨ + + + + + + +
+
+ Dasein +
+ +
+

@rbdr

+
+ +
Hi, this is a test. 💸
+
+
+
+ + + diff --git a/yarn.lock b/yarn.lock index cc376fb..b8597b5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1,5 +1,14 @@ # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. # yarn lockfile v1 + + +accepts@^1.2.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" + dependencies: + mime-types "~2.1.11" + negotiator "0.6.1" + acorn-jsx@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" @@ -37,6 +46,10 @@ ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" +any-promise@^1.0.0, any-promise@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + argparse@^1.0.7: version "1.0.9" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" @@ -69,6 +82,10 @@ balanced-match@^0.4.1: version "0.4.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" +base64url@2.0.0, base64url@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/base64url/-/base64url-2.0.0.tgz#eac16e03ea1438eff9423d69baa36262ed1f70bb" + brace-expansion@^1.0.0: version "1.1.6" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" @@ -76,6 +93,10 @@ brace-expansion@^1.0.0: balanced-match "^0.4.1" concat-map "0.0.1" +buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + caller-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" @@ -110,7 +131,7 @@ cli-width@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" -co@^4.6.0: +co@^4.0.2, co@^4.4.0, co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -118,6 +139,13 @@ code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" +composition@^2.1.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/composition/-/composition-2.3.0.tgz#742805374cab550c520a33662f5a732e0208d6f2" + dependencies: + any-promise "^1.1.0" + co "^4.0.2" + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -130,6 +158,21 @@ concat-stream@^1.4.6: readable-stream "~2.0.0" typedarray "~0.0.5" +content-disposition@~0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + +content-type@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" + +cookies@~0.6.1: + version "0.6.2" + resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.6.2.tgz#6ac1b052895208e8fc4c4f5f86a9ed31b9cb5ccf" + dependencies: + depd "~1.1.0" + keygrip "~1.0.1" + core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -140,12 +183,16 @@ d@^0.1.1, d@~0.1.1: dependencies: es5-ext "~0.10.2" -debug@^2.1.1: - version "2.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" +debug@*, debug@^2.1.1: + version "2.4.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.4.4.tgz#c04d17a654e9202464803f096153f70a6f31f4be" dependencies: ms "0.7.2" +deep-equal@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" @@ -162,6 +209,18 @@ del@^2.0.2: pinkie-promise "^2.0.0" rimraf "^2.2.8" +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +depd@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" + +destroy@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + doctrine@^1.2.2: version "1.5.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" @@ -169,6 +228,21 @@ doctrine@^1.2.2: esutils "^2.0.2" isarray "^1.0.0" +ecdsa-sig-formatter@1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.9.tgz#4bc926274ec3b5abb5016e7e1d60921ac262b2a1" + dependencies: + base64url "^2.0.0" + safe-buffer "^5.0.1" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +error-inject@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/error-inject/-/error-inject-1.0.0.tgz#e2b3d91b54aed672f309d950d154850fa11d4f37" + es5-ext@^0.10.7, es5-ext@^0.10.8, es5-ext@~0.10.11, es5-ext@~0.10.2, es5-ext@~0.10.7: version "0.10.12" resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.12.tgz#aa84641d4db76b62abba5e45fd805ecbab140047" @@ -205,7 +279,7 @@ es6-set@~0.1.3: es6-symbol "3" event-emitter "~0.3.4" -es6-symbol@~3.1, es6-symbol@~3.1.0, es6-symbol@3: +es6-symbol@3, es6-symbol@~3.1, es6-symbol@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa" dependencies: @@ -221,6 +295,10 @@ es6-weak-map@^2.0.1: es6-iterator "2" es6-symbol "3" +escape-html@~1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -354,6 +432,10 @@ flat-cache@^1.2.1: graceful-fs "^4.1.2" write "^0.2.1" +fresh@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.3.0.tgz#651f838e22424e7566de161d8358caa199f83d4f" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -368,6 +450,10 @@ generate-object-property@^1.1.0: dependencies: is-property "^1.0.0" +getenv: + version "0.7.0" + resolved "https://registry.yarnpkg.com/getenv/-/getenv-0.7.0.tgz#39b91838707e2086fd1cf6ef8777d1c93e14649e" + glob@^7.0.0, glob@^7.0.3, glob@^7.0.5: version "7.1.1" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" @@ -416,6 +502,32 @@ has-ansi@^2.0.0: dependencies: ansi-regex "^2.0.0" +hoek@2.x.x: + version "2.16.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + +http-assert@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.2.0.tgz#d6392e6f6519def4e340266b35096db6d3feba00" + dependencies: + deep-equal "~1.0.0" + http-errors "~1.4.0" + +http-errors@^1.2.8, http-errors@~1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.5.1.tgz#788c0d2c1de2c81b9e6e8c01843b6b97eb920750" + dependencies: + inherits "2.0.3" + setprototypeof "1.0.2" + statuses ">= 1.3.1 < 2" + +http-errors@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.4.0.tgz#6c0242dea6b3df7afda153c71089b31c6e82aabf" + dependencies: + inherits "2.0.1" + statuses ">= 1.2.1 < 2" + ignore@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.0.tgz#8d88f03c3002a0ac52114db25d2c673b0bf1e435" @@ -431,10 +543,14 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@~2.0.1, inherits@2: +inherits@2, inherits@2.0.3, inherits@~2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + inquirer@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" @@ -502,10 +618,27 @@ is-resolvable@^1.0.0: dependencies: tryit "^1.0.1" +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" +isemail@1.x.x: + version "1.2.0" + resolved "https://registry.yarnpkg.com/isemail/-/isemail-1.2.0.tgz#be03df8cc3e29de4d2c5df6501263f1fa4595e9a" + +joi@^6.10.1: + version "6.10.1" + resolved "https://registry.yarnpkg.com/joi/-/joi-6.10.1.tgz#4d50c318079122000fe5f16af1ff8e1917b77e06" + dependencies: + hoek "2.x.x" + isemail "1.x.x" + moment "2.x.x" + topo "1.x.x" + js-tokens@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-2.0.0.tgz#79903f5563ee778cc1162e6dcf1a0027c97f9cb5" @@ -531,6 +664,117 @@ jsonpointer@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.0.tgz#6661e161d2fc445f19f98430231343722e1fcbd5" +jsonwebtoken@5.x.x: + version "5.7.0" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-5.7.0.tgz#1c90f9a86ce5b748f5f979c12b70402b4afcddb4" + dependencies: + jws "^3.0.0" + ms "^0.7.1" + xtend "^4.0.1" + +jsonwebtoken@^7.2.1: + version "7.2.1" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-7.2.1.tgz#0fc7217473fc02b4c9aa1e188aa70b51bba4fccb" + dependencies: + joi "^6.10.1" + jws "^3.1.4" + lodash.once "^4.0.0" + ms "^0.7.1" + xtend "^4.0.1" + +jwa@^1.1.4: + version "1.1.5" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.1.5.tgz#a0552ce0220742cd52e153774a32905c30e756e5" + dependencies: + base64url "2.0.0" + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.9" + safe-buffer "^5.0.1" + +jws@^3.0.0, jws@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.1.4.tgz#f9e8b9338e8a847277d6444b1464f61880e050a2" + dependencies: + base64url "^2.0.0" + jwa "^1.1.4" + safe-buffer "^5.0.1" + +keygrip@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.0.1.tgz#b02fa4816eef21a8c4b35ca9e52921ffc89a30e9" + +koa: + version "1.2.4" + resolved "https://registry.yarnpkg.com/koa/-/koa-1.2.4.tgz#6ef6d17a7bea8ec778a8572b55a0d0562e488654" + dependencies: + accepts "^1.2.2" + co "^4.4.0" + composition "^2.1.1" + content-disposition "~0.5.0" + content-type "^1.0.0" + cookies "~0.6.1" + debug "*" + delegates "^1.0.0" + destroy "^1.0.3" + error-inject "~1.0.0" + escape-html "~1.0.1" + fresh "^0.3.0" + http-assert "^1.1.0" + http-errors "^1.2.8" + koa-compose "^2.3.0" + koa-is-json "^1.0.0" + mime-types "^2.0.7" + on-finished "^2.1.0" + only "0.0.2" + parseurl "^1.3.0" + statuses "^1.2.0" + type-is "^1.5.5" + vary "^1.0.0" + +koa-compose@^2.3.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-2.5.1.tgz#726cfb17694de5cb9fbf03c0adf172303f83f156" + +koa-is-json@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/koa-is-json/-/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14" + +koa-jwt@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/koa-jwt/-/koa-jwt-1.2.0.tgz#c0589c2c27d7e0b497a22cb28575d0bc7dc0f959" + dependencies: + jsonwebtoken "5.x.x" + koa-unless "0.0.1" + thunkify "~2.1.x" + +koa-route@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/koa-route/-/koa-route-2.4.2.tgz#0de227989e6aa7334768abbfb16c519ad9a7fa71" + dependencies: + debug "*" + methods "~1.1.0" + path-to-regexp "^1.2.0" + +koa-send@~3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/koa-send/-/koa-send-3.1.1.tgz#ef0af0f9a531ec817e88056b52b8e32d2e0ba91a" + dependencies: + co "^4.6.0" + debug "*" + mz "^2.3.1" + resolve-path "^1.3.1" + +koa-static: + version "2.0.0" + resolved "https://registry.yarnpkg.com/koa-static/-/koa-static-2.0.0.tgz#2693482e1a4c0219e6d926be1703a2658b754f26" + dependencies: + debug "*" + koa-send "~3.1.0" + +koa-unless@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/koa-unless/-/koa-unless-0.0.1.tgz#cfcdd1cdfbaf066e05d843e6a412df8a7c69b218" + levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" @@ -538,10 +782,32 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + lodash@^4.0.0, lodash@^4.3.0: version "4.17.2" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.2.tgz#34a3055babe04ce42467b607d700072c7ff6bf42" +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + +methods@~1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + +mime-db@~1.25.0: + version "1.25.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.25.0.tgz#c18dbd7c73a5dbf6f44a024dc0d165a1e7b1c392" + +mime-types@^2.0.7, mime-types@~2.1.11, mime-types@~2.1.13: + version "2.1.13" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.13.tgz#e07aaa9c6c6b9a7ca3012c69003ad25a39e92a88" + dependencies: + mime-db "~1.25.0" + minimatch@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" @@ -558,7 +824,11 @@ mkdirp@^0.5.0, mkdirp@^0.5.1: dependencies: minimist "0.0.8" -ms@0.7.2: +moment@2.x.x: + version "2.17.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.17.1.tgz#fed9506063f36b10f066c8b59a144d7faebe1d82" + +ms@0.7.2, ms@^0.7.1: version "0.7.2" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" @@ -566,10 +836,22 @@ mute-stream@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" +mz@^2.3.1: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.6.0.tgz#c8b8521d958df0a4f2768025db69c719ee4ef1ce" + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + no-arrowception@1.x.x: version "1.0.0" resolved "https://registry.yarnpkg.com/no-arrowception/-/no-arrowception-1.0.0.tgz#5bf3e95eb9c41b57384a805333daa3b734ee327a" @@ -578,10 +860,20 @@ number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" +oauth: + version "0.9.15" + resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1" + object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" +on-finished@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -592,6 +884,10 @@ onetime@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" +only@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" + optionator@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" @@ -607,7 +903,11 @@ os-homedir@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" -path-is-absolute@^1.0.0: +parseurl@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" + +path-is-absolute@1.0.1, path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" @@ -615,7 +915,13 @@ path-is-inside@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" -pify@^2.0.0: +path-to-regexp@^1.2.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" + dependencies: + isarray "0.0.1" + +pify, pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -681,6 +987,13 @@ resolve-from@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" +resolve-path@^1.3.1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/resolve-path/-/resolve-path-1.3.3.tgz#4d83aba6468c2b8e632a575e3f52b0fa0dbe1a5c" + dependencies: + http-errors "~1.5.0" + path-is-absolute "1.0.1" + resolve@^1.1.6: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" @@ -708,6 +1021,14 @@ rx-lite@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" +safe-buffer@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7" + +setprototypeof@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.2.tgz#81a552141ec104b88e89ce383103ad5c66564d08" + shelljs@^0.7.5: version "0.7.5" resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.5.tgz#2eef7a50a21e1ccf37da00df767ec69e30ad0675" @@ -724,9 +1045,9 @@ sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" +"statuses@>= 1.2.1 < 2", "statuses@>= 1.3.1 < 2", statuses@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" string-width@^1.0.1: version "1.0.2" @@ -743,6 +1064,10 @@ string-width@^2.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^3.0.0" +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + strip-ansi@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" @@ -776,10 +1101,32 @@ text-table@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.2.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.2.1.tgz#251fd1c80aff6e5cf57cb179ab1fcb724269bd11" + dependencies: + any-promise "^1.0.0" + through@^2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" +thunkify@~2.1.x: + version "2.1.2" + resolved "https://registry.yarnpkg.com/thunkify/-/thunkify-2.1.2.tgz#faa0e9d230c51acc95ca13a361ac05ca7e04553d" + +topo@1.x.x: + version "1.1.0" + resolved "https://registry.yarnpkg.com/topo/-/topo-1.1.0.tgz#e9d751615d1bb87dc865db182fa1ca0a5ef536d5" + dependencies: + hoek "2.x.x" + tryit@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" @@ -790,6 +1137,13 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" +type-is@^1.5.5: + version "1.6.14" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.13" + typedarray@~0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" @@ -804,6 +1158,10 @@ util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" +vary@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.0.tgz#e1e5affbbd16ae768dd2674394b9ad3022653140" + wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" @@ -818,7 +1176,6 @@ write@^0.2.1: dependencies: mkdirp "^0.5.1" -xtend@^4.0.0: +xtend@^4.0.0, xtend@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" - -- cgit From a6ccda0fbc4df683f9568d85eb22b21684d2a0bd Mon Sep 17 00:00:00 2001 From: Rubén Beltrán del Río Date: Mon, 30 Jan 2017 02:47:14 -0600 Subject: Create and Show Posts (#3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 📝 Update changelog (retroactive) SORRY * Add JSDoc * Document twitter helper * Add posts handler * Remove cookies, set routes under /api * Update readme for clearer callback instructions * Redirect callback to login with token * Add dasein paw helper * Remove unused hostname * Remove hostname, add expiration to config * Rename expiration ttl * Send TTL to posts handler * Add redis dependency * Add redis config to config file * Add DASEIN_REDIS_HOST to env.dist * Correct redis config structure * Add redis db to compose * Add redis to posts handler * Update dasein paw file * Git add uuid * Add first iteration of post handlers * Ignore docs in linter * Ignore generated assets * Ignore docs and assets * Add frontend dependencies + more koa * Add post creation to backend * Adjust readme to show actual callback route * Add npm build as part of docker process * Configure babel * Update paw * Add webpack config * Add frontend code * List globals --- .babelrc | 3 + .dockerignore | 1 + .eslintignore | 2 + .gitignore | 6 + CHANGELOG.md | 3 +- Dockerfile | 2 + README.md | 5 +- app/.eslintrc | 5 + app/components/login.js | 46 + app/components/post_form.js | 57 ++ app/components/posts.js | 77 ++ app/components/welcome.js | 39 + app/dasein.js | 90 ++ app/filters/datetime.js | 10 + app/filters/usertime.js | 20 + app/services/auth.js | 75 ++ config/config.js | 69 +- config/env.dist | 2 +- config/jsdoc.json | 9 + config/webpack.js | 43 + docker-compose.yml | 6 + etc/dasein.paw | Bin 0 -> 16889 bytes lib/dasein.js | 91 +- lib/handlers/auth.js | 73 +- lib/handlers/posts.js | 177 ++++ lib/twitter_helper.js | 64 ++ package.json | 22 +- static/css/app.css | 51 ++ static/index.html | 24 + static/windex.html | 36 - yarn.lock | 2009 ++++++++++++++++++++++++++++++++++++++++++- 31 files changed, 2984 insertions(+), 133 deletions(-) create mode 100644 .babelrc create mode 100644 .eslintignore create mode 100644 app/.eslintrc create mode 100644 app/components/login.js create mode 100644 app/components/post_form.js create mode 100644 app/components/posts.js create mode 100644 app/components/welcome.js create mode 100644 app/dasein.js create mode 100644 app/filters/datetime.js create mode 100644 app/filters/usertime.js create mode 100644 app/services/auth.js create mode 100644 config/jsdoc.json create mode 100644 config/webpack.js create mode 100644 etc/dasein.paw create mode 100644 lib/handlers/posts.js create mode 100644 static/index.html delete mode 100644 static/windex.html (limited to 'lib/dasein.js') diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..5686105 --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["latest"] +} diff --git a/.dockerignore b/.dockerignore index 8d87b1d..fa078bb 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1 +1,2 @@ node_modules/* +doc/* diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..04afc86 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +doc +static/assets diff --git a/.gitignore b/.gitignore index ce59e98..a3ac6ce 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,9 @@ jspm_packages # Env files .env + +# Documentation +doc + +# Generated assets +static/assets diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d54d18..425a9d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] - 2016-12-12 ### Added -- Dummy project files +- JSDoc config +- Twitter OAuth Integration - Simple contributing guidelines - Eslint configuration - Docker configuration diff --git a/Dockerfile b/Dockerfile index 5e2f7f9..85d78c2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,4 +11,6 @@ COPY yarn.lock /app/ RUN yarn install COPY . /app +RUN npm run build + ENTRYPOINT [ "node", "bin/dasein" ]) diff --git a/README.md b/README.md index 584a258..cda0252 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,9 @@ way. ## Generating documentation -This project uses JS Doc to generate documentation. Generate everything -with `npm run doc`. +This project uses JSDoc to generate documentation. Generate everything +with `npm run document`. The documentation will be generated in the +`doc` directory. ## Building and pushing the image diff --git a/app/.eslintrc b/app/.eslintrc new file mode 100644 index 0000000..bd14a19 --- /dev/null +++ b/app/.eslintrc @@ -0,0 +1,5 @@ +{ + "parserOptions": { + "sourceType": "module" + } +} diff --git a/app/components/login.js b/app/components/login.js new file mode 100644 index 0000000..d900c72 --- /dev/null +++ b/app/components/login.js @@ -0,0 +1,46 @@ +import Vue from 'vue'; +import AuthService from '../services/auth'; + +const internals = {}; + +export default internals.LoginComponent = Vue.component('login', { + template: '', + + props: ['oAuthToken', 'oAuthVerifier'], + + data() { + + return { + message: 'Logging you in... Wait a sec.', + authService: new AuthService() + }; + }, + methods: { + login() { + + if (this.authService.authenticated) { + return this.$router.push('/'); + } + + return this.authService.getUserObject(this.oAuthToken, this.oAuthVerifier).then((response) => { + + console.log(response); + + return this.authService.login(response.user, response.token, response.expiresAt); + }).then(() => { + + this.$router.push('/'); + }).catch((err) => { + + console.error(err); + this.message = 'Oh no! There was a problem logging you in.'; + }); + } + }, + mounted: function mounted() { + + this.login(); + } +}); diff --git a/app/components/post_form.js b/app/components/post_form.js new file mode 100644 index 0000000..cee17b0 --- /dev/null +++ b/app/components/post_form.js @@ -0,0 +1,57 @@ +import Axios from 'axios'; +import Vue from 'vue'; +import AuthService from '../services/auth'; + +const internals = {}; + +internals.kPostsRoute = '/api/posts'; + +export default internals.PostFormComponent = Vue.component('post-form', { + template: '
' + + '

sup.

' + + '' + + '

{{message}}

' + + '' + + '
', + + data() { + + return { + content: '', + message: '', + submitting: false, + authService: new AuthService() + }; + }, + + methods: { + submit() { + + this.submitting = true; + + return Axios({ + method: 'post', + headers: { + Authorization: `Bearer ${this.authService.token}` + }, + data: { + content: this.content + }, + url: internals.kPostsRoute + }).then((response) => { + + this.$emit('post-submitted', response.data); + this.content = ''; + this.message = ''; + this.submitting = false; + }).catch((err) => { + + console.error(err.stack); + this.submitting = false; + this.message = 'Error while creating the post...'; + }); + } + } +}); + + diff --git a/app/components/posts.js b/app/components/posts.js new file mode 100644 index 0000000..c41707f --- /dev/null +++ b/app/components/posts.js @@ -0,0 +1,77 @@ +import Axios from 'axios'; +import Vue from 'vue'; +import AuthService from '../services/auth'; + +import PostFormComponent from './post_form'; +import DatetimeFilter from '../filters/datetime'; +import UsertimeFilter from '../filters/usertime'; + +const internals = {}; + +internals.kPostsRoute = '/api/posts'; + +export default internals.PostsComponent = Vue.component('posts', { + template: '
' + + '' + + '

Posts.

' + + '

{{message}}

' + + '
' + + '' + + '
{{post.content}}
' + + '
' + + '
', + + data() { + + return { + message: '', + authService: new AuthService(), + posts: [] + }; + }, + + methods: { + fetchPosts() { + + return Axios({ + method: 'get', + headers: { + Authorization: `Bearer ${this.authService.token}` + }, + url: internals.kPostsRoute + }).then((response) => { + + this.posts = response.data; + }).catch((err) => { + + console.err(err.stack); + this.message = 'Error while loading the posts...'; + }); + }, + + addPost(post) { + + this.posts.unshift(post); + } + }, + + components: { + postForm: PostFormComponent, + datetime: DatetimeFilter, + usertime: UsertimeFilter + }, + + mounted: function mounted() { + + if (!this.authService.authenticated) { + return this.$router.push('/login'); + } + + return this.fetchPosts(); + } +}); + diff --git a/app/components/welcome.js b/app/components/welcome.js new file mode 100644 index 0000000..4fcee0f --- /dev/null +++ b/app/components/welcome.js @@ -0,0 +1,39 @@ +import Vue from 'vue'; +import AuthService from '../services/auth'; + +/* global window */ + +const internals = {}; + +export default internals.WelcomeComponent = Vue.component('welcome', { + template: '
' + + '

{{message}}

' + + 'Login' + + '
', + + data() { + + return { + message: 'Welcome to Dasein, a social network with posts that disappear when the conversation stops', + loggingIn: false, + authService: new AuthService() + }; + }, + + methods: { + initiateLogin() { + + this.message = 'Logging you in...'; + this.loggingIn = true; + + this.authService.initiateLogin().then((authData) => { + + window.location.href = authData.loginUrl; + }).catch((err) => { + + console.error(err); + this.message = 'Oh no! There was a problem logging you in.'; + }); + } + } +}); diff --git a/app/dasein.js b/app/dasein.js new file mode 100644 index 0000000..6b3fd95 --- /dev/null +++ b/app/dasein.js @@ -0,0 +1,90 @@ +import Vue from 'vue'; +import VueRouter from 'vue-router'; + +import AuthService from './services/auth'; + +import LoginComponent from './components/login'; +import WelcomeComponent from './components/welcome'; +import PostsComponent from './components/posts'; + +/* global window */ + +const internals = {}; + +export default internals.Dasein = { + + start() { + + this._setupVue(); + + internals.authService = new AuthService(); + + this.vm = new Vue({ + router: this._setupRouter(), + el: '#dasein', + components: { + login: LoginComponent, + welcome: WelcomeComponent + }, + data: { + message: 'Hello Vue!' + }, + methods: { + authenticated() { + + return internals.authService.authenticated; + } + } + }); + + }, + + // Initializes vue options + + _setupVue() { + + Vue.use(VueRouter); + }, + + // Sets up the routes + + _setupRouter() { + + const routes = [ + { + path: '/login', + component: WelcomeComponent + }, + { + path: '/', + component: PostsComponent + }, + { + path: '/login-callback', + component: LoginComponent, + props: (route) => { + + return { + oAuthToken: route.query.oauth_token, + oAuthVerifier: route.query.oauth_verifier + }; + } + } + ]; + + const router = new VueRouter({ + mode: 'history', + routes + }); + + return router; + } +}; + + +internals.run = function () { + + internals.Dasein.start(); +}; + +window.addEventListener('load', internals.run); diff --git a/app/filters/datetime.js b/app/filters/datetime.js new file mode 100644 index 0000000..e4bf432 --- /dev/null +++ b/app/filters/datetime.js @@ -0,0 +1,10 @@ +import Vue from 'vue'; + +const internals = {}; + +export default internals.DatetimeFilter = Vue.filter('datetime', (timestamp) => { + + const date = new Date(parseInt(timestamp)); + + return date.toISOString(); +}); diff --git a/app/filters/usertime.js b/app/filters/usertime.js new file mode 100644 index 0000000..de67894 --- /dev/null +++ b/app/filters/usertime.js @@ -0,0 +1,20 @@ +import Vue from 'vue'; + +const internals = {}; + +export default internals.UsertimeFilter = Vue.filter('usertime', (timestamp) => { + + const date = new Date(parseInt(timestamp)); + + const dateString = date.toISOString(); + + const dateComponents = dateString.split('T'); + const dateFragment = dateComponents[0]; + const timeComponents = dateComponents[1].split(':'); + + const hourFragment = timeComponents[0]; + const minuteFragment = timeComponents[1]; + + return `${dateFragment} ${hourFragment}:${minuteFragment}`; +}); + diff --git a/app/services/auth.js b/app/services/auth.js new file mode 100644 index 0000000..32db321 --- /dev/null +++ b/app/services/auth.js @@ -0,0 +1,75 @@ +import Axios from 'axios'; + +const internals = {}; + +/* global localStorage */ + +internals.kInitiateLoginRoute = '/api/auth/login'; +internals.kHandleCallbackRoute = '/api/auth/callback'; + +export default internals.AuthService = class AuthService { + + constructor() { + + this.authenticated = false; + + // Bootstrap from local storage. + if (localStorage.hasOwnProperty('user') && localStorage.hasOwnProperty('token') + && localStorage.hasOwnProperty('expiresAt')) { + + if (parseInt(localStorage.getItem('expiresAt')) > Date.now()) { + this.expiresAt = localStorage.getItem('expiresAt'); + this.user = JSON.parse(localStorage.getItem('user')); + this.token = localStorage.getItem('token'); + this.authenticated = true; + } + } + } + + // Initiates the login process. Resolves to an object that contains the URL + // to redirect to to continue processing. + initiateLogin() { + + return Axios.get(internals.kInitiateLoginRoute).then((response) => { + + return response.data; + }); + } + + // Posts the oAuthToken and verifier to the API to get back a user object + // and a signed JWT + getUserObject(oAuthToken, oAuthVerifier) { + + return Axios.post(internals.kHandleCallbackRoute, { + oAuthToken, + oAuthVerifier + }).then((response) => { + + return response.data; + }); + } + + // Logs in the user by setting the user and token + login(user, token, expiresAt) { + + localStorage.setItem('user', JSON.stringify(user)); + localStorage.setItem('token', token); + localStorage.setItem('expiresAt', expiresAt); + this.user = user; + this.token = token; + this.expiresAt = expiresAt; + this.authenticated = true; + } + + // Logs a user out by removing the user and token + logout() { + + localStorage.removeItem('user'); + localStorage.removeItem('token'); + localStorage.removeItem('expiresAt'); + delete this.user; + delete this.token; + delete this.expiresAt; + this.authenticated = false; + } +}; diff --git a/config/config.js b/config/config.js index 1c1c8a0..c82dced 100644 --- a/config/config.js +++ b/config/config.js @@ -4,18 +4,69 @@ const Getenv = require('getenv'); const internals = {}; +/** + * The main configuration object for Dasein. It will be used to + * initialize all of the sub-components. It can extend any property of + * the dasein object. + * + * @memberof Dasein + * @typedef {object} tConfiguration + * @property {number} [port=1927] the port where the app will listen on + * @property {string} [staticDirectory=static] the path, relative to the + * project root, where static assets live + * @property {number} [ttl=180] the time in seconds that posts + * remain alive + * @property {Dasein.tRedisConfiguration} redis the configuration to + * connect to the redis server + * @property {Dasein.tJWTConfiguration} jwt the configuration for the + * JWT authentication + * @property {Dasein.tTwitterConfiguration} twitter the configuration + * for twitter integration + */ module.exports = internals.Config = { - cookieKeys: Getenv.array('DASEIN_COOKIE_KEYS'), // Signatures for the cookies - port: Getenv.int('DASEIN_PORT', 1927), // Port to listen on - hostname: Getenv('DASEIN_HOSTNAME', 'localhost'), // Domain to listen on, used for cookies - staticDirectory: Getenv('DASEIN_STATIC_DIRECTORY', 'static'), // Location of static assets + port: Getenv.int('DASEIN_PORT', 1927), + staticDirectory: Getenv('DASEIN_STATIC_DIRECTORY', 'static'), + ttl: Getenv.int('DASEIN_TTL', 180), + + /** + * Configures the behavior of the JWT token. + * + * @memberof Dasein + * @typedef {object} tJWTConfiguration + * @property {number} [duration=86400] the duration of the JWT in + * seconds + * @property {string} secret the secret used to sign the JWT + */ jwt: { - cookieName: Getenv('DASEIN_JWT_COOKIE_NAME', 'dasein_jwt'), // Name of cookie where jwt is stored - duration: Getenv('DASEIN_JWT_DURATION', 86400), // Duration of JWT (24 hours) - secret: Getenv('DASEIN_JWT_SECRET') // Secret to sign JWT + duration: Getenv.int('DASEIN_JWT_DURATION', 86400), + secret: Getenv('DASEIN_JWT_SECRET') + }, + + /** + * Information required to connect to the redis server + * + * @memberof Dasein + * @typedef {object} tRedisConfiguration + * @property {string} host the location of the redis host + * @property {string} [post=6379] port where redis server is listening + */ + redis: { + host: Getenv('DASEIN_REDIS_HOST'), + port: Getenv.int('DASEIN_REDIS_PORT', 6379) }, + + /** + * Configures the twitter integration values + * + * @memberof Dasein + * @typedef {object} tTwitterConfiguration + * @property {string} consumerKey The consumer key used to authenticate + * with the twitter API + * @property {string} consumerSecret the consumer secret used to + * authenticate with the twitter API + */ twitter: { - consumerKey: Getenv('DASEIN_TWITTER_CONSUMER_KEY'), // Consumer key for twitter - consumerSecret: Getenv('DASEIN_TWITTER_CONSUMER_SECRET') // Consumer secret for twitter + consumerKey: Getenv('DASEIN_TWITTER_CONSUMER_KEY'), + consumerSecret: Getenv('DASEIN_TWITTER_CONSUMER_SECRET') } }; diff --git a/config/env.dist b/config/env.dist index ee23ee1..ffb50f2 100644 --- a/config/env.dist +++ b/config/env.dist @@ -1,4 +1,4 @@ -DASEIN_COOKIE_KEYS=comma,separated,keys +DASEIN_REDIS_HOST=location_of_redis_server DASEIN_TWITTER_CONSUMER_KEY=your_twitter_key DASEIN_TWITTER_CONSUMER_SECRET=your_twitter_secret DASEIN_JWT_SECRET=some_random_string diff --git a/config/jsdoc.json b/config/jsdoc.json new file mode 100644 index 0000000..9e05753 --- /dev/null +++ b/config/jsdoc.json @@ -0,0 +1,9 @@ +{ + "plugins": ["plugins/markdown"], + "opts": { + "destination": "doc", + "readme": "README.md", + "template": "node_modules/docdash", + "recurse": true + } +} diff --git a/config/webpack.js b/config/webpack.js new file mode 100644 index 0000000..f808b06 --- /dev/null +++ b/config/webpack.js @@ -0,0 +1,43 @@ +'use strict'; + +const Path = require('path'); + +module.exports = { + entry: './app/dasein', + + output: { + path: Path.resolve(__dirname, '../static/assets'), + filename: 'bundle.js', + publicPath: '/assets/', + library: 'Dasein', + libraryTarget: 'umd' + }, + + module: { + loaders: [ + { + test: /\.js$/, + exclude: /(node_modules|doc)/, + loader: 'babel-loader', + query: { + presets: ['es2015'] + } + } + ] + }, + + resolve: { + modules: [ + 'node_modules', + Path.resolve(__dirname, '../app') + ], + + alias: { + 'vue$': 'vue/dist/vue.common.js' + } + }, + + extensions: ['.js', '.json', '.css'], + + context: Path.resolve(__dirname, '..') +}; diff --git a/docker-compose.yml b/docker-compose.yml index 92205a9..1a6c9cf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,5 +5,11 @@ services: build: . env_file: .env image: rbdr/dasein + environment: + - DASEIN_REDIS_HOST=db ports: - "1927:1927" + depends_on: + - db + db: + image: redis:3.2.6 diff --git a/etc/dasein.paw b/etc/dasein.paw new file mode 100644 index 0000000..9983dad Binary files /dev/null and b/etc/dasein.paw differ diff --git a/lib/dasein.js b/lib/dasein.js index 38654a4..3a537bd 100644 --- a/lib/dasein.js +++ b/lib/dasein.js @@ -1,17 +1,28 @@ 'use strict'; const Koa = require('koa'); +const KoaBodyParser = require('koa-bodyparser'); const KoaJwt = require('koa-jwt'); -const KoaStatic = require('koa-static'); const KoaRoute = require('koa-route'); +const KoaSend = require('koa-send'); +const KoaStatic = require('koa-static'); +const Path = require('path'); const AuthHandler = require('./handlers/auth'); +const PostsHandler = require('./handlers/posts'); const internals = {}; internals.k401Location = '/401.html'; internals.kMainLocation = '/'; +/** + * The Dasein class is the main entry point for the application. + * + * @class Dasein + * @param {Dasein.tConfiguration} config the initialization options to + * extend the instance + */ module.exports = internals.Dasein = class Dasein { constructor(config) { @@ -19,6 +30,14 @@ module.exports = internals.Dasein = class Dasein { Object.assign(this, config); } + /** + * Initializes the application and starts listening. Also prints a + * nice robotic banner with information. + * + * @function run + * @memberof Dasein + * @instance + */ run() { this._initializeServer(); @@ -28,15 +47,18 @@ module.exports = internals.Dasein = class Dasein { return Promise.resolve(); } + // Initializes the Koa application and all the handlers. + _initializeServer() { - this._app = Koa(); + const self = this; - this._app.keys = this.cookieKeys; + this._app = Koa(); this._app.use(KoaStatic(this.staticDirectory)); + this._app.use(KoaBodyParser()); - // Redirect all 401s to the 401 static page + // Error handler this._app.use(function * (next) { @@ -44,51 +66,74 @@ module.exports = internals.Dasein = class Dasein { yield next; } catch (err) { - if (err.status === 401) { - return this.redirect(internals.k401Location); + this.status = err.status || 500; + + const response = { + error: err.message, + status: this.status + }; + + if (response.status === 401) { + response.error === 'Protected resource, use Authorization header to get access'; } - throw err; + this.body = response; + + this.app.emit('error', err, this); } }); this._app.use(KoaJwt({ secret: this.jwt.secret, - passthrough: true, - cookie: this.jwt.cookieName + passthrough: true })); - // Handlers for Twitter Auth Related Routes + this._initializeAuthRoutes(); + this._initializePostsRoutes(); + + this._app.use(function * () { + + yield KoaSend(this, Path.join(self.staticDirectory, 'index.html')); + }); + + } + + // Initialize routes for auth + + _initializeAuthRoutes() { const authHandler = new AuthHandler({ - hostname: this.hostname, jwt: this.jwt, twitter: this.twitter }); - this._app.use(KoaRoute.get('/login', authHandler.login())); - this._app.use(KoaRoute.get('/login-callback', authHandler.callback())); - this._app.use(KoaRoute.get('/logout', authHandler.logout())); + this._app.use(KoaRoute.get('/api/auth/login', authHandler.login())); + this._app.use(KoaRoute.post('/api/auth/callback', authHandler.callback())); + } - // The index + // Initialize routes for posts - this._app.use(function * () { + _initializePostsRoutes() { - if (this.state.user) { - this.body = ` Hello ${this.state.user.screen_name}`; - return; - } - - this.body = 'Go to /login to login'; - return; + const postsHandler = new PostsHandler({ + ttl: this.ttl, + redis: this.redis }); + this._app.use(KoaRoute.get('/api/posts', postsHandler.findAll())); + this._app.use(KoaRoute.get('/api/posts/:id', postsHandler.find())); + this._app.use(KoaRoute.post('/api/posts', postsHandler.create())); + this._app.use(KoaRoute.delete('/api/posts/:id', postsHandler.delete())); + } + // Starts listening + _startServer() { this._app.listen(this.port); } // Prints the banner. + _printBanner() { console.log(' .'); diff --git a/lib/handlers/auth.js b/lib/handlers/auth.js index d16e15d..1db9494 100644 --- a/lib/handlers/auth.js +++ b/lib/handlers/auth.js @@ -1,41 +1,63 @@ 'use strict'; const Co = require('co'); -const TwitterHelper = require('../twitter_helper'); const JsonWebToken = require('jsonwebtoken'); const Pify = require('pify'); +const TwitterHelper = require('../twitter_helper'); const internals = {}; internals.kRedirectUrl = 'https://api.twitter.com/oauth/authenticate?oauth_token='; -internals.kMainLocation = '/'; +internals.kLoginRedirect = '/login'; internals.signJsonWebToken = Pify(JsonWebToken.sign); +/** + * Handles the HTTP requests for auth related operations. + * + * @class AuthHandler + * @param {Dasein.tConfiguration} config The configuration to + * initialize. + */ module.exports = internals.AuthHandler = class AuthHandler { constructor(config) { this._twitterHelper = new TwitterHelper(config.twitter); this._jwtConfig = config.jwt; - this._hostname = config.hostname; } + /** + * Triggers the twitter login flow. Redirects to twitter's oauth + * request page + * + * @function login + * @memberof AuthHandler + * @instance + * @return {generator} a koa compatible handler generator function + */ login() { const twitterHelper = this._twitterHelper; return function *handleLogin() { - if (this.state.user) { - return this.redirect(internals.kMainLocation); - } - const requestToken = yield twitterHelper.getRequestToken(); - this.redirect(`${internals.kRedirectUrl}${requestToken.oAuthToken}`); + const loginUrl = `${internals.kRedirectUrl}${requestToken.oAuthToken}`; + + this.body = { loginUrl }; }; } + /** + * Handles twitter's callback. Fetches the oAuth Verifier, attempts to + * obtain a user object and responds with the JWT + * + * @function callback + * @memberof AuthHandler + * @instance + * @return {generator} a koa compatible handler generator function + */ callback() { const self = this; @@ -46,8 +68,8 @@ module.exports = internals.AuthHandler = class AuthHandler { return this.throw(401); } - const oAuthToken = this.request.query.oauth_token; - const oAuthVerifier = this.request.query.oauth_verifier; + const oAuthToken = this.request.body.oAuthToken; + const oAuthVerifier = this.request.body.oAuthVerifier; let user; try { @@ -59,25 +81,23 @@ module.exports = internals.AuthHandler = class AuthHandler { return this.throw(401); } - yield self._setJWT(user, this); - - this.redirect(internals.kMainLocation); - }; - } - - logout() { + const expiresAt = Date.now() + self._jwtConfig.duration * 1000; - const self = this; + const token = yield self._getToken(user); - return function * () { + const response = { + expiresAt, + user, + token + }; - this.cookies.set(self._jwtConfig.cookieName, null); - this.redirect(internals.kMainLocation); + this.body = response; }; } - // Sets a JSON Web Token Cookie - _setJWT(payload, context) { + // Generates a JSON Web Token + + _getToken(payload) { const self = this; @@ -87,12 +107,7 @@ module.exports = internals.AuthHandler = class AuthHandler { expiresIn: self._jwtConfig.duration }); - context.cookies.set(self._jwtConfig.cookieName, token, { - maxAge: self._jwtConfig.duration * 1000, - signed: true, - domain: self._hostname, - overwrite: true - }); + return token; }); } }; diff --git a/lib/handlers/posts.js b/lib/handlers/posts.js new file mode 100644 index 0000000..425fb5e --- /dev/null +++ b/lib/handlers/posts.js @@ -0,0 +1,177 @@ +'use strict'; + +const Joi = require('joi'); +const Pify = require('pify'); +const Redis = require('redis'); +const UUID = require('uuid/v4'); + +const internals = {}; + +internals.kPostsPrefix = 'posts'; +internals.kMaxPostSize = 255; + +internals.kPostsSchema = Joi.object().keys({ + uuid: Joi.string().required(), + content: Joi.string().max(internals.kMaxPostSize).required(), + timestamp: Joi.number().integer().required(), + userId: Joi.string().required(), + userName: Joi.string().required(), + userImage: Joi.string().required() +}); + +/** + * Handles the HTTP requests for posts related operations + * + * @class PostsHandler + * @param {Dasein.tConfiguration} config The configuration to + * initialize. + */ +module.exports = internals.PostsHandler = class PostsHandler { + constructor(config) { + + this._ttl = config.ttl; + this._redis = Redis.createClient(config.redis); + + // Log an error if it happens. + this._redis.on('error', (err) => { + + console.error(err); + }); + } + + /** + * Fetches all available posts + * + * @function findAll + * @memberof PostsHandler + * @instance + * @return {generator} a koa compatible handler generator function + */ + findAll() { + + const self = this; + + return function * () { + + if (!this.state.user) { + return this.throw('Unauthorized', 401); + } + + const scan = Pify(self._redis.scan.bind(self._redis)); + const hgetall = Pify(self._redis.hgetall.bind(self._redis)); + + const cursor = parseInt(this.request.query.cursor) || 0; + const [nextCursor, keys] = yield scan(cursor, 'MATCH', `${internals.kPostsPrefix}:*`); + + if (nextCursor > 0) { + this.append('Link', `<${this.request.origin}${this.request.path}?cursor=${nextCursor}>; rel="next"`); + } + + const posts = yield keys.map((key) => hgetall(key)); + + this.body = posts; + }; + } + + /** + * Fetches a single post + * + * @function find + * @memberof PostsHandler + * @instance + * @return {generator} a koa compatible handler generator function + */ + find() { + + const self = this; + + return function * (uuid) { + + if (!this.state.user) { + return this.throw('Unauthorized', 401); + } + + const hgetall = Pify(self._redis.hgetall.bind(self._redis)); + + const postKey = `${internals.kPostsPrefix}:${uuid}`; + + const post = yield hgetall(postKey); + + if (!post) { + this.throw('Post not found', 404); + } + + this.body = post; + }; + } + + /** + * Creates a post + * + * @function create + * @memberof PostsHandler + * @instance + * @return {generator} a koa compatible handler generator function + */ + create() { + + const self = this; + + return function * () { + + if (!this.state.user) { + return this.throw('Unauthorized', 401); + } + + const hmset = Pify(self._redis.hmset.bind(self._redis)); + const hgetall = Pify(self._redis.hgetall.bind(self._redis)); + const expire = Pify(self._redis.expire.bind(self._redis)); + + const uuid = UUID(); + const timestamp = Date.now(); + const user = this.state.user; + + const postKey = `${internals.kPostsPrefix}:${uuid}`; + + const post = { + uuid, + content: this.request.body.content, + timestamp, + userId: user.screen_name, + userName: user.name, + userImage: user.profile_image_url_https + }; + + yield self._validate(post).catch((err) => { + + this.throw(err.message, 422); + }); + + yield hmset(postKey, post); + yield expire(postKey, self._ttl); + + this.body = yield hgetall(postKey); + }; + } + + /** + * Deletes a post + * + * @function delete + * @memberof PostsHandler + * @instance + * @return {generator} a koa compatible handler generator function + */ + delete() { + + return function * () {}; + } + + // Validates the post schema + + _validate(post) { + + const validate = Pify(Joi.validate.bind(Joi)); + return validate(post, internals.kPostsSchema); + } +}; diff --git a/lib/twitter_helper.js b/lib/twitter_helper.js index 3ab51fa..6edf030 100644 --- a/lib/twitter_helper.js +++ b/lib/twitter_helper.js @@ -12,6 +12,16 @@ internals.kVerifyCredentialsUrl = 'https://api.twitter.com/1.1/account/verify_cr internals.kOauthVersion = '1.0A'; internals.kOauthSignatureMethod = 'HMAC-SHA1'; +/** + * Helper to communicate with the twitter API + * + * @class TwitterHelper + * @param {Dasein.tTwitterConfiguration} config the configuration to + * initialize the twitter API + * @see {@link https://dev.twitter.com/web/sign-in/implementing|Implementing + * Sign in with Twitter} + * + */ module.exports = internals.TwitterHelper = class TwitterHelper { constructor(config) { @@ -27,6 +37,14 @@ module.exports = internals.TwitterHelper = class TwitterHelper { ); } + /** + * Calls the API to get a request token. + * + * @function getRequestToken + * @memberof TwitterHelper + * @instance + * @return {Promise} the request token response + */ getRequestToken() { const self = this; @@ -36,6 +54,15 @@ module.exports = internals.TwitterHelper = class TwitterHelper { const getOAuthRequestToken = Pify(self._oAuth.getOAuthRequestToken.bind(self._oAuth), { multiArgs: true }); const [oAuthToken, oAuthTokenSecret] = yield getOAuthRequestToken(); + /** + * The request token and secret pair from the twitter API + * + * @memberof TwitterHelper + * @typedef {object} tRequestToken + * @property {string} oAuthToken The oAuth request token + * @property {string} oAuthTokenSecret The oAuth request token + * secret + */ return { oAuthToken, oAuthTokenSecret @@ -43,6 +70,17 @@ module.exports = internals.TwitterHelper = class TwitterHelper { }); } + /** + * Calls the API to get an access token + * + * @function getAccessToken + * @memberof TwitterHelper + * @instance + * @param {string} oAuthToken An oAuth request token + * @param {string} oAuthVerifier An oAuth verifier sent from the + * twitter callback + * @return {Promise} the acess token response + */ getAccessToken(oAuthToken, oAuthVerifier) { const self = this; @@ -54,6 +92,15 @@ module.exports = internals.TwitterHelper = class TwitterHelper { '', oAuthVerifier); + /** + * The access token and secret pair from the twitter API + * + * @memberof TwitterHelper + * @typedef {object} tAccessToken + * @property {string} oAuthAccessToken The oAuth access token + * @property {string} oAuthAccessTokenSecret The oAuth access token + * secret + */ return { oAuthAccessToken, oAuthAccessTokenSecret @@ -61,6 +108,17 @@ module.exports = internals.TwitterHelper = class TwitterHelper { }); } + /** + * Gets a user object from twitter + * + * @function getUser + * @memberof TwitterHelper + * @instance + * @param {string} oAuthAccessToken An oAuth access token + * @param {string} oAuthAccessTokenSecret An oAuth access token secret + * @return {Promise} the user object from + * twitter + */ getUser(oAuthAccessToken, oAuthAccessTokenSecret) { const self = this; @@ -72,6 +130,12 @@ module.exports = internals.TwitterHelper = class TwitterHelper { oAuthAccessToken, oAuthAccessTokenSecret); + /** + * The twitter user from the API + * @external TwitterUser + * @see {@link https://dev.twitter.com/overview/api/users|Twitter + * Api Overview: Users} + */ return JSON.parse(userResponse); }); } diff --git a/package.json b/package.json index ba898d2..bfefe77 100644 --- a/package.json +++ b/package.json @@ -13,23 +13,39 @@ "dasein": "./bin/dasein.js" }, "scripts": { + "build": "webpack --config ./config/webpack.js", + "document": "jsdoc -c ./config/jsdoc.json lib config", "lint": "eslint .", "start": "node ./bin/dasein.js", "test": "echo \"Error: no test specified... sorry D:\"" }, "devDependencies": { + "babel-core": "^6.22.1", + "babel-loader": "^6.2.10", + "babel-preset-latest": "^6.22.0", + "docdash": "^0.4.0", "eslint": "^3.12.1", "eslint-config-hapi": "^10.0.0", - "eslint-plugin-hapi": "^4.0.0" + "eslint-plugin-hapi": "^4.0.0", + "jsdoc": "^3.4.3", + "webpack": "^1.14.0" }, "dependencies": { + "axios": "^0.15.3", "getenv": "^0.7.0", + "joi": "^10.2.0", "jsonwebtoken": "^7.2.1", "koa": "^1.2.4", - "koa-jwt": "^1.2.0", + "koa-bodyparser": "^2.3.0", + "koa-jwt": "^1.3.1", "koa-route": "^2.4.2", + "koa-send": "^3.3.0", "koa-static": "^2.0.0", "oauth": "^0.9.15", - "pify": "^2.3.0" + "pify": "^2.3.0", + "redis": "^2.6.5", + "uuid": "^3.0.1", + "vue": "^2.1.10", + "vue-router": "^2.2.0" } } diff --git a/static/css/app.css b/static/css/app.css index 956a281..34712e3 100644 --- a/static/css/app.css +++ b/static/css/app.css @@ -39,4 +39,55 @@ section { font-size: 96px; } +.welcome-container, +.login-container { + font-size: 24px; + padding: 50px 10px 10px; +} + /* The stream */ + +.posts-container .post .post-meta { + background-color: lightgray; + display: flex; + align-items: center; +} + +.post-meta time, .post-meta a { + padding: 0 10px; +} + +.posts-container .post .post-content, +.post-form-container .post-content-input, +.post-form-container .post-submit { + font-family: -apple-system, BlinkMacSystemFont, + "Segoe UI", "Roboto", "Oxygen", + "Ubuntu", "Cantarell", "Fira Sans", + "Droid Sans", "Helvetica Neue", sans-serif; + font-size: 24px; + padding: 10px; +} + +.post-form-container .post-content-input { + display: block; + margin: 10px; + width: 90%; + resize: none; + height: 140px; +} + +.post-form-container .post-submit { + margin: 10px auto; + display: block; + background-color: lightgray; +} + +.post-form-container .post-submit:active { + background-color: cyan; +} + +.posts-error, +.post-form-error { + color: red; + padding: 10px; +} diff --git a/static/index.html b/static/index.html new file mode 100644 index 0000000..6e8e1f3 --- /dev/null +++ b/static/index.html @@ -0,0 +1,24 @@ + + + + + + + ✨ dasein ✨ + + + + + + + + +
+
+ Dasein +
+ +
+ + + diff --git a/static/windex.html b/static/windex.html deleted file mode 100644 index f4a6ac5..0000000 --- a/static/windex.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - ✨ dasein ✨ - - - - - - -
-
- Dasein -
- -
-

@rbdr

-
- -
Hi, this is a test. 💸
-
-
-
- - - diff --git a/yarn.lock b/yarn.lock index b8597b5..96c1fd8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,10 @@ # yarn lockfile v1 +abbrev@1: + version "1.0.9" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" + accepts@^1.2.2: version "1.3.3" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" @@ -15,7 +19,7 @@ acorn-jsx@^3.0.0: dependencies: acorn "^3.0.4" -acorn@^3.0.4: +acorn@^3.0.0, acorn@^3.0.4, acorn@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" @@ -34,6 +38,18 @@ ajv@^4.7.0: co "^4.6.0" json-stable-stringify "^1.0.1" +align-text@^0.1.1, align-text@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + dependencies: + kind-of "^3.0.2" + longest "^1.0.1" + repeat-string "^1.5.2" + +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + ansi-escapes@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" @@ -50,12 +66,40 @@ any-promise@^1.0.0, any-promise@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" +anymatch@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" + dependencies: + arrify "^1.0.0" + micromatch "^2.1.5" + +aproba@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0" + +are-we-there-yet@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.0 || ^1.1.13" + argparse@^1.0.7: version "1.0.9" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" dependencies: sprintf-js "~1.0.2" +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + +arr-flatten@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b" + array-union@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" @@ -66,26 +110,589 @@ array-uniq@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + arrify@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" -babel-code-frame@^6.16.0: - version "6.20.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.20.0.tgz#b968f839090f9a8bc6d41938fb96cb84f7387b26" +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + +assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +assert@^1.1.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + dependencies: + util "0.10.3" + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + +async@^0.9.0: + version "0.9.2" + resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" + +async@^1.3.0: + version "1.5.2" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + +async@~0.2.6: + version "0.2.10" + resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + +aws4@^1.2.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755" + +axios@^0.15.3: + version "0.15.3" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.15.3.tgz#2c9d638b2e191a08ea1d6cc988eadd6ba5bdc053" + dependencies: + follow-redirects "1.0.0" + +babel-code-frame@^6.16.0, babel-code-frame@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4" dependencies: chalk "^1.1.0" esutils "^2.0.2" - js-tokens "^2.0.0" + js-tokens "^3.0.0" + +babel-core@^6.22.0, babel-core@^6.22.1: + version "6.22.1" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.22.1.tgz#9c5fd658ba1772d28d721f6d25d968fc7ae21648" + dependencies: + babel-code-frame "^6.22.0" + babel-generator "^6.22.0" + babel-helpers "^6.22.0" + babel-messages "^6.22.0" + babel-register "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + babel-traverse "^6.22.1" + babel-types "^6.22.0" + babylon "^6.11.0" + convert-source-map "^1.1.0" + debug "^2.1.1" + json5 "^0.5.0" + lodash "^4.2.0" + minimatch "^3.0.2" + path-is-absolute "^1.0.0" + private "^0.1.6" + slash "^1.0.0" + source-map "^0.5.0" + +babel-generator@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.22.0.tgz#d642bf4961911a8adc7c692b0c9297f325cda805" + dependencies: + babel-messages "^6.22.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.2.0" + source-map "^0.5.0" + +babel-helper-builder-binary-assignment-operator-visitor@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.22.0.tgz#29df56be144d81bdeac08262bfa41d2c5e91cdcd" + dependencies: + babel-helper-explode-assignable-expression "^6.22.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-helper-call-delegate@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.22.0.tgz#119921b56120f17e9dae3f74b4f5cc7bcc1b37ef" + dependencies: + babel-helper-hoist-variables "^6.22.0" + babel-runtime "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" + +babel-helper-define-map@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.22.0.tgz#9544e9502b2d6dfe7d00ff60e82bd5a7a89e95b7" + dependencies: + babel-helper-function-name "^6.22.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" + lodash "^4.2.0" + +babel-helper-explode-assignable-expression@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.22.0.tgz#c97bf76eed3e0bae4048121f2b9dae1a4e7d0478" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" + +babel-helper-function-name@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.22.0.tgz#51f1bdc4bb89b15f57a9b249f33d742816dcbefc" + dependencies: + babel-helper-get-function-arity "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" + +babel-helper-get-function-arity@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.22.0.tgz#0beb464ad69dc7347410ac6ade9f03a50634f5ce" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-helper-hoist-variables@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.22.0.tgz#3eacbf731d80705845dd2e9718f600cfb9b4ba72" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-helper-optimise-call-expression@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.22.0.tgz#f8d5d4b40a6e2605a6a7f9d537b581bea3756d15" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-helper-regex@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.22.0.tgz#79f532be1647b1f0ee3474b5f5c3da58001d247d" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + lodash "^4.2.0" + +babel-helper-remap-async-to-generator@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.22.0.tgz#2186ae73278ed03b8b15ced089609da981053383" + dependencies: + babel-helper-function-name "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" + +babel-helper-replace-supers@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.22.0.tgz#1fcee2270657548908c34db16bcc345f9850cf42" + dependencies: + babel-helper-optimise-call-expression "^6.22.0" + babel-messages "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" + +babel-helpers@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.22.0.tgz#d275f55f2252b8101bff07bc0c556deda657392c" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.22.0" + +babel-loader@^6.2.10: + version "6.2.10" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-6.2.10.tgz#adefc2b242320cd5d15e65b31cea0e8b1b02d4b0" + dependencies: + find-cache-dir "^0.1.1" + loader-utils "^0.2.11" + mkdirp "^0.5.1" + object-assign "^4.0.1" + +babel-messages@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.22.0.tgz#36066a214f1217e4ed4164867669ecb39e3ea575" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-check-es2015-constants@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-syntax-async-functions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + +babel-plugin-syntax-exponentiation-operator@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + +babel-plugin-syntax-trailing-function-commas@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + +babel-plugin-transform-async-to-generator@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.22.0.tgz#194b6938ec195ad36efc4c33a971acf00d8cd35e" + dependencies: + babel-helper-remap-async-to-generator "^6.22.0" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-arrow-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoping@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.22.0.tgz#00d6e3a0bebdcfe7536b9d653b44a9141e63e47e" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" + lodash "^4.2.0" + +babel-plugin-transform-es2015-classes@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.22.0.tgz#54d44998fd823d9dca15292324161c331c1b6f14" + dependencies: + babel-helper-define-map "^6.22.0" + babel-helper-function-name "^6.22.0" + babel-helper-optimise-call-expression "^6.22.0" + babel-helper-replace-supers "^6.22.0" + babel-messages "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" + +babel-plugin-transform-es2015-computed-properties@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.22.0.tgz#7c383e9629bba4820c11b0425bdd6290f7f057e7" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.22.0" + +babel-plugin-transform-es2015-destructuring@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.22.0.tgz#8e0af2f885a0b2cf999d47c4c1dd23ce88cfa4c6" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-duplicate-keys@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.22.0.tgz#672397031c21610d72dd2bbb0ba9fb6277e1c36b" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-plugin-transform-es2015-for-of@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.22.0.tgz#180467ad63aeea592a1caeee4bf1c8b3e2616265" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-function-name@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.22.0.tgz#f5fcc8b09093f9a23c76ac3d9e392c3ec4b77104" + dependencies: + babel-helper-function-name "^6.22.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-plugin-transform-es2015-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-modules-amd@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.22.0.tgz#bf69cd34889a41c33d90dfb740e0091ccff52f21" + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + +babel-plugin-transform-es2015-modules-commonjs@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.22.0.tgz#6ca04e22b8e214fb50169730657e7a07dc941145" + dependencies: + babel-plugin-transform-strict-mode "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + babel-types "^6.22.0" + +babel-plugin-transform-es2015-modules-systemjs@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.22.0.tgz#810cd0cd025a08383b84236b92c6e31f88e644ad" + dependencies: + babel-helper-hoist-variables "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + +babel-plugin-transform-es2015-modules-umd@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.22.0.tgz#60d0ba3bd23258719c64391d9bf492d648dc0fae" + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + +babel-plugin-transform-es2015-object-super@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.22.0.tgz#daa60e114a042ea769dd53fe528fc82311eb98fc" + dependencies: + babel-helper-replace-supers "^6.22.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-parameters@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.22.0.tgz#57076069232019094f27da8c68bb7162fe208dbb" + dependencies: + babel-helper-call-delegate "^6.22.0" + babel-helper-get-function-arity "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" + +babel-plugin-transform-es2015-shorthand-properties@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.22.0.tgz#8ba776e0affaa60bff21e921403b8a652a2ff723" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-plugin-transform-es2015-spread@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-sticky-regex@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.22.0.tgz#ab316829e866ee3f4b9eb96939757d19a5bc4593" + dependencies: + babel-helper-regex "^6.22.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-plugin-transform-es2015-template-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-typeof-symbol@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.22.0.tgz#87faf2336d3b6a97f68c4d906b0cd0edeae676e1" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-unicode-regex@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.22.0.tgz#8d9cc27e7ee1decfe65454fb986452a04a613d20" + dependencies: + babel-helper-regex "^6.22.0" + babel-runtime "^6.22.0" + regexpu-core "^2.0.0" + +babel-plugin-transform-exponentiation-operator@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.22.0.tgz#d57c8335281918e54ef053118ce6eb108468084d" + dependencies: + babel-helper-builder-binary-assignment-operator-visitor "^6.22.0" + babel-plugin-syntax-exponentiation-operator "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-regenerator@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.22.0.tgz#65740593a319c44522157538d690b84094617ea6" + dependencies: + regenerator-transform "0.9.8" + +babel-plugin-transform-strict-mode@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.22.0.tgz#e008df01340fdc87e959da65991b7e05970c8c7c" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-preset-es2015@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.22.0.tgz#af5a98ecb35eb8af764ad8a5a05eb36dc4386835" + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.22.0" + babel-plugin-transform-es2015-classes "^6.22.0" + babel-plugin-transform-es2015-computed-properties "^6.22.0" + babel-plugin-transform-es2015-destructuring "^6.22.0" + babel-plugin-transform-es2015-duplicate-keys "^6.22.0" + babel-plugin-transform-es2015-for-of "^6.22.0" + babel-plugin-transform-es2015-function-name "^6.22.0" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-plugin-transform-es2015-modules-commonjs "^6.22.0" + babel-plugin-transform-es2015-modules-systemjs "^6.22.0" + babel-plugin-transform-es2015-modules-umd "^6.22.0" + babel-plugin-transform-es2015-object-super "^6.22.0" + babel-plugin-transform-es2015-parameters "^6.22.0" + babel-plugin-transform-es2015-shorthand-properties "^6.22.0" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.22.0" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.22.0" + babel-plugin-transform-es2015-unicode-regex "^6.22.0" + babel-plugin-transform-regenerator "^6.22.0" + +babel-preset-es2016@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-preset-es2016/-/babel-preset-es2016-6.22.0.tgz#b061aaa3983d40c9fbacfa3743b5df37f336156c" + dependencies: + babel-plugin-transform-exponentiation-operator "^6.22.0" + +babel-preset-es2017@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-preset-es2017/-/babel-preset-es2017-6.22.0.tgz#de2f9da5a30c50d293fb54a0ba15d6ddc573f0f2" + dependencies: + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-to-generator "^6.22.0" + +babel-preset-latest@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-preset-latest/-/babel-preset-latest-6.22.0.tgz#47b800531350a3dc69126e8c375a40655cd1eeff" + dependencies: + babel-preset-es2015 "^6.22.0" + babel-preset-es2016 "^6.22.0" + babel-preset-es2017 "^6.22.0" + +babel-register@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.22.0.tgz#a61dd83975f9ca4a9e7d6eff3059494cd5ea4c63" + dependencies: + babel-core "^6.22.0" + babel-runtime "^6.22.0" + core-js "^2.4.0" + home-or-tmp "^2.0.0" + lodash "^4.2.0" + mkdirp "^0.5.1" + source-map-support "^0.4.2" + +babel-runtime@^6.18.0, babel-runtime@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.22.0.tgz#1cf8b4ac67c77a4ddb0db2ae1f74de52ac4ca611" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.10.0" + +babel-template@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.22.0.tgz#403d110905a4626b317a2a1fcb8f3b73204b2edb" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" + babylon "^6.11.0" + lodash "^4.2.0" + +babel-traverse@^6.22.0, babel-traverse@^6.22.1: + version "6.22.1" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.22.1.tgz#3b95cd6b7427d6f1f757704908f2fc9748a5f59f" + dependencies: + babel-code-frame "^6.22.0" + babel-messages "^6.22.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" + babylon "^6.15.0" + debug "^2.2.0" + globals "^9.0.0" + invariant "^2.2.0" + lodash "^4.2.0" + +babel-types@^6.19.0, babel-types@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.22.0.tgz#2a447e8d0ea25d2512409e4175479fd78cc8b1db" + dependencies: + babel-runtime "^6.22.0" + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^1.0.1" + +babylon@^6.11.0, babylon@^6.15.0: + version "6.15.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.15.0.tgz#ba65cfa1a80e1759b0e89fb562e27dccae70348e" balanced-match@^0.4.1: version "0.4.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" +base64-js@^1.0.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1" + base64url@2.0.0, base64url@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/base64url/-/base64url-2.0.0.tgz#eac16e03ea1438eff9423d69baa36262ed1f70bb" +bcrypt-pbkdf@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.0.tgz#3ca76b85241c7170bf7d9703e7b9aa74630040d4" + dependencies: + tweetnacl "^0.14.3" + +big.js@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978" + +binary-extensions@^1.0.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + dependencies: + inherits "~2.0.0" + +bluebird@~3.4.6: + version "3.4.7" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" + +boom@2.x.x: + version "2.10.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + dependencies: + hoek "2.x.x" + brace-expansion@^1.0.0: version "1.1.6" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" @@ -93,10 +700,50 @@ brace-expansion@^1.0.0: balanced-match "^0.4.1" concat-map "0.0.1" +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +browserify-aes@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-0.4.0.tgz#067149b668df31c4b58533e02d01e806d8608e2c" + dependencies: + inherits "^2.0.1" + +browserify-zlib@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d" + dependencies: + pako "~0.2.0" + buffer-equal-constant-time@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" +buffer-shims@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" + +buffer@^4.9.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + +bytes@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" + caller-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" @@ -107,6 +754,27 @@ callsites@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" +camelcase@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + +caseless@~0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" + +catharsis@~0.8.8: + version "0.8.8" + resolved "https://registry.yarnpkg.com/catharsis/-/catharsis-0.8.8.tgz#693479f43aac549d806bd73e924cd0d944951a06" + dependencies: + underscore-contrib "~0.3.0" + +center-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + dependencies: + align-text "^0.1.3" + lazy-cache "^1.0.3" + chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" @@ -117,6 +785,21 @@ chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" +chokidar@^1.0.0: + version "1.6.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2" + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + circular-json@^0.3.0: version "0.3.1" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" @@ -131,6 +814,27 @@ cli-width@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" +cliui@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + dependencies: + center-align "^0.1.1" + right-align "^0.1.1" + wordwrap "0.0.2" + +clone@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149" + +co-body@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/co-body/-/co-body-4.2.0.tgz#74df20fa73262125dc45482af04e342ea8db3515" + dependencies: + inflation "~2.0.0" + qs "~4.0.0" + raw-body "~2.1.2" + type-is "~1.6.6" + co@^4.0.2, co@^4.4.0, co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -139,6 +843,22 @@ code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" +combined-stream@^1.0.5, combined-stream@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" + dependencies: + delayed-stream "~1.0.0" + +commander@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" + dependencies: + graceful-readlink ">= 1.0.0" + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + composition@^2.1.1: version "2.3.0" resolved "https://registry.yarnpkg.com/composition/-/composition-2.3.0.tgz#742805374cab550c520a33662f5a732e0208d6f2" @@ -158,6 +878,20 @@ concat-stream@^1.4.6: readable-stream "~2.0.0" typedarray "~0.0.5" +console-browserify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + dependencies: + date-now "^0.1.4" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + content-disposition@~0.5.0: version "0.5.2" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" @@ -166,6 +900,10 @@ content-type@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" +convert-source-map@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.3.0.tgz#e9f3e9c6e2728efc2676696a70eb382f73106a67" + cookies@~0.6.1: version "0.6.2" resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.6.2.tgz#6ac1b052895208e8fc4c4f5f86a9ed31b9cb5ccf" @@ -173,26 +911,79 @@ cookies@~0.6.1: depd "~1.1.0" keygrip "~1.0.1" +copy-to@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/copy-to/-/copy-to-2.0.1.tgz#2680fbb8068a48d08656b6098092bdafc906f4a5" + +core-js@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" + core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" +cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + dependencies: + boom "2.x.x" + +crypto-browserify@3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.3.0.tgz#b9fc75bb4a0ed61dcf1cd5dae96eb30c9c3e506c" + dependencies: + browserify-aes "0.4.0" + pbkdf2-compat "2.0.1" + ripemd160 "0.2.0" + sha.js "2.2.6" + d@^0.1.1, d@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309" dependencies: es5-ext "~0.10.2" -debug@*, debug@^2.1.1: +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +date-now@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + +debug@*: version "2.4.4" resolved "https://registry.yarnpkg.com/debug/-/debug-2.4.4.tgz#c04d17a654e9202464803f096153f70a6f31f4be" dependencies: ms "0.7.2" +debug@^2.1.1, debug@^2.2.0, debug@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.0.tgz#bc596bcabe7617f11d9fa15361eded5608b8499b" + dependencies: + ms "0.7.2" + +debug@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" + dependencies: + ms "0.7.1" + +decamelize@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + deep-equal@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" +deep-extend@~0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253" + deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" @@ -209,6 +1000,10 @@ del@^2.0.2: pinkie-promise "^2.0.0" rimraf "^2.2.8" +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" @@ -221,6 +1016,16 @@ destroy@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + dependencies: + repeating "^2.0.0" + +docdash@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/docdash/-/docdash-0.4.0.tgz#05c3a50d83189981699ee0c076d3a3950db7ec00" + doctrine@^1.2.2: version "1.5.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" @@ -228,6 +1033,20 @@ doctrine@^1.2.2: esutils "^2.0.2" isarray "^1.0.0" +domain-browser@^1.1.1: + version "1.1.7" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" + +double-ended-queue@^2.1.0-0: + version "2.1.0-0" + resolved "https://registry.yarnpkg.com/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz#103d3527fd31528f40188130c841efdd78264e5c" + +ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + ecdsa-sig-formatter@1.0.9: version "1.0.9" resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.9.tgz#4bc926274ec3b5abb5016e7e1d60921ac262b2a1" @@ -239,6 +1058,24 @@ ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" +emojis-list@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + +enhanced-resolve@~0.9.0: + version "0.9.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz#4d6e689b3725f86090927ccc86cd9f1635b89e2e" + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.2.0" + tapable "^0.1.8" + +errno@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d" + dependencies: + prr "~0.0.0" + error-inject@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/error-inject/-/error-inject-1.0.0.tgz#e2b3d91b54aed672f309d950d154850fa11d4f37" @@ -299,7 +1136,7 @@ escape-html@~1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5, escape-string-regexp@~1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -371,6 +1208,13 @@ espree@^3.3.1: acorn "^4.0.1" acorn-jsx "^3.0.0" +espree@~3.1.7: + version "3.1.7" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.1.7.tgz#fd5deec76a97a5120a9cd3a7cb1177a0923b11d2" + dependencies: + acorn "^3.3.0" + acorn-jsx "^3.0.0" + esprima@^2.6.0: version "2.7.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" @@ -401,10 +1245,40 @@ event-emitter@~0.3.4: d "~0.1.1" es5-ext "~0.10.7" +events@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + exit-hook@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + +extend@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + +extsprintf@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" + fast-levenshtein@~2.0.4: version "2.0.5" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.5.tgz#bd33145744519ab1c36c3ee9f31f08e9079b67f2" @@ -423,6 +1297,35 @@ file-entry-cache@^2.0.0: flat-cache "^1.2.1" object-assign "^4.0.1" +filename-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" + +fill-range@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^1.1.3" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +find-cache-dir@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-0.1.1.tgz#c8defae57c8a52a8a784f9e31c57c742e993a0b9" + dependencies: + commondir "^1.0.1" + mkdirp "^0.5.1" + pkg-dir "^1.0.0" + +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + flat-cache@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.1.tgz#6c837d6225a7de5659323740b36d5361f71691ff" @@ -432,6 +1335,34 @@ flat-cache@^1.2.1: graceful-fs "^4.1.2" write "^0.2.1" +follow-redirects@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.0.0.tgz#8e34298cbd2e176f254effec75a1c78cc849fd37" + dependencies: + debug "^2.2.0" + +for-in@^0.1.5: + version "0.1.6" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.6.tgz#c9f96e89bfad18a545af5ec3ed352a1d9e5b4dc8" + +for-own@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.4.tgz#0149b41a39088c7515f51ebe1c1386d45f935072" + dependencies: + for-in "^0.1.5" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + fresh@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.3.0.tgz#651f838e22424e7566de161d8358caa199f83d4f" @@ -440,6 +1371,44 @@ fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" +fsevents@^1.0.0: + version "1.0.17" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.0.17.tgz#8537f3f12272678765b4fd6528c0f1f66f8f4558" + dependencies: + nan "^2.3.0" + node-pre-gyp "^0.6.29" + +fstream-ignore@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" + dependencies: + fstream "^1.0.0" + inherits "2" + minimatch "^3.0.0" + +fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.10.tgz#604e8a92fe26ffd9f6fae30399d4984e1ab22822" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +gauge@~2.7.1: + version "2.7.2" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.2.tgz#15cecc31b02d05345a5d6b0e171cdb3ad2307774" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + supports-color "^0.2.0" + wide-align "^1.1.0" + generate-function@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" @@ -454,6 +1423,25 @@ getenv: version "0.7.0" resolved "https://registry.yarnpkg.com/getenv/-/getenv-0.7.0.tgz#39b91838707e2086fd1cf6ef8777d1c93e14649e" +getpass@^0.1.1: + version "0.1.6" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" + dependencies: + assert-plus "^1.0.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + glob@^7.0.0, glob@^7.0.3, glob@^7.0.5: version "7.1.1" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" @@ -465,7 +1453,7 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.5: once "^1.3.0" path-is-absolute "^1.0.0" -globals@^9.14.0: +globals@^9.0.0, globals@^9.14.0: version "9.14.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.14.0.tgz#8859936af0038741263053b39d0e76ca241e4034" @@ -480,10 +1468,14 @@ globby@^5.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" -graceful-fs@^4.1.2: +graceful-fs@^4.1.2, graceful-fs@^4.1.9: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" +"graceful-readlink@>= 1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + hapi-capitalize-modules@1.x.x: version "1.1.6" resolved "https://registry.yarnpkg.com/hapi-capitalize-modules/-/hapi-capitalize-modules-1.1.6.tgz#7991171415e15e6aa3231e64dda73c8146665318" @@ -496,16 +1488,53 @@ hapi-scope-start@2.x.x: version "2.1.1" resolved "https://registry.yarnpkg.com/hapi-scope-start/-/hapi-scope-start-2.1.1.tgz#7495a726fe72b7bca8de2cdcc1d87cd8ce6ab4f2" +har-validator@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" + dependencies: + chalk "^1.1.1" + commander "^2.9.0" + is-my-json-valid "^2.12.4" + pinkie-promise "^2.0.0" + has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" dependencies: ansi-regex "^2.0.0" +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + hoek@2.x.x: version "2.16.3" resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" +hoek@4.x.x: + version "4.1.0" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.1.0.tgz#4a4557460f69842ed463aa00628cc26d2683afa7" + +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + http-assert@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.2.0.tgz#d6392e6f6519def4e340266b35096db6d3feba00" @@ -528,6 +1557,26 @@ http-errors@~1.4.0: inherits "2.0.1" statuses ">= 1.2.1 < 2" +http-signature@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82" + +iconv-lite@0.4.13: + version "0.4.13" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" + +ieee754@^1.1.4: + version "1.1.8" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" + ignore@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.0.tgz#8d88f03c3002a0ac52114db25d2c673b0bf1e435" @@ -536,6 +1585,14 @@ imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + +inflation@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/inflation/-/inflation-2.0.0.tgz#8b417e47c28f925a45133d914ca1fd389107f30f" + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -543,7 +1600,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.3, inherits@~2.0.1: +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" @@ -551,6 +1608,10 @@ inherits@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" +ini@~1.3.0: + version "1.3.4" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" + inquirer@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" @@ -569,10 +1630,54 @@ inquirer@^0.12.0: strip-ansi "^3.0.0" through "^2.3.6" +interpret@^0.6.4: + version "0.6.6" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-0.6.6.tgz#fecd7a18e7ce5ca6abfb953e1f86213a49f1625b" + interpret@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.1.tgz#d579fb7f693b858004947af39fa0db49f795602c" +invariant@^2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" + dependencies: + loose-envify "^1.0.0" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.0.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b" + +is-dotfile@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + dependencies: + number-is-nan "^1.0.0" + is-fullwidth-code-point@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" @@ -583,7 +1688,13 @@ is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" -is-my-json-valid@^2.10.0: +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + +is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4: version "2.15.0" resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b" dependencies: @@ -592,6 +1703,12 @@ is-my-json-valid@^2.10.0: jsonpointer "^4.0.0" xtend "^4.0.0" +is-number@^2.0.2, is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + is-path-cwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" @@ -608,6 +1725,14 @@ is-path-inside@^1.0.0: dependencies: path-is-inside "^1.0.1" +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + is-property@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" @@ -618,11 +1743,15 @@ is-resolvable@^1.0.0: dependencies: tryit "^1.0.1" +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" -isarray@^1.0.0, isarray@~1.0.0: +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -630,6 +1759,39 @@ isemail@1.x.x: version "1.2.0" resolved "https://registry.yarnpkg.com/isemail/-/isemail-1.2.0.tgz#be03df8cc3e29de4d2c5df6501263f1fa4595e9a" +isemail@2.x.x: + version "2.2.1" + resolved "https://registry.yarnpkg.com/isemail/-/isemail-2.2.1.tgz#0353d3d9a62951080c262c2aa0a42b8ea8e9e2a6" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +items@2.x.x: + version "2.1.1" + resolved "https://registry.yarnpkg.com/items/-/items-2.1.1.tgz#8bd16d9c83b19529de5aea321acaada78364a198" + +jodid25519@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" + dependencies: + jsbn "~0.1.0" + +joi@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/joi/-/joi-10.2.0.tgz#2c9dba08240d453e58145667f0d5006de527e328" + dependencies: + hoek "4.x.x" + isemail "2.x.x" + items "2.x.x" + topo "2.x.x" + joi@^6.10.1: version "6.10.1" resolved "https://registry.yarnpkg.com/joi/-/joi-6.10.1.tgz#4d50c318079122000fe5f16af1ff8e1917b77e06" @@ -639,9 +1801,9 @@ joi@^6.10.1: moment "2.x.x" topo "1.x.x" -js-tokens@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-2.0.0.tgz#79903f5563ee778cc1162e6dcf1a0027c97f9cb5" +js-tokens@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.0.tgz#a2f2a969caae142fb3cd56228358c89366957bd1" js-yaml@^3.5.1: version "3.7.0" @@ -650,12 +1812,57 @@ js-yaml@^3.5.1: argparse "^1.0.7" esprima "^2.6.0" +js2xmlparser@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/js2xmlparser/-/js2xmlparser-1.0.0.tgz#5a170f2e8d6476ce45405e04823242513782fe30" + +jsbn@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.0.tgz#650987da0dd74f4ebf5a11377a2aa2d273e97dfd" + +jsdoc@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jsdoc/-/jsdoc-3.4.3.tgz#e5740d6145c681f6679e6c17783a88dbdd97ccd3" + dependencies: + bluebird "~3.4.6" + catharsis "~0.8.8" + escape-string-regexp "~1.0.5" + espree "~3.1.7" + js2xmlparser "~1.0.0" + klaw "~1.3.0" + marked "~0.3.6" + mkdirp "~0.5.1" + requizzle "~0.2.1" + strip-json-comments "~2.0.1" + taffydb "2.6.2" + underscore "~1.8.3" + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" dependencies: jsonify "~0.0.0" +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +json5@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" @@ -682,6 +1889,14 @@ jsonwebtoken@^7.2.1: ms "^0.7.1" xtend "^4.0.1" +jsprim@^1.2.2: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.3.1.tgz#2a7256f70412a29ee3670aaca625994c4dcff252" + dependencies: + extsprintf "1.0.2" + json-schema "0.2.3" + verror "1.3.6" + jwa@^1.1.4: version "1.1.5" resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.1.5.tgz#a0552ce0220742cd52e153774a32905c30e756e5" @@ -703,6 +1918,18 @@ keygrip@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.0.1.tgz#b02fa4816eef21a8c4b35ca9e52921ffc89a30e9" +kind-of@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47" + dependencies: + is-buffer "^1.0.2" + +klaw@~1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + optionalDependencies: + graceful-fs "^4.1.9" + koa: version "1.2.4" resolved "https://registry.yarnpkg.com/koa/-/koa-1.2.4.tgz#6ef6d17a7bea8ec778a8572b55a0d0562e488654" @@ -731,6 +1958,13 @@ koa: type-is "^1.5.5" vary "^1.0.0" +koa-bodyparser@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/koa-bodyparser/-/koa-bodyparser-2.3.0.tgz#236ed90a16f562e79cade2b958f67c848824e818" + dependencies: + co-body "^4.2.0" + copy-to "^2.0.1" + koa-compose@^2.3.0: version "2.5.1" resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-2.5.1.tgz#726cfb17694de5cb9fbf03c0adf172303f83f156" @@ -739,9 +1973,9 @@ koa-is-json@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/koa-is-json/-/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14" -koa-jwt@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/koa-jwt/-/koa-jwt-1.2.0.tgz#c0589c2c27d7e0b497a22cb28575d0bc7dc0f959" +koa-jwt@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/koa-jwt/-/koa-jwt-1.3.1.tgz#14eaa675ba7027b0766808e437b68a125a90d79f" dependencies: jsonwebtoken "5.x.x" koa-unless "0.0.1" @@ -755,6 +1989,15 @@ koa-route@^2.4.2: methods "~1.1.0" path-to-regexp "^1.2.0" +koa-send@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/koa-send/-/koa-send-3.3.0.tgz#5a4ae245564680c6ecf6079e9275fa5173a861dc" + dependencies: + co "^4.6.0" + debug "^2.6.0" + mz "^2.3.1" + resolve-path "^1.3.1" + koa-send@~3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/koa-send/-/koa-send-3.1.1.tgz#ef0af0f9a531ec817e88056b52b8e32d2e0ba91a" @@ -775,6 +2018,10 @@ koa-unless@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/koa-unless/-/koa-unless-0.0.1.tgz#cfcdd1cdfbaf066e05d843e6a412df8a7c69b218" +lazy-cache@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" @@ -782,43 +2029,99 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" +loader-utils@^0.2.11: + version "0.2.16" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.16.tgz#f08632066ed8282835dff88dfb52704765adee6d" + dependencies: + big.js "^3.1.3" + emojis-list "^2.0.0" + json5 "^0.5.0" + object-assign "^4.0.1" + lodash.once@^4.0.0: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" -lodash@^4.0.0, lodash@^4.3.0: +lodash@^4.0.0, lodash@^4.2.0, lodash@^4.3.0: version "4.17.2" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.2.tgz#34a3055babe04ce42467b607d700072c7ff6bf42" +longest@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + +loose-envify@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" + dependencies: + js-tokens "^3.0.0" + +marked@~0.3.6: + version "0.3.6" + resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.6.tgz#b2c6c618fccece4ef86c4fc6cb8a7cbf5aeda8d7" + media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" +memory-fs@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.2.0.tgz#f2bb25368bc121e391c2520de92969caee0a0290" + +memory-fs@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.3.0.tgz#7bcc6b629e3a43e871d7e29aca6ae8a7f15cbb20" + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + methods@~1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" +micromatch@^2.1.5: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + mime-db@~1.25.0: version "1.25.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.25.0.tgz#c18dbd7c73a5dbf6f44a024dc0d165a1e7b1c392" -mime-types@^2.0.7, mime-types@~2.1.11, mime-types@~2.1.13: +mime-types@^2.0.7, mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.13, mime-types@~2.1.7: version "2.1.13" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.13.tgz#e07aaa9c6c6b9a7ca3012c69003ad25a39e92a88" dependencies: mime-db "~1.25.0" -minimatch@^3.0.2: +minimatch@^3.0.0, minimatch@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" dependencies: brace-expansion "^1.0.0" -minimist@0.0.8: +minimist@0.0.8, minimist@~0.0.1: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" -mkdirp@^0.5.0, mkdirp@^0.5.1: +minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: @@ -828,6 +2131,10 @@ moment@2.x.x: version "2.17.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.17.1.tgz#fed9506063f36b10f066c8b59a144d7faebe1d82" +ms@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" + ms@0.7.2, ms@^0.7.1: version "0.7.2" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" @@ -844,6 +2151,10 @@ mz@^2.3.1: object-assign "^4.0.1" thenify-all "^1.0.0" +nan@^2.3.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.5.1.tgz#d5b01691253326a97a2bbee9e61c55d8d60351e2" + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -856,6 +2167,67 @@ no-arrowception@1.x.x: version "1.0.0" resolved "https://registry.yarnpkg.com/no-arrowception/-/no-arrowception-1.0.0.tgz#5bf3e95eb9c41b57384a805333daa3b734ee327a" +node-libs-browser@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-0.7.0.tgz#3e272c0819e308935e26674408d7af0e1491b83b" + dependencies: + assert "^1.1.1" + browserify-zlib "^0.1.4" + buffer "^4.9.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "3.3.0" + domain-browser "^1.1.1" + events "^1.0.0" + https-browserify "0.0.1" + os-browserify "^0.2.0" + path-browserify "0.0.0" + process "^0.11.0" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.0.5" + stream-browserify "^2.0.1" + stream-http "^2.3.1" + string_decoder "^0.10.25" + timers-browserify "^2.0.2" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.10.3" + vm-browserify "0.0.4" + +node-pre-gyp@^0.6.29: + version "0.6.32" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.32.tgz#fc452b376e7319b3d255f5f34853ef6fd8fe1fd5" + dependencies: + mkdirp "~0.5.1" + nopt "~3.0.6" + npmlog "^4.0.1" + rc "~1.1.6" + request "^2.79.0" + rimraf "~2.5.4" + semver "~5.3.0" + tar "~2.2.1" + tar-pack "~3.3.0" + +nopt@~3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + dependencies: + abbrev "1" + +normalize-path@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" + +npmlog@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.1" + set-blocking "~2.0.0" + number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" @@ -864,10 +2236,21 @@ oauth: version "0.9.15" resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1" +oauth-sign@~0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + on-finished@^2.1.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" @@ -880,6 +2263,12 @@ once@^1.3.0: dependencies: wrappy "1" +once@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" + dependencies: + wrappy "1" + onetime@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" @@ -888,6 +2277,13 @@ only@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" +optimist@~0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + optionator@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" @@ -899,14 +2295,45 @@ optionator@^0.8.2: type-check "~0.3.2" wordwrap "~1.0.0" +os-browserify@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.2.1.tgz#63fc4ccee5d2d7763d26bbf8601078e6c2e0044f" + os-homedir@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" +os-tmpdir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +pako@~0.2.0: + version "0.2.9" + resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + parseurl@^1.3.0: version "1.3.1" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" +path-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + dependencies: + pinkie-promise "^2.0.0" + path-is-absolute@1.0.1, path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" @@ -921,6 +2348,10 @@ path-to-regexp@^1.2.0: dependencies: isarray "0.0.1" +pbkdf2-compat@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pbkdf2-compat/-/pbkdf2-compat-2.0.1.tgz#b6e0c8fa99494d94e0511575802a59a5c142f288" + pify, pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -935,6 +2366,12 @@ pinkie@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" +pkg-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" + dependencies: + find-up "^1.0.0" + pluralize@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" @@ -943,15 +2380,91 @@ prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + +private@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.6.tgz#55c6a976d0f9bafb9924851350fe47b9b5fbb7c1" + process-nextick-args@~1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" +process@^0.11.0: + version "0.11.9" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.9.tgz#7bd5ad21aa6253e7da8682264f1e11d11c0318c1" + progress@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" -readable-stream@~2.0.0: +prr@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + +punycode@^1.2.4, punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +qs@~4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-4.0.0.tgz#c31d9b74ec27df75e543a86c78728ed8d4623607" + +qs@~6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442" + +querystring-es3@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + +randomatic@^1.1.3: + version "1.1.6" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" + dependencies: + is-number "^2.0.2" + kind-of "^3.0.2" + +raw-body@~2.1.2: + version "2.1.7" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.1.7.tgz#adfeace2e4fb3098058014d08c072dcc59758774" + dependencies: + bytes "2.4.0" + iconv-lite "0.4.13" + unpipe "1.0.0" + +rc@~1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.1.6.tgz#43651b76b6ae53b5c802f1151fa3fc3b059969c9" + dependencies: + deep-extend "~0.4.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~1.0.4" + +"readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.1.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e" + dependencies: + buffer-shims "^1.0.0" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@~2.0.0: version "2.0.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" dependencies: @@ -962,6 +2475,27 @@ readable-stream@~2.0.0: string_decoder "~0.10.x" util-deprecate "~1.0.1" +readable-stream@~2.1.4: + version "2.1.5" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0" + dependencies: + buffer-shims "^1.0.0" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + readline2@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" @@ -976,6 +2510,102 @@ rechoir@^0.6.2: dependencies: resolve "^1.1.6" +redis-commands@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.3.1.tgz#81d826f45fa9c8b2011f4cd7a0fe597d241d442b" + +redis-parser@^2.0.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-2.4.0.tgz#018ea743077aae944d0b798b2fd12587320bf3c9" + +redis@^2.6.5: + version "2.6.5" + resolved "https://registry.yarnpkg.com/redis/-/redis-2.6.5.tgz#87c1eff4a489f94b70871f3d08b6988f23a95687" + dependencies: + double-ended-queue "^2.1.0-0" + redis-commands "^1.2.0" + redis-parser "^2.0.0" + +regenerate@^1.2.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" + +regenerator-runtime@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.1.tgz#257f41961ce44558b18f7814af48c17559f9faeb" + +regenerator-transform@0.9.8: + version "0.9.8" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.9.8.tgz#0f88bb2bc03932ddb7b6b7312e68078f01026d6c" + dependencies: + babel-runtime "^6.18.0" + babel-types "^6.19.0" + private "^0.1.6" + +regex-cache@^0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" + dependencies: + is-equal-shallow "^0.1.3" + is-primitive "^2.0.0" + +regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + dependencies: + jsesc "~0.5.0" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + +request@^2.79.0: + version "2.79.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~2.0.6" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + qs "~6.3.0" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "~0.4.1" + uuid "^3.0.0" + require-uncached@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" @@ -983,6 +2613,12 @@ require-uncached@^1.0.2: caller-path "^0.1.0" resolve-from "^1.0.0" +requizzle@~0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/requizzle/-/requizzle-0.2.1.tgz#6943c3530c4d9a7e46f1cddd51c158fc670cdbde" + dependencies: + underscore "~1.6.0" + resolve-from@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" @@ -1005,12 +2641,22 @@ restore-cursor@^1.0.1: exit-hook "^1.0.0" onetime "^1.0.0" -rimraf@^2.2.8: +right-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + dependencies: + align-text "^0.1.1" + +rimraf@2, rimraf@^2.2.8, rimraf@~2.5.1, rimraf@~2.5.4: version "2.5.4" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" dependencies: glob "^7.0.5" +ripemd160@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-0.2.0.tgz#2bf198bde167cacfa51c0a928e84b68bbe171fce" + run-async@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" @@ -1025,10 +2671,30 @@ safe-buffer@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7" +semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + setprototypeof@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.2.tgz#81a552141ec104b88e89ce383103ad5c66564d08" +sha.js@2.2.6: + version "2.2.6" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.2.6.tgz#17ddeddc5f722fb66501658895461977867315ba" + shelljs@^0.7.5: version "0.7.5" resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.5.tgz#2eef7a50a21e1ccf37da00df767ec69e30ad0675" @@ -1037,18 +2703,84 @@ shelljs@^0.7.5: interpret "^1.0.0" rechoir "^0.6.2" +signal-exit@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + slice-ansi@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" +sntp@1.x.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + +source-list-map@~0.1.7: + version "0.1.8" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106" + +source-map-support@^0.4.2: + version "0.4.11" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.11.tgz#647f939978b38535909530885303daf23279f322" + dependencies: + source-map "^0.5.3" + +source-map@^0.5.0, source-map@^0.5.3, source-map@~0.5.1: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + +source-map@~0.4.1: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + dependencies: + amdefine ">=0.0.4" + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" +sshpk@^1.7.0: + version "1.10.2" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.10.2.tgz#d5a804ce22695515638e798dbe23273de070a5fa" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jodid25519 "^1.0.0" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + "statuses@>= 1.2.1 < 2", "statuses@>= 1.3.1 < 2", statuses@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" +stream-browserify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-http@^2.3.1: + version "2.6.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.6.3.tgz#4c3ddbf9635968ea2cfd4e48d43de5def2625ac3" + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.1.0" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" @@ -1064,11 +2796,15 @@ string-width@^2.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^3.0.0" -string_decoder@~0.10.x: +string_decoder@^0.10.25, string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" -strip-ansi@^3.0.0: +stringstream@~0.0.4: + version "0.0.5" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" dependencies: @@ -1078,14 +2814,28 @@ strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" -strip-json-comments@~1.0.1: +strip-json-comments@~1.0.1, strip-json-comments@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +supports-color@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" + supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" +supports-color@^3.1.0: + version "3.2.3" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + dependencies: + has-flag "^1.0.0" + table@^3.7.8: version "3.8.3" resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" @@ -1097,6 +2847,35 @@ table@^3.7.8: slice-ansi "0.0.4" string-width "^2.0.0" +taffydb@2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/taffydb/-/taffydb-2.6.2.tgz#7cbcb64b5a141b6a2efc2c5d2c67b4e150b2a268" + +tapable@^0.1.8, tapable@~0.1.8: + version "0.1.10" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.1.10.tgz#29c35707c2b70e50d07482b5d202e8ed446dafd4" + +tar-pack@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.3.0.tgz#30931816418f55afc4d21775afdd6720cee45dae" + dependencies: + debug "~2.2.0" + fstream "~1.0.10" + fstream-ignore "~1.0.5" + once "~1.3.3" + readable-stream "~2.1.4" + rimraf "~2.5.1" + tar "~2.2.1" + uid-number "~0.0.6" + +tar@~2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + text-table@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -1121,23 +2900,61 @@ thunkify@~2.1.x: version "2.1.2" resolved "https://registry.yarnpkg.com/thunkify/-/thunkify-2.1.2.tgz#faa0e9d230c51acc95ca13a361ac05ca7e04553d" +timers-browserify@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.2.tgz#ab4883cf597dcd50af211349a00fbca56ac86b86" + dependencies: + setimmediate "^1.0.4" + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + +to-fast-properties@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" + topo@1.x.x: version "1.1.0" resolved "https://registry.yarnpkg.com/topo/-/topo-1.1.0.tgz#e9d751615d1bb87dc865db182fa1ca0a5ef536d5" dependencies: hoek "2.x.x" +topo@2.x.x: + version "2.0.2" + resolved "https://registry.yarnpkg.com/topo/-/topo-2.0.2.tgz#cd5615752539057c0dc0491a621c3bc6fbe1d182" + dependencies: + hoek "4.x.x" + +tough-cookie@~2.3.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" + dependencies: + punycode "^1.4.1" + tryit@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + +tunnel-agent@~0.4.1: + version "0.4.3" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" dependencies: prelude-ls "~1.1.2" -type-is@^1.5.5: +type-is@^1.5.5, type-is@~1.6.6: version "1.6.14" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2" dependencies: @@ -1148,6 +2965,48 @@ typedarray@~0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" +uglify-js@~2.7.3: + version "2.7.5" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8" + dependencies: + async "~0.2.6" + source-map "~0.5.1" + uglify-to-browserify "~1.0.0" + yargs "~3.10.0" + +uglify-to-browserify@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + +uid-number@~0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + +underscore-contrib@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/underscore-contrib/-/underscore-contrib-0.3.0.tgz#665b66c24783f8fa2b18c9f8cbb0e2c7d48c26c7" + dependencies: + underscore "1.6.0" + +underscore@1.6.0, underscore@~1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.6.0.tgz#8b38b10cacdef63337b8b24e4ff86d45aea529a8" + +underscore@~1.8.3: + version "1.8.3" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" + +unpipe@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + dependencies: + punycode "1.3.2" + querystring "0.2.0" + user-home@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" @@ -1158,10 +3017,93 @@ util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" +util@0.10.3, util@^0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + dependencies: + inherits "2.0.1" + +uuid@^3.0.0, uuid@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" + vary@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.0.tgz#e1e5affbbd16ae768dd2674394b9ad3022653140" +verror@1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" + dependencies: + extsprintf "1.0.2" + +vm-browserify@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" + dependencies: + indexof "0.0.1" + +vue-router@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-2.2.0.tgz#65a29ce23d718ddf09237938a58a01b3d1acc77c" + +vue@^2.1.10: + version "2.1.10" + resolved "https://registry.yarnpkg.com/vue/-/vue-2.1.10.tgz#c9235ca48c7925137be5807832ac4e3ac180427b" + +watchpack@^0.2.1: + version "0.2.9" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-0.2.9.tgz#62eaa4ab5e5ba35fdfc018275626e3c0f5e3fb0b" + dependencies: + async "^0.9.0" + chokidar "^1.0.0" + graceful-fs "^4.1.2" + +webpack-core@~0.6.9: + version "0.6.9" + resolved "https://registry.yarnpkg.com/webpack-core/-/webpack-core-0.6.9.tgz#fc571588c8558da77be9efb6debdc5a3b172bdc2" + dependencies: + source-list-map "~0.1.7" + source-map "~0.4.1" + +webpack@^1.14.0: + version "1.14.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-1.14.0.tgz#54f1ffb92051a328a5b2057d6ae33c289462c823" + dependencies: + acorn "^3.0.0" + async "^1.3.0" + clone "^1.0.2" + enhanced-resolve "~0.9.0" + interpret "^0.6.4" + loader-utils "^0.2.11" + memory-fs "~0.3.0" + mkdirp "~0.5.0" + node-libs-browser "^0.7.0" + optimist "~0.6.0" + supports-color "^3.1.0" + tapable "~0.1.8" + uglify-js "~2.7.3" + watchpack "^0.2.1" + webpack-core "~0.6.9" + +wide-align@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" + dependencies: + string-width "^1.0.1" + +window-size@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + +wordwrap@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" @@ -1179,3 +3121,12 @@ write@^0.2.1: xtend@^4.0.0, xtend@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +yargs@~3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + dependencies: + camelcase "^1.0.2" + cliui "^2.1.0" + decamelize "^1.0.0" + window-size "0.1.0" -- cgit From 9b1f50fefe021578113b8f5935084fe4fed110b2 Mon Sep 17 00:00:00 2001 From: Rubén Beltrán del Río Date: Tue, 31 Jan 2017 00:49:26 -0600 Subject: Add Comments (#4) * Preserve whitespace in posts * Create comments handler * Use comments handler * Update paw * Add comment components * Style comments * Remove unnecessary code from app * Fix linter warning * Add key to handle children (thx @javierbyte) * Add toggling to the form * Return all keys always * Correct missing semicolons * Restore redirect * Render posts conditionally * Set poll time to 1s * Set post frequency to 2s * Add polling to comments * Correct typo in error logging * Clear intervals and reduce polling * Stops polling if it's being destroyed * Update changelog --- CHANGELOG.md | 3 + app/components/comment.js | 17 +++++ app/components/comment_form.js | 73 +++++++++++++++++++++ app/components/comments.js | 76 ++++++++++++++++++++++ app/components/post.js | 23 +++++++ app/components/post_form.js | 19 +++++- app/components/posts.js | 24 +++---- app/dasein.js | 7 --- etc/dasein.paw | Bin 16889 -> 20249 bytes lib/dasein.js | 14 +++++ lib/handlers/comments.js | 140 +++++++++++++++++++++++++++++++++++++++++ lib/handlers/posts.js | 14 +++-- static/css/app.css | 48 ++++++++++++++ 13 files changed, 430 insertions(+), 28 deletions(-) create mode 100644 app/components/comment.js create mode 100644 app/components/comment_form.js create mode 100644 app/components/comments.js create mode 100644 app/components/post.js create mode 100644 lib/handlers/comments.js (limited to 'lib/dasein.js') diff --git a/CHANGELOG.md b/CHANGELOG.md index 425a9d3..fd38475 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] - 2016-12-12 ### Added +- Add inefficient API response +- Add inefficient polling +- Add comments - JSDoc config - Twitter OAuth Integration - Simple contributing guidelines diff --git a/app/components/comment.js b/app/components/comment.js new file mode 100644 index 0000000..33ce2c7 --- /dev/null +++ b/app/components/comment.js @@ -0,0 +1,17 @@ +import Vue from 'vue'; + +const internals = {}; + +export default internals.CommentComponent = Vue.component('comment', { + template: '
' + + '' + + '
{{comment.content}}
' + + '
', + + props: ['comment'] +}); + diff --git a/app/components/comment_form.js b/app/components/comment_form.js new file mode 100644 index 0000000..bf60d06 --- /dev/null +++ b/app/components/comment_form.js @@ -0,0 +1,73 @@ +import Axios from 'axios'; +import Vue from 'vue'; +import AuthService from '../services/auth'; + +const internals = {}; + +internals.kPostsRoute = '/api/posts'; +internals.kCommentsRoute = '/comments'; + +export default internals.CommentFormComponent = Vue.component('comment-form', { + template: '
' + + '

' + + '' + + '

' + + '' + + '

{{message}}

' + + '' + + '
', + + props: ['postUuid'], + + data() { + + return { + content: '', + message: '', + active: false, + submitting: false, + authService: new AuthService() + }; + }, + + methods: { + + // Activates the form. + + activate() { + + this.active = true; + }, + + // Creates a comment + + submit() { + + this.submitting = true; + const route = `${internals.kPostsRoute}/${this.postUuid}${internals.kCommentsRoute}`; + + return Axios({ + method: 'post', + headers: { + Authorization: `Bearer ${this.authService.token}` + }, + data: { + content: this.content + }, + url: route + }).then((response) => { + + this.$emit('comment-submitted', response.data); + this.content = ''; + this.message = ''; + this.submitting = false; + this.active = false; + }).catch((err) => { + + console.error(err.stack); + this.submitting = false; + this.message = 'Error while creating the post...'; + }); + } + } +}); diff --git a/app/components/comments.js b/app/components/comments.js new file mode 100644 index 0000000..e29cedc --- /dev/null +++ b/app/components/comments.js @@ -0,0 +1,76 @@ +import Axios from 'axios'; +import Vue from 'vue'; +import AuthService from '../services/auth'; + +import CommentFormComponent from './comment_form'; +import CommentComponent from './comment'; +import DatetimeFilter from '../filters/datetime'; +import UsertimeFilter from '../filters/usertime'; + +const internals = {}; + +internals.kPostsRoute = '/api/posts'; +internals.kCommentsRoute = '/comments'; +internals.kPollFrequency = 2000; + +export default internals.CommentsComponent = Vue.component('comments', { + template: '
' + + '

{{message}}

' + + '' + + '' + + '
', + + props: ['postUuid'], + + data() { + + return { + message: '', + poller: null, + authService: new AuthService(), + comments: [] + }; + }, + + methods: { + fetchComments() { + + const route = `${internals.kPostsRoute}/${this.postUuid}${internals.kCommentsRoute}`; + + return Axios({ + method: 'get', + headers: { + Authorization: `Bearer ${this.authService.token}` + }, + url: route + }).then((response) => { + + this.comments = response.data; + if (!this._isBeingDestroyed) { + setTimeout(this.fetchComments.bind(this), internals.kPollFrequency); + } + }).catch((err) => { + + console.error(err.stack); + this.message = 'Error while loading the comments...'; + }); + }, + + addComment(comment) { + + this.comments.push(comment); + } + }, + + components: { + commentForm: CommentFormComponent, + comment: CommentComponent, + datetime: DatetimeFilter, + usertime: UsertimeFilter + }, + + mounted() { + + this.fetchComments(); + } +}); diff --git a/app/components/post.js b/app/components/post.js new file mode 100644 index 0000000..bb72189 --- /dev/null +++ b/app/components/post.js @@ -0,0 +1,23 @@ +import Vue from 'vue'; + +import CommentsComponent from './comments'; + +const internals = {}; + +export default internals.PostComponent = Vue.component('post', { + template: '
' + + '' + + '
{{post.content}}
' + + '' + + '
', + + props: ['post'], + + components: { + comments: CommentsComponent + } +}); diff --git a/app/components/post_form.js b/app/components/post_form.js index cee17b0..1f45f0c 100644 --- a/app/components/post_form.js +++ b/app/components/post_form.js @@ -8,10 +8,11 @@ internals.kPostsRoute = '/api/posts'; export default internals.PostFormComponent = Vue.component('post-form', { template: '
' + - '

sup.

' + - '' + + '

hi {{authService.user.name}}

' + + '' + + '' + '

{{message}}

' + - '' + + '' + '
', data() { @@ -20,11 +21,22 @@ export default internals.PostFormComponent = Vue.component('post-form', { content: '', message: '', submitting: false, + active: false, authService: new AuthService() }; }, methods: { + + // Activates the form. + + activate() { + + this.active = true; + }, + + // Creates a post + submit() { this.submitting = true; @@ -44,6 +56,7 @@ export default internals.PostFormComponent = Vue.component('post-form', { this.content = ''; this.message = ''; this.submitting = false; + this.active = false; }).catch((err) => { console.error(err.stack); diff --git a/app/components/posts.js b/app/components/posts.js index c41707f..d0e0338 100644 --- a/app/components/posts.js +++ b/app/components/posts.js @@ -3,26 +3,21 @@ import Vue from 'vue'; import AuthService from '../services/auth'; import PostFormComponent from './post_form'; +import PostComponent from './post'; import DatetimeFilter from '../filters/datetime'; import UsertimeFilter from '../filters/usertime'; const internals = {}; internals.kPostsRoute = '/api/posts'; +internals.kPollFrequency = 5000; export default internals.PostsComponent = Vue.component('posts', { - template: '
' + + template: '
' + '' + '

Posts.

' + '

{{message}}

' + - '
' + - '' + - '
{{post.content}}
' + - '
' + + '' + '
', data() { @@ -46,9 +41,12 @@ export default internals.PostsComponent = Vue.component('posts', { }).then((response) => { this.posts = response.data; + if (!this._isBeingDestroyed) { + setTimeout(this.fetchPosts.bind(this), internals.kPollFrequency); + } }).catch((err) => { - console.err(err.stack); + console.error(err.stack); this.message = 'Error while loading the posts...'; }); }, @@ -61,17 +59,19 @@ export default internals.PostsComponent = Vue.component('posts', { components: { postForm: PostFormComponent, + post: PostComponent, datetime: DatetimeFilter, usertime: UsertimeFilter }, - mounted: function mounted() { + mounted() { if (!this.authService.authenticated) { return this.$router.push('/login'); } - return this.fetchPosts(); + this.fetchPosts(); + } }); diff --git a/app/dasein.js b/app/dasein.js index 6b3fd95..699a01f 100644 --- a/app/dasein.js +++ b/app/dasein.js @@ -22,13 +22,6 @@ export default internals.Dasein = { this.vm = new Vue({ router: this._setupRouter(), el: '#dasein', - components: { - login: LoginComponent, - welcome: WelcomeComponent - }, - data: { - message: 'Hello Vue!' - }, methods: { authenticated() { diff --git a/etc/dasein.paw b/etc/dasein.paw index 9983dad..632b02b 100644 Binary files a/etc/dasein.paw and b/etc/dasein.paw differ diff --git a/lib/dasein.js b/lib/dasein.js index 3a537bd..5b8486a 100644 --- a/lib/dasein.js +++ b/lib/dasein.js @@ -10,6 +10,7 @@ const Path = require('path'); const AuthHandler = require('./handlers/auth'); const PostsHandler = require('./handlers/posts'); +const CommentsHandler = require('./handlers/comments'); const internals = {}; @@ -90,6 +91,7 @@ module.exports = internals.Dasein = class Dasein { this._initializeAuthRoutes(); this._initializePostsRoutes(); + this._initializeCommentsRoutes(); this._app.use(function * () { @@ -125,6 +127,18 @@ module.exports = internals.Dasein = class Dasein { } + // Initialize routes for comments + + _initializeCommentsRoutes() { + + const commentsHandler = new CommentsHandler({ + ttl: this.ttl, + redis: this.redis + }); + this._app.use(KoaRoute.get('/api/posts/:postId/comments', commentsHandler.findAll())); + this._app.use(KoaRoute.post('/api/posts/:postId/comments', commentsHandler.create())); + } + // Starts listening _startServer() { diff --git a/lib/handlers/comments.js b/lib/handlers/comments.js new file mode 100644 index 0000000..14bd137 --- /dev/null +++ b/lib/handlers/comments.js @@ -0,0 +1,140 @@ +'use strict'; + +const Joi = require('joi'); +const Pify = require('pify'); +const Redis = require('redis'); +const UUID = require('uuid/v4'); + +const internals = {}; + +internals.kPostsPrefix = 'posts'; +internals.kCommentsPrefix = 'comments'; +internals.kMaxCommentSize = 255; + +internals.kCommentsSchema = Joi.object().keys({ + uuid: Joi.string().required(), + content: Joi.string().max(internals.kMaxCommentSize).required(), + timestamp: Joi.number().integer().required(), + userId: Joi.string().required(), + userName: Joi.string().required(), + userImage: Joi.string().required() +}); + +/** + * Handles the HTTP requests for comment related operations + * + * @class CommentsHandler + * @param {Dasein.tConfiguration} config The configuration to + * initialize. + */ +module.exports = internals.CommentsHandler = class CommentsHandler { + constructor(config) { + + this._ttl = config.ttl; + this._redis = Redis.createClient(config.redis); + + // Log an error if it happens. + this._redis.on('error', (err) => { + + console.error(err); + }); + } + + /** + * Fetches all available comments + * + * @function findAll + * @memberof CommentsHandler + * @instance + * @return {generator} a koa compatible handler generator function + */ + findAll() { + + const self = this; + + return function * (postId) { + + if (!this.state.user) { + return this.throw('Unauthorized', 401); + } + + const scan = Pify(self._redis.scan.bind(self._redis)); + const hgetall = Pify(self._redis.hgetall.bind(self._redis)); + + const commentsKey = `${internals.kCommentsPrefix}:${postId}:*`; + let keys = []; + let nextCursor = 0; + let currentKeys = null; + + do { + [nextCursor, currentKeys] = yield scan(nextCursor || 0, 'MATCH', commentsKey); + keys = keys.concat(currentKeys); + } while (nextCursor > 0); + + const comments = yield keys.map((key) => hgetall(key)); + + this.body = comments.sort((a, b) => a.timestamp - b.timestamp); + }; + } + + /** + * Creates a comment + * + * @function create + * @memberof CommentsHandler + * @instance + * @return {generator} a koa compatible handler generator function + */ + create() { + + const self = this; + + return function * (postId) { + + if (!this.state.user) { + return this.throw('Unauthorized', 401); + } + + const hmset = Pify(self._redis.hmset.bind(self._redis)); + const hgetall = Pify(self._redis.hgetall.bind(self._redis)); + const expire = Pify(self._redis.expire.bind(self._redis)); + + const uuid = UUID(); + const timestamp = Date.now(); + const user = this.state.user; + + const postKey = `${internals.kPostsPrefix}:${postId}`; + const commentKey = `${internals.kCommentsPrefix}:${postId}:${uuid}`; + + const comment = { + uuid, + content: this.request.body.content, + timestamp, + userId: user.screen_name, + userName: user.name, + userImage: user.profile_image_url_https + }; + + yield self._validate(comment).catch((err) => { + + this.throw(err.message, 422); + }); + + yield hmset(commentKey, comment); + yield expire(commentKey, self._ttl * 100); // this is me being lazy :( + // comments will last at most 100 bumps + // but will disappear eventually + yield expire(postKey, self._ttl); // bumps the parent comment TTL + + this.body = yield hgetall(commentKey); + }; + } + + // Validates the comment schema + + _validate(comment) { + + const validate = Pify(Joi.validate.bind(Joi)); + return validate(comment, internals.kCommentsSchema); + } +}; diff --git a/lib/handlers/posts.js b/lib/handlers/posts.js index 425fb5e..b5e4f0e 100644 --- a/lib/handlers/posts.js +++ b/lib/handlers/posts.js @@ -60,16 +60,18 @@ module.exports = internals.PostsHandler = class PostsHandler { const scan = Pify(self._redis.scan.bind(self._redis)); const hgetall = Pify(self._redis.hgetall.bind(self._redis)); - const cursor = parseInt(this.request.query.cursor) || 0; - const [nextCursor, keys] = yield scan(cursor, 'MATCH', `${internals.kPostsPrefix}:*`); + let keys = []; + let nextCursor = 0; + let currentKeys = null; - if (nextCursor > 0) { - this.append('Link', `<${this.request.origin}${this.request.path}?cursor=${nextCursor}>; rel="next"`); - } + do { + [nextCursor, currentKeys] = yield scan(nextCursor || 0, 'MATCH', `${internals.kPostsPrefix}:*`); + keys = keys.concat(currentKeys); + } while (nextCursor > 0); const posts = yield keys.map((key) => hgetall(key)); - this.body = posts; + this.body = posts.sort((a, b) => b.timestamp - a.timestamp); }; } diff --git a/static/css/app.css b/static/css/app.css index 34712e3..2177c51 100644 --- a/static/css/app.css +++ b/static/css/app.css @@ -47,16 +47,22 @@ section { /* The stream */ +.comments-container .comment .comment-meta, .posts-container .post .post-meta { background-color: lightgray; display: flex; align-items: center; + font-size: 20px; } +.comment-meta time, .comment-meta a, .post-meta time, .post-meta a { padding: 0 10px; } +.comments-container .comment .comment-content, +.comment-form-container .comment-content-input, +.comment-form-container .comment-submit, .posts-container .post .post-content, .post-form-container .post-content-input, .post-form-container .post-submit { @@ -68,6 +74,13 @@ section { padding: 10px; } +.comments-container .comment .comment-content, +.posts-container .post .post-content { + white-space: pre-wrap; + word-wrap: break-word; +} + +.comment-form-container .comment-content-input, .post-form-container .post-content-input { display: block; margin: 10px; @@ -76,6 +89,8 @@ section { height: 140px; } +.comment-form-container .comment-submit, +.comment-form-container .comment-activate, .post-form-container .post-submit { margin: 10px auto; display: block; @@ -87,7 +102,40 @@ section { } .posts-error, +.comments-error, .post-form-error { color: red; padding: 10px; } + +/* Comments */ + +.comments-container .comment .comment-meta { + background-color: ghostwhite; + font-size: 16px; +} + +.comments-container .comment .comment-meta img { + width: 24px; + height: 24px; +} + +.comments-container .comment .comment-content, +.comment-form-container .comment-content-input, +.comment-form-container .comment-submit { + font-size: 16px; +} + +.comment-form-container .comment-activate { + padding: 2px; + font-size: 12px; +} + +.comment-form-container .comment-content-input { + height: 70px; +} + +.comment-form-container .comment-activate:active, +.comment-form-container .comment-submit:active { + background-color: magenta; +} -- cgit