From 78deff85bdad55c7c636f146bc16f56b1f4d16d4 Mon Sep 17 00:00:00 2001 From: Mireille Niwemuhuza Date: Mon, 10 Jun 2019 14:27:08 +0200 Subject: [PATCH] feat: add registration validation errors --- .env.example | 4 +- .travis.yml | 4 + package.json | 4 +- src/api/routes/authRouter.js | 5 +- src/config/config.js | 6 +- src/{api => }/helpers/Token.helper.js | 0 src/helpers/signupSchema.js | 49 ++++ src/index.js | 9 +- src/middleware/userExists.js | 23 ++ src/middleware/usernameExists.js | 23 ++ src/middleware/validateBody.js | 24 ++ .../migrations/20190611080237-create-user.js | 48 +++ src/sequelize/models/index.js | 3 + src/sequelize/models/user.js | 16 + .../seeders/20190611101225-test-user.js | 23 ++ test/auth.js | 67 +++++ yarn.lock | 276 +++++++++++++++++- 17 files changed, 556 insertions(+), 28 deletions(-) rename src/{api => }/helpers/Token.helper.js (100%) create mode 100644 src/helpers/signupSchema.js create mode 100644 src/middleware/userExists.js create mode 100644 src/middleware/usernameExists.js create mode 100644 src/middleware/validateBody.js create mode 100644 src/sequelize/migrations/20190611080237-create-user.js create mode 100644 src/sequelize/models/user.js create mode 100644 src/sequelize/seeders/20190611101225-test-user.js diff --git a/.env.example b/.env.example index 9215b1d..032bdbc 100644 --- a/.env.example +++ b/.env.example @@ -4,6 +4,4 @@ DATABASE_URL= LOCAL_DB_USER= LOCAL_DB_PASSWORD= LOCAL_DB_NAME= -TEST_DB_USER= -TEST_DB_PASSWORD= -TEST_DB_NAME= +TEST_DATABASE_URL= diff --git a/.travis.yml b/.travis.yml index 121cbf7..a1c2c07 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,10 @@ language: node_js node_js: - "stable" +before_script: + - yarn add sequelize-cli + - sequelize db:migrate + - sequelize db:seed:all script: - yarn test before_install: diff --git a/package.json b/package.json index 86a973c..b14d670 100644 --- a/package.json +++ b/package.json @@ -8,12 +8,13 @@ "build": "babel src --out-dir dist", "serve": "node dist/index.js", "start": "node dist/index.js", - "test": "nyc --reporter=html --reporter=text mocha ./test/*.js --exit", + "test": "nyc --reporter=text ./node_modules/.bin/mocha --recursive ./test/* --exit --require @babel/register --require @babel/polyfill ", "coverage": "nyc report --reporter=text-lcov | coveralls" }, "author": "Andela Simulations Programme", "license": "MIT", "dependencies": { + "@hapi/joi": "^15.0.3", "body-parser": "^1.18.3", "cors": "^2.8.4", "dotenv": "^8.0.0", @@ -23,6 +24,7 @@ "express-jwt": "^5.3.1", "express-session": "^1.15.6", "jsonwebtoken": "^8.5.1", + "joi": "^14.3.1", "method-override": "^2.3.10", "methods": "^1.1.2", "morgan": "^1.9.1", diff --git a/src/api/routes/authRouter.js b/src/api/routes/authRouter.js index 48ca89e..8440a0d 100644 --- a/src/api/routes/authRouter.js +++ b/src/api/routes/authRouter.js @@ -1,9 +1,12 @@ import { Router } from 'express'; import authController from '../controllers/auth'; +import signupValidation from '../../middleware/validateBody'; +import emailValidation from '../../middleware/userExists'; +import usernameValidation from '../../middleware/usernameExists'; const authRouter = Router(); const { signup } = authController; -authRouter.post('/signup', signup); +authRouter.post('/signup', signupValidation, usernameValidation.usernameExist, emailValidation.userExist, signup); export default authRouter; diff --git a/src/config/config.js b/src/config/config.js index 1bb3143..fbedacc 100644 --- a/src/config/config.js +++ b/src/config/config.js @@ -15,11 +15,7 @@ config.staging = { }; config.test = { - username: process.env.TEST_DB_USER, - password: process.env.TEST_DB_PASSWORD, - database: process.env.TEST_DB_NAME, - host: '127.0.0.1', - dialect: 'postgres' + use_env_variable: 'TEST_DATABASE_URL', }; config.production = { diff --git a/src/api/helpers/Token.helper.js b/src/helpers/Token.helper.js similarity index 100% rename from src/api/helpers/Token.helper.js rename to src/helpers/Token.helper.js diff --git a/src/helpers/signupSchema.js b/src/helpers/signupSchema.js new file mode 100644 index 0000000..358af96 --- /dev/null +++ b/src/helpers/signupSchema.js @@ -0,0 +1,49 @@ +import Joi from '@hapi/joi'; + +export default { + signup: (userData) => { + const schema = { + firstName: Joi.string() + .trim() + .required() + .regex(/^[A-Za-z_-]+$/) + .min(3) + .label('First name is required, it must have at least 3 letters and must contain only letters'), + lastName: Joi.string() + .trim() + .required() + .regex(/^[A-Za-z_.-]+$/) + .min(3) + .label('Last name is required, it must have at least 3 letters and must contain only letters'), + username: Joi.string() + .trim() + .lowercase() + .required() + .regex(/^[a-zA-Z0-9_.-]+$/) + .min(3) + .label('Username is required, it must have at least 3 letters and must contain only letters, numbers, underscores(_), hyphens (-) and points (.)'), + email: Joi.string() + .trim() + .lowercase() + .email() + .required() + .label('Email is required and should look like this : example@email.com!'), + password: Joi.string() + .trim() + .regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.{8,})/) + .required() + .label('Password is required and must be at least 8 letters containing' + + ' at least a number a Lowercase letter and an Uppercase letter'), + confirmPassword: Joi.any() + .required() + .valid(Joi.ref('password')) + .label('Password and Confirm Password do not match'), + bio: Joi.string(), + image: Joi.string(), + dateOfBirth: Joi.string(), + gender: Joi.string() + }; + + return Joi.validate(userData, schema, { abortEarly: false }); + }, +}; diff --git a/src/index.js b/src/index.js index 434c072..963987a 100644 --- a/src/index.js +++ b/src/index.js @@ -1,7 +1,7 @@ import express from 'express'; import dotenv from 'dotenv'; import swaggerUi from 'swagger-ui-express'; -import api from './api/routes'; +import api from './api/routes/index'; import globalMiddleware from './middleware/globalMiddleware'; import swaggerDoc from '../swagger.json'; import db from './sequelize/models/index'; @@ -12,10 +12,11 @@ dotenv.config(); const port = process.env.PORT || 3000; const app = express(); -globalMiddleware(app); -app.use('/', swaggerUi.serve, swaggerUi.setup(swaggerDoc)); +globalMiddleware(app); app.use('/api', api); +app.get('/', swaggerUi.serve, swaggerUi.setup(swaggerDoc)); + sequelize.sync().then(() => { app.listen(port, () => { @@ -23,3 +24,5 @@ sequelize.sync().then(() => { console.log(`Database succesfully connected\nServer listening on port: ${port} in ${process.env.NODE_ENV} mode`); }); }); + +export default app; diff --git a/src/middleware/userExists.js b/src/middleware/userExists.js new file mode 100644 index 0000000..aece282 --- /dev/null +++ b/src/middleware/userExists.js @@ -0,0 +1,23 @@ +import models from '../sequelize/models'; + +const checkEmail = { + async userExist(req, res, next) { + const { email } = req.body; + await models.User.findAll({ + where: { + email + }, + }).then((data) => { + if (data.length > 0) { + return res.status(400).json({ + status: 400, + message: 'This email is already in use', + }); + } + }); + + next(); + }, +}; + +export default checkEmail; diff --git a/src/middleware/usernameExists.js b/src/middleware/usernameExists.js new file mode 100644 index 0000000..4bf7b19 --- /dev/null +++ b/src/middleware/usernameExists.js @@ -0,0 +1,23 @@ +import models from '../sequelize/models'; + +const usernameAvailability = { + async usernameExist(req, res, next) { + const { username } = req.body; + await models.User.findAll({ + where: { + username + }, + }).then((data) => { + if (data.length > 0) { + return res.status(400).json({ + status: 400, + message: 'This username is not available, Please choose another one!', + }); + } + }); + + next(); + }, +}; + +export default usernameAvailability; diff --git a/src/middleware/validateBody.js b/src/middleware/validateBody.js new file mode 100644 index 0000000..5a6a828 --- /dev/null +++ b/src/middleware/validateBody.js @@ -0,0 +1,24 @@ +import validate from '../helpers/signupSchema'; + + +const validateBody = (req, res, next) => { + const data = req.body; + const err = validate.signup(data); + + if (err.error === null) { + req.body = data; + next(); + } else { + const allErrors = []; + + err.error.details.forEach((errors) => { + allErrors.push(errors.context.label); + }); + + return res.status(400).send({ + message: allErrors, + }); + } +}; + +export default validateBody; diff --git a/src/sequelize/migrations/20190611080237-create-user.js b/src/sequelize/migrations/20190611080237-create-user.js new file mode 100644 index 0000000..14a14cd --- /dev/null +++ b/src/sequelize/migrations/20190611080237-create-user.js @@ -0,0 +1,48 @@ + + +module.exports = { + up: (queryInterface, Sequelize) => queryInterface.createTable('Users', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + firstName: { + type: Sequelize.STRING + }, + lastName: { + type: Sequelize.STRING + }, + username: { + type: Sequelize.STRING + }, + email: { + type: Sequelize.STRING + }, + password: { + type: Sequelize.STRING + }, + bio: { + type: Sequelize.STRING + }, + image: { + type: Sequelize.STRING + }, + dateOfBirth: { + type: Sequelize.DATE + }, + gender: { + type: Sequelize.STRING + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }), + down: queryInterface => queryInterface.dropTable('Users') +}; diff --git a/src/sequelize/models/index.js b/src/sequelize/models/index.js index 1f3abb0..e212a58 100644 --- a/src/sequelize/models/index.js +++ b/src/sequelize/models/index.js @@ -1,6 +1,9 @@ import fs from 'fs'; import path from 'path'; import Sequelize from 'sequelize'; +import dotenv from 'dotenv'; + +dotenv.config(); const basename = path.basename(__filename); const env = process.env.NODE_ENV || 'development'; diff --git a/src/sequelize/models/user.js b/src/sequelize/models/user.js new file mode 100644 index 0000000..2f776ca --- /dev/null +++ b/src/sequelize/models/user.js @@ -0,0 +1,16 @@ + + +module.exports = (sequelize, DataTypes) => { + const User = sequelize.define('User', { + firstName: DataTypes.STRING, + lastName: DataTypes.STRING, + username: DataTypes.STRING, + email: DataTypes.STRING, + password: DataTypes.STRING, + bio: DataTypes.STRING, + image: DataTypes.STRING, + dateOfBirth: DataTypes.DATE, + gender: DataTypes.STRING + }, {}); + return User; +}; diff --git a/src/sequelize/seeders/20190611101225-test-user.js b/src/sequelize/seeders/20190611101225-test-user.js new file mode 100644 index 0000000..9301861 --- /dev/null +++ b/src/sequelize/seeders/20190611101225-test-user.js @@ -0,0 +1,23 @@ + + +module.exports = { + up: queryInterface => + /* + Add altering commands here. + Return a promise to correctly handle asynchronicity. + */ + + queryInterface.bulkInsert('Users', [{ + firstName: 'Mireille', + lastName: 'Niwemuhuza', + username: 'mifeille', + email: 'nimilleer@gmail.com', + password: 'Mireille1!', + bio: '', + image: '', + dateOfBirth: '12/12/2000', + gender: '', + createdAt: new Date(), + updatedAt: new Date(), + }], {}), +}; diff --git a/test/auth.js b/test/auth.js index e69de29..7caf626 100644 --- a/test/auth.js +++ b/test/auth.js @@ -0,0 +1,67 @@ +import chaiHttp from 'chai-http'; +import chai from 'chai'; +import dotenv from 'dotenv'; +import server from '../src/index'; + + +dotenv.config(); + +const { expect } = chai; +chai.use(chaiHttp); + + +describe('User Registration', () => { + it('should not let a user signup without valid credentials ', (done) => { + chai.request(server) + .post('/api/auth/signup') + .send({ + firstName: 'Emy', + lastName: 'Rukundo', + username: 'emy2', + email: 'rukundogmail.com', + password: 'Rukundo1!', + confirmPassword: 'Rukundo1!' + }) + .end((err, res) => { + expect(res.status).to.equal(400); + expect(res.body).to.be.an('object'); + done(); + }); + }); + + it('should not let a user signup with an already existing email ', (done) => { + chai.request(server) + .post('/api/auth/signup') + .send({ + firstName: 'Emy', + lastName: 'Rukundo', + username: 'mifeillee', + email: 'nimilleer@gmail.com', + password: 'Rukundo1!', + confirmPassword: 'Rukundo1!' + }) + .end((err, res) => { + expect(res.status).to.equal(400); + expect(res.body).to.be.an('object'); + done(); + }); + }); + + it('should not let a user signup with an already existing username ', (done) => { + chai.request(server) + .post('/api/auth/signup') + .send({ + firstName: 'Emy', + lastName: 'Rukundo', + username: 'mifeille', + email: 'nimiller@gmail.com', + password: 'Rukundo1!', + confirmPassword: 'Rukundo1!' + }) + .end((err, res) => { + expect(res.status).to.equal(400); + expect(res.body).to.be.an('object'); + done(); + }); + }); +}); diff --git a/yarn.lock b/yarn.lock index 66ac56f..0316c40 100644 --- a/yarn.lock +++ b/yarn.lock @@ -667,6 +667,32 @@ lodash "^4.17.11" to-fast-properties "^2.0.0" +"@hapi/address@2.x.x": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.0.0.tgz#9f05469c88cb2fd3dcd624776b54ee95c312126a" + integrity sha512-mV6T0IYqb0xL1UALPFplXYQmR0twnXG0M6jUswpquqT2sD12BOiCiLy3EvMp/Fy7s3DZElC4/aPjEjo2jeZpvw== + +"@hapi/hoek@6.x.x": + version "6.2.4" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-6.2.4.tgz#4b95fbaccbfba90185690890bdf1a2fbbda10595" + integrity sha512-HOJ20Kc93DkDVvjwHyHawPwPkX44sIrbXazAUDiUXaY2R9JwQGo2PhFfnQtdrsIe4igjG2fPgMra7NYw7qhy0A== + +"@hapi/joi@^15.0.3": + version "15.0.3" + resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-15.0.3.tgz#e94568fd859e5e945126d5675e7dd218484638a7" + integrity sha512-z6CesJ2YBwgVCi+ci8SI8zixoj8bGFn/vZb9MBPbSyoxsS2PnWYjHcyTM17VLK6tx64YVK38SDIh10hJypB+ig== + dependencies: + "@hapi/address" "2.x.x" + "@hapi/hoek" "6.x.x" + "@hapi/topo" "3.x.x" + +"@hapi/topo@3.x.x": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-3.1.0.tgz#5c47cd9637c2953db185aa957a27bcb2a8b7a6f8" + integrity sha512-gZDI/eXOIk8kP2PkUKjWu9RW8GGVd2Hkgjxyr/S7Z+JF+0mr7bAlbw+DkTRxnD580o8Kqxlnba9wvqp5aOHBww== + dependencies: + "@hapi/hoek" "6.x.x" + "@types/chai@4": version "4.1.7" resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.7.tgz#1b8e33b61a8c09cbe1f85133071baa0dbf9fa71a" @@ -740,7 +766,7 @@ ansi-escapes@^3.2.0: resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== -ansi-regex@^2.0.0: +ansi-regex@^2.0.0, ansi-regex@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= @@ -897,6 +923,14 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== +babel-runtime@^6.23.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" @@ -1169,6 +1203,18 @@ cli-boxes@^1.0.0: resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM= +cli-color@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/cli-color/-/cli-color-1.4.0.tgz#7d10738f48526824f8fe7da51857cb0f572fe01f" + integrity sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w== + dependencies: + ansi-regex "^2.1.1" + d "1" + es5-ext "^0.10.46" + es6-iterator "^2.0.3" + memoizee "^0.4.14" + timers-ext "^0.1.5" + cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" @@ -1239,7 +1285,7 @@ combined-stream@^1.0.6, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" -commander@^2.8.1, commander@~2.20.0: +commander@^2.19.0, commander@^2.8.1, commander@~2.20.0: version "2.20.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== @@ -1259,6 +1305,14 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= +config-chain@^1.1.12: + version "1.1.12" + resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" + integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA== + dependencies: + ini "^1.3.4" + proto-list "~1.2.1" + configstore@^3.0.0: version "3.1.2" resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.2.tgz#c6f25defaeef26df12dd33414b001fe81a543f8f" @@ -1339,7 +1393,7 @@ core-js-pure@3.1.3: resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.1.3.tgz#4c90752d5b9471f641514f3728f51c1e0783d0b5" integrity sha512-k3JWTrcQBKqjkjI0bkfXS0lbpWPxYuHWfMMjC1VDmzU4Q58IwSbuXSo99YO/hUHlw/EB4AlfA2PVxOGkrIq6dA== -core-js@^2.6.5: +core-js@^2.4.0, core-js@^2.6.5: version "2.6.9" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2" integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A== @@ -1425,6 +1479,13 @@ crypto-random-string@^1.0.0: resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4= +d@1: + version "1.0.0" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" + integrity sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8= + dependencies: + es5-ext "^0.10.9" + dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" @@ -1603,6 +1664,16 @@ ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer "^5.0.1" +editorconfig@^0.15.3: + version "0.15.3" + resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-0.15.3.tgz#bef84c4e75fb8dcb0ce5cee8efd51c15999befc5" + integrity sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g== + dependencies: + commander "^2.19.0" + lru-cache "^4.1.5" + semver "^5.6.0" + sigmund "^1.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" @@ -1671,11 +1742,47 @@ es-to-primitive@^1.2.0: is-date-object "^1.0.1" is-symbol "^1.0.2" +es5-ext@^0.10.35, es5-ext@^0.10.45, es5-ext@^0.10.46, es5-ext@^0.10.9, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46: + version "0.10.50" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.50.tgz#6d0e23a0abdb27018e5ac4fd09b412bc5517a778" + integrity sha512-KMzZTPBkeQV/JcSQhI5/z6d9VWJ3EnQ194USTUwIYZ2ZbpN8+SGXQKt1h68EX44+qt+Fzr8DO17vnxrw7c3agw== + dependencies: + es6-iterator "~2.0.3" + es6-symbol "~3.1.1" + next-tick "^1.0.0" + es6-error@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== +es6-iterator@^2.0.3, es6-iterator@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-symbol@^3.1.1, es6-symbol@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" + integrity sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc= + dependencies: + d "1" + es5-ext "~0.10.14" + +es6-weak-map@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.3.tgz#b6da1f16cc2cc0d9be43e6bdbfc5e7dfcdf31d53" + integrity sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA== + dependencies: + d "1" + es5-ext "^0.10.46" + es6-iterator "^2.0.3" + es6-symbol "^3.1.1" + escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -1836,6 +1943,14 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= +event-emitter@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + integrity sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk= + dependencies: + d "1" + es5-ext "~0.10.14" + execa@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" @@ -2138,6 +2253,15 @@ fresh@0.5.2: resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= +fs-extra@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-minipass@^1.2.5: version "1.2.6" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07" @@ -2287,7 +2411,7 @@ got@^6.7.1: unzip-response "^2.0.1" url-parse-lax "^1.0.0" -graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2: +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6: version "4.1.15" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== @@ -2386,6 +2510,11 @@ he@1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +hoek@6.x.x: + version "6.1.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-6.1.3.tgz#73b7d33952e01fe27a38b0457294b79dd8da242c" + integrity sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ== + homedir-polyfill@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" @@ -2708,7 +2837,7 @@ is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" -is-promise@^2.1.0: +is-promise@^2.1, is-promise@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= @@ -2757,6 +2886,13 @@ isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= +isemail@3.x.x: + version "3.2.0" + resolved "https://registry.yarnpkg.com/isemail/-/isemail-3.2.0.tgz#59310a021931a9fb06bbb51e155ce0b3f236832c" + integrity sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg== + dependencies: + punycode "2.x.x" + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -2831,6 +2967,26 @@ istanbul-reports@^2.2.4: dependencies: handlebars "^4.1.2" +joi@^14.3.1: + version "14.3.1" + resolved "https://registry.yarnpkg.com/joi/-/joi-14.3.1.tgz#164a262ec0b855466e0c35eea2a885ae8b6c703c" + integrity sha512-LQDdM+pkOrpAn4Lp+neNIFV3axv1Vna3j38bisbQhETPMANYRbFJFUyOZcOClYvM/hppMhGWuKSFEK9vjrB+bQ== + dependencies: + hoek "6.x.x" + isemail "3.x.x" + topo "3.x.x" + +js-beautify@^1.8.8: + version "1.10.0" + resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.10.0.tgz#9753a13c858d96828658cd18ae3ca0e5783ea672" + integrity sha512-OMwf/tPDpE/BLlYKqZOhqWsd3/z2N3KOlyn1wsCRGFwViE8LOQTcDtathQvHvZc+q+zWmcNAbwKSC+iJoMaH2Q== + dependencies: + config-chain "^1.1.12" + editorconfig "^0.15.3" + glob "^7.1.3" + mkdirp "~0.5.1" + nopt "~4.0.1" + js-levenshtein@^1.1.3: version "1.1.6" resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d" @@ -2896,7 +3052,14 @@ json5@^2.1.0: dependencies: minimist "^1.2.0" -jsonwebtoken@^8.1.0, jsonwebtoken@^8.5.1: +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + +jsonwebtoken@^8.1.0, jsonwebtoken@^8.3.0: version "8.5.1" resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== @@ -3071,7 +3234,7 @@ lodash.set@^4.0.0: resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM= -lodash@^4.17.11: +lodash@^4.17.11, lodash@^4.17.5: version "4.17.11" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== @@ -3100,7 +3263,7 @@ lowercase-keys@^1.0.0: resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== -lru-cache@^4.0.1: +lru-cache@^4.0.1, lru-cache@^4.1.5: version "4.1.5" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== @@ -3108,6 +3271,13 @@ lru-cache@^4.0.1: pseudomap "^1.0.2" yallist "^2.1.2" +lru-queue@0.1: + version "0.1.0" + resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3" + integrity sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM= + dependencies: + es5-ext "~0.10.2" + make-dir@^1.0.0: version "1.3.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" @@ -3156,6 +3326,20 @@ mem@^4.0.0: mimic-fn "^2.0.0" p-is-promise "^2.0.0" +memoizee@^0.4.14: + version "0.4.14" + resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.14.tgz#07a00f204699f9a95c2d9e77218271c7cd610d57" + integrity sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg== + dependencies: + d "1" + es5-ext "^0.10.45" + es6-weak-map "^2.0.2" + event-emitter "^0.3.5" + is-promise "^2.1" + lru-queue "0.1" + next-tick "1" + timers-ext "^0.1.5" + merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" @@ -3274,7 +3458,7 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1: +mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= @@ -3404,6 +3588,11 @@ nested-error-stacks@^2.0.0: resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz#0fbdcf3e13fe4994781280524f8b96b0cdff9c61" integrity sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug== +next-tick@1, next-tick@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" + integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -3461,7 +3650,7 @@ nodemon@^1.19.1: undefsafe "^2.0.2" update-notifier "^2.5.0" -nopt@^4.0.1: +nopt@^4.0.1, nopt@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= @@ -4052,6 +4241,11 @@ progress@^2.0.0: resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== +proto-list@~1.2.1: + version "1.2.4" + resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= + proxy-addr@~2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34" @@ -4083,16 +4277,16 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" +punycode@2.x.x, punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= -punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - qs@6.7.0, qs@^6.5.1: version "6.7.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" @@ -4201,6 +4395,11 @@ regenerate@^1.4.0: resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== + regenerator-runtime@^0.13.2: version "0.13.2" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447" @@ -4454,6 +4653,20 @@ send@0.17.1: range-parser "~1.2.1" statuses "~1.5.0" +sequelize-cli@^5.4.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/sequelize-cli/-/sequelize-cli-5.4.0.tgz#6a2c2af331466414d8b2ecb6912e24d2de0d04b5" + integrity sha512-4Gvl0yH0T3hhSdiiOci3+IKIfVG9x2os0hGWsbfa8QuyGgk9mZOqgTBnSCRtuxsdAyzUix9kfcTnfNolVNtprg== + dependencies: + bluebird "^3.5.3" + cli-color "^1.4.0" + fs-extra "^7.0.1" + js-beautify "^1.8.8" + lodash "^4.17.5" + resolve "^1.5.0" + umzug "^2.1.0" + yargs "^12.0.5" + sequelize-pool@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/sequelize-pool/-/sequelize-pool-1.0.2.tgz#89c767882bbdb8a41dac66922ed9820939a5401e" @@ -4539,6 +4752,11 @@ shimmer@^1.1.0: resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== +sigmund@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" + integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA= + signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" @@ -4880,6 +5098,14 @@ timed-out@^4.0.0: resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= +timers-ext@^0.1.5: + version "0.1.7" + resolved "https://registry.yarnpkg.com/timers-ext/-/timers-ext-0.1.7.tgz#6f57ad8578e07a3fb9f91d9387d65647555e25c6" + integrity sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ== + dependencies: + es5-ext "~0.10.46" + next-tick "1" + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -4922,6 +5148,13 @@ toidentifier@1.0.0: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== +topo@3.x.x: + version "3.0.3" + resolved "https://registry.yarnpkg.com/topo/-/topo-3.0.3.tgz#d5a67fb2e69307ebeeb08402ec2a2a6f5f7ad95c" + integrity sha512-IgpPtvD4kjrJ7CRA3ov2FhWQADwv+Tdqbsf1ZnPUSAtCJ9e1Z44MmoSGDXGk4IppoZA7jd/QRkNddlLJWlUZsQ== + dependencies: + hoek "6.x.x" + toposort-class@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/toposort-class/-/toposort-class-1.0.1.tgz#7ffd1f78c8be28c3ba45cd4e1a3f5ee193bd9988" @@ -4999,6 +5232,14 @@ uid-safe@~2.1.5: dependencies: random-bytes "~1.0.0" +umzug@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/umzug/-/umzug-2.2.0.tgz#6160bdc1817e4a63a625946775063c638623e62e" + integrity sha512-xZLW76ax70pND9bx3wqwb8zqkFGzZIK8dIHD9WdNy/CrNfjWcwQgQkGCuUqcuwEBvUm+g07z+qWvY+pxDmMEEw== + dependencies: + babel-runtime "^6.23.0" + bluebird "^3.5.3" + undefsafe@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.2.tgz#225f6b9e0337663e0d8e7cfd686fc2836ccace76" @@ -5051,6 +5292,11 @@ unique-string@^1.0.0: dependencies: crypto-random-string "^1.0.0" +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"