Use koa-router and fix graphql-uploads

This commit is contained in:
Alexandre Bodin 2019-08-21 11:05:33 +02:00
parent a148c43758
commit 7c5f1484ba
26 changed files with 273 additions and 510 deletions

View File

@ -7,10 +7,7 @@
},
"options": {
"increments": true,
"timestamps": [
"created_at",
"updated_at"
],
"timestamps": ["created_at", "updated_at"],
"comment": ""
},
"attributes": {
@ -20,6 +17,11 @@
"minLength": 5,
"type": "string"
},
"cover": {
"model": "file",
"via": "related",
"plugin": "upload"
},
"menu": {
"model": "menu",
"via": "restaurant"
@ -31,13 +33,7 @@
"model": "address"
},
"price_range": {
"enum": [
"very_cheap",
"cheap",
"average",
"expensive",
"very_expensive"
],
"enum": ["very_cheap", "cheap", "average", "expensive", "very_expensive"],
"type": "enumeration"
},
"description": {
@ -63,4 +59,4 @@
"type": "group"
}
}
}
}

View File

@ -28,29 +28,7 @@
"mode": "block"
},
"cors": {
"enabled": true,
"origin": "*",
"expose": [
"WWW-Authenticate",
"Server-Authorization"
],
"maxAge": 31536000,
"credentials": true,
"methods": [
"GET",
"POST",
"PUT",
"PATCH",
"DELETE",
"OPTIONS",
"HEAD"
],
"headers": [
"Content-Type",
"Authorization",
"X-Frame-Options",
"Origin"
]
"enabled": true
},
"ip": {
"enabled": false,

View File

@ -6,7 +6,8 @@
},
"csp": {
"enabled": true,
"policy": [{
"policy": [
{
"img-src": "'self' http:"
},
"block-all-mixed-content"
@ -30,29 +31,7 @@
"mode": "block"
},
"cors": {
"enabled": true,
"origin": "*",
"expose": [
"WWW-Authenticate",
"Server-Authorization"
],
"maxAge": 31536000,
"credentials": true,
"methods": [
"GET",
"POST",
"PUT",
"PATCH",
"DELETE",
"OPTIONS",
"HEAD"
],
"headers": [
"Content-Type",
"Authorization",
"X-Frame-Options",
"Origin"
]
"enabled": true
},
"ip": {
"enabled": false,

View File

@ -6,7 +6,8 @@
},
"csp": {
"enabled": true,
"policy": [{
"policy": [
{
"img-src": "'self' http:"
},
"block-all-mixed-content"
@ -30,29 +31,7 @@
"mode": "block"
},
"cors": {
"enabled": true,
"origin": "*",
"expose": [
"WWW-Authenticate",
"Server-Authorization"
],
"maxAge": 31536000,
"credentials": true,
"methods": [
"GET",
"POST",
"PUT",
"PATCH",
"DELETE",
"OPTIONS",
"HEAD"
],
"headers": [
"Content-Type",
"Authorization",
"X-Frame-Options",
"Origin"
]
"enabled": true
},
"ip": {
"enabled": false,

View File

@ -28,29 +28,7 @@
"mode": "block"
},
"cors": {
"enabled": true,
"origin": "*",
"expose": [
"WWW-Authenticate",
"Server-Authorization"
],
"maxAge": 31536000,
"credentials": true,
"methods": [
"GET",
"POST",
"PUT",
"PATCH",
"DELETE",
"OPTIONS",
"HEAD"
],
"headers": [
"Content-Type",
"Authorization",
"X-Frame-Options",
"Origin"
]
"enabled": true
},
"ip": {
"enabled": false,

View File

@ -6,7 +6,8 @@
},
"csp": {
"enabled": true,
"policy": [{
"policy": [
{
"img-src": "'self' http:"
},
"block-all-mixed-content"
@ -30,29 +31,7 @@
"mode": "block"
},
"cors": {
"enabled": true,
"origin": "*",
"expose": [
"WWW-Authenticate",
"Server-Authorization"
],
"maxAge": 31536000,
"credentials": true,
"methods": [
"GET",
"POST",
"PUT",
"PATCH",
"DELETE",
"OPTIONS",
"HEAD"
],
"headers": [
"Content-Type",
"Authorization",
"X-Frame-Options",
"Origin"
]
"enabled": true
},
"ip": {
"enabled": false,

View File

@ -6,7 +6,8 @@
},
"csp": {
"enabled": true,
"policy": [{
"policy": [
{
"img-src": "'self' http:"
},
"block-all-mixed-content"
@ -30,29 +31,7 @@
"mode": "block"
},
"cors": {
"enabled": true,
"origin": "*",
"expose": [
"WWW-Authenticate",
"Server-Authorization"
],
"maxAge": 31536000,
"credentials": true,
"methods": [
"GET",
"POST",
"PUT",
"PATCH",
"DELETE",
"OPTIONS",
"HEAD"
],
"headers": [
"Content-Type",
"Authorization",
"X-Frame-Options",
"Origin"
]
"enabled": true
},
"ip": {
"enabled": false,

View File

@ -52,9 +52,7 @@ function checkTokenValidity(response) {
if (auth.getToken()) {
return fetch(`${strapi.backendURL}/users/me`, options).then(() => {
if (response.status === 401) {
window.location = `${
strapi.remoteURL
}/plugins/users-permissions/auth/login`;
window.location = `${strapi.remoteURL}/plugins/users-permissions/auth/login`;
auth.clearAppStorage();
}

View File

@ -5,7 +5,7 @@ const uploadFiles = require('../../utils/upload-files');
module.exports = async (ctx, next) => {
const { source } = ctx.request.query;
const { model } = ctx.request.params;
const { model } = ctx.params;
const target = source === 'admin' ? strapi.admin : strapi.plugins[source];

View File

@ -48,28 +48,23 @@ module.exports = strapi => {
])
) {
route.config.prefix = '';
route.path = `/${
strapi.plugins.documentation.config['x-strapi-config'].path
}${route.path}`.replace('//', '/');
route.path = `/${strapi.plugins.documentation.config['x-strapi-config'].path}${route.path}`.replace(
'//',
'/'
);
}
return route;
}
);
strapi.router.route({
method: 'GET',
path: '/plugins/documentation/*.*',
handler: [
async (ctx, next) => {
ctx.url = path.basename(ctx.url);
strapi.router.get('/plugins/documentation/*', async (ctx, next) => {
ctx.url = path.basename(ctx.url);
return await koaStatic(swaggerUi.getAbsoluteFSPath(), {
maxage: strapi.config.middleware.settings.public.maxAge,
defer: true,
})(ctx, next);
},
],
return await koaStatic(swaggerUi.getAbsoluteFSPath(), {
maxage: strapi.config.middleware.settings.public.maxAge,
defer: true,
})(ctx, next);
});
},
};

View File

@ -81,6 +81,8 @@ module.exports = strapi => {
validationRules: [depthLimit(strapi.plugins.graphql.config.depthLimit)],
tracing: _.get(strapi.plugins.graphql, 'config.tracing', false),
playground: false,
cors: false,
bodyParserConfig: true,
};
// Disable GraphQL Playground in production environment.

View File

@ -59,7 +59,7 @@ function* uploadFiles(action) {
'/upload',
{ method: 'POST', headers, body: action.formData },
false,
false,
false
);
const newFiles = response.map(file => Map(file));
@ -103,10 +103,10 @@ function* search() {
: '/upload/files';
const params = isEmpty(search)
? {
_limit: pageParams._limit,
_sort: pageParams._sort,
_start,
}
_limit: pageParams._limit,
_sort: pageParams._sort,
_start,
}
: {};
const response = yield call(request, requestURL, { method: 'GET', params });
const entries = response.length === 0 ? [] : response.map(obj => Map(obj));

View File

@ -1,44 +1,120 @@
const path = require('path');
const _ = require('lodash');
const crypto = require('crypto');
const toArray = require('stream-to-array');
const uuid = require('uuid/v4');
function niceHash(buffer) {
return crypto
.createHash('sha256')
.update(buffer)
.digest('base64')
.replace(/=/g, '')
.replace(/\//g, '-')
.replace(/\+/, '_');
}
module.exports = {
mutation: `
upload(refId: ID, ref: String, source: String, file: Upload!): UploadFile!
upload(refId: ID, ref: String, field: String, source: String, file: Upload!): UploadFile!
multipleUpload(refId: ID, ref: String, field: String, source: String, files: [Upload]!): [UploadFile]!
`,
resolver: {
Query: {
file: false,
files: {
resolver: 'Upload.find'
}
resolver: 'Upload.find',
},
},
Mutation: {
createFile: false,
updateFile: false,
deleteFile: false,
upload: {
description: 'Upload one or many files',
resolver: async (obj, { file, ...fields}, { context }) => {
// Construct context to fit with koa-parser guidelines
// and avoid to update our business logic too much.
context.request.body = {
files: {
files: await file
},
fields
};
description: 'Upload one file',
resolver: async (obj, { file: upload, ...fields }) => {
const file = await formatFile(upload, fields);
// Call controller action.
await strapi.plugins.upload.controllers.upload.upload(context);
const config = await strapi
.store({
environment: strapi.config.environment,
type: 'plugin',
name: 'upload',
})
.get({ key: 'provider' });
// Handle case when the user is uploading only one file.
if (_.isArray(context.body) && context.body.length === 1) {
return context.body[0];
}
const uploadedFiles = await strapi.plugins.upload.services.upload.upload(
[file],
config
);
// Return response.
return context.body;
}
}
}
}
return uploadedFiles.length === 1 ? uploadedFiles[0] : uploadedFiles;
},
},
multipleUpload: {
description: 'Upload one file',
resolver: async (obj, { files: uploads, ...fields }) => {
const files = await Promise.all(
uploads.map(upload => formatFile(upload, fields))
);
const config = await strapi
.store({
environment: strapi.config.environment,
type: 'plugin',
name: 'upload',
})
.get({ key: 'provider' });
const uploadedFiles = await strapi.plugins.upload.services.upload.upload(
files,
config
);
// Return response.
return uploadedFiles;
},
},
},
},
};
const formatFile = async (upload, fields) => {
const { filename, mimetype, createReadStream } = await upload;
const stream = createReadStream();
const parts = await toArray(stream);
const buffers = parts.map(part =>
_.isBuffer(part) ? part : Buffer.from(part)
);
const buffer = Buffer.concat(buffers);
const fileData = {
name: filename,
sha256: niceHash(buffer),
hash: uuid().replace(/-/g, ''),
ext: path.extname(filename),
buffer,
mime: mimetype,
size: (buffer.length / 1000).toFixed(2),
};
const { refId, ref, source, field } = fields;
// Add details to the file to be able to create the relationships.
if (refId && ref && field) {
fileData.related = [
{
refId,
ref,
source,
field,
},
];
}
return fileData;
};

View File

@ -83,7 +83,9 @@ module.exports = {
const res = await strapi.plugins['upload'].services.upload.add(file);
// Remove temp file
fs.unlinkSync(file.tmpPath);
if (file.tmpPath) {
fs.unlinkSync(file.tmpPath);
}
return res;
};

View File

@ -6,6 +6,7 @@ const path = require('path');
const { EventEmitter } = require('events');
const fse = require('fs-extra');
const Koa = require('koa');
const Router = require('koa-router');
const _ = require('lodash');
const { logger, models } = require('strapi-utils');
const utils = require('./utils');
@ -64,6 +65,7 @@ class Strapi extends EventEmitter {
// Expose `koa`.
this.app = new Koa();
this.router = new Router();
// Mount the HTTP server.
this.server = http.createServer(this.app.callback());
@ -151,6 +153,8 @@ class Strapi extends EventEmitter {
// Init first start
utils.init(this.config);
this.app.use(this.router.routes()).use(this.router.allowedMethods());
// Launch server.
this.server.listen(this.config.port, async err => {
if (err) return this.stopWithError(err);
@ -315,11 +319,8 @@ class Strapi extends EventEmitter {
initCoreStore(this);
// Initialize hooks and middlewares.
await Promise.all([
initializeMiddlewares.call(this),
initializeHooks.call(this),
]);
await initializeMiddlewares.call(this);
await initializeHooks.call(this);
}
reload() {

View File

@ -4,7 +4,6 @@ const _ = require('lodash');
const { createController, createService } = require('../core-api');
const getURLFromSegments = require('../utils/url-from-segments');
const routerJoi = require('koa-joi-router');
module.exports = function(strapi) {
// Retrieve Strapi version.
@ -38,9 +37,6 @@ module.exports = function(strapi) {
);
}
// Initialize main router to use it in middlewares.
strapi.router = routerJoi();
Object.keys(strapi.groups).forEach(key => {
const group = strapi.groups[key];

View File

@ -1,27 +0,0 @@
{
"cors": {
"enabled": false,
"origin": "*",
"expose": [
"WWW-Authenticate",
"Server-Authorization"
],
"maxAge": 31536000,
"credentials": true,
"methods": [
"GET",
"POST",
"PUT",
"PATCH",
"DELETE",
"HEAD",
"OPTIONS"
],
"headers": [
"Content-Type",
"Authorization",
"X-Forwarded-Host"
],
"keepHeadersOnError": false
}
}

View File

@ -3,59 +3,47 @@
/**
* Module dependencies
*/
const cors = require('@koa/cors');
/**
* CORS hook
*/
const defaults = require('./defaults.json');
const kcors = require('kcors');
const defaults = {
origin: '*',
maxAge: 31536000,
credentials: true,
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'],
headers: ['Content-Type', 'Authorization', 'Origin', 'Accept'],
keepHeadersOnError: false,
};
module.exports = strapi => {
return {
/**
* Initialize the hook
*/
initialize() {
strapi.app.use(async (ctx, next) => {
if (ctx.request.admin) {
return kcors({
origin: '*',
exposeHeaders: defaults.cors.expose,
maxAge: defaults.cors.maxAge,
credentials: defaults.cors.credentials,
allowMethods: defaults.cors.methods,
allowHeaders: defaults.cors.headers,
keepHeadersOnError: defaults.cors.keepHeadersOnError,
})(ctx, next);
} else if (strapi.config.currentEnvironment.security.cors.enabled) {
return kcors({
origin: function(ctx) {
const whitelist = strapi.config.middleware.settings.cors.origin.split(
/\s*,\s*/
);
const requestOrigin = ctx.accept.headers.origin;
if (whitelist.includes('*')) {
return '*';
}
if (!whitelist.includes(requestOrigin)) {
return ctx.throw(`${requestOrigin} is not a valid origin`);
}
return requestOrigin;
},
exposeHeaders: strapi.config.middleware.settings.cors.expose,
maxAge: strapi.config.middleware.settings.cors.maxAge,
credentials: strapi.config.middleware.settings.cors.credentials,
allowMethods: strapi.config.middleware.settings.cors.methods,
allowHeaders: strapi.config.middleware.settings.cors.headers,
keepHeadersOnError:
strapi.config.middleware.settings.cors.keepHeadersOnError,
})(ctx, next);
}
if (strapi.config.currentEnvironment.security.cors.enabled !== true)
return;
await next();
});
const {
origin,
expose,
maxAge,
credentials,
methods,
headers,
keepHeadersOnError,
} = Object.assign({}, defaults, strapi.config.middleware.settings.cors);
strapi.app.use(
cors({
origin,
exposeHeaders: expose,
maxAge,
credentials,
allowMethods: methods,
allowHeaders: headers,
keepHeadersOnError,
})
);
},
};
};

View File

@ -3,17 +3,6 @@
const { uniq, difference, get, isUndefined, merge } = require('lodash');
module.exports = async function() {
// Set if is admin destination for middleware application.
this.app.use(async (ctx, next) => {
if (ctx.request.header['origin'] === 'http://localhost:4000') {
ctx.request.header['x-forwarded-host'] = 'strapi';
}
ctx.request.admin = ctx.request.header['x-forwarded-host'] === 'strapi';
await next();
});
/** Utils */
const middlewareConfig = this.config.middleware;

View File

@ -13,12 +13,16 @@ module.exports = strapi => {
*/
initialize() {
strapi.app.use(
body({
strapi.app.use((ctx, next) => {
// disable for graphql
// TODO: find a better way later
if (ctx.url === '/graphql') return next();
return body({
patchKoa: true,
...strapi.config.middleware.settings.parser,
})
);
})(ctx, next);
});
qs(strapi.app);
},

View File

@ -29,41 +29,34 @@ module.exports = strapi => {
);
// Serve /public index page.
strapi.router.route({
method: 'GET',
path: '/',
handler: [
async (ctx, next) => {
ctx.url = path.basename(`${ctx.url}/index.html`);
await next();
},
koaStatic(staticDir, {
maxage: maxAge,
defer: true,
}),
],
});
strapi.router.get(
'/',
async (ctx, next) => {
ctx.url = path.basename(`${ctx.url}/index.html`);
await next();
},
koaStatic(staticDir, {
maxage: maxAge,
defer: true,
})
);
// Match every route with an extension.
// The file without extension will not be served.
// Note: This route could be override by the user.
strapi.router.route({
method: 'GET',
path: '/*',
handler: [
async (ctx, next) => {
const parse = path.parse(ctx.url);
ctx.url = path.join(parse.dir, parse.base);
strapi.router.get(
'/*',
async (ctx, next) => {
const parse = path.parse(ctx.url);
ctx.url = path.join(parse.dir, parse.base);
await next();
},
koaStatic(staticDir, {
maxage: maxAge,
defer: true,
}),
],
});
await next();
},
koaStatic(staticDir, {
maxage: maxAge,
defer: true,
})
);
const basename = _.get(
strapi.config.currentEnvironment.server,
@ -75,59 +68,49 @@ module.exports = strapi => {
const buildDir = path.resolve(strapi.dir, 'build');
// Serve /admin index page.
strapi.router.route({
method: 'GET',
path: basename,
handler: [
async (ctx, next) => {
ctx.url = 'index.html';
await next();
},
koaStatic(buildDir, {
maxage: maxAge,
defer: true,
}),
],
});
strapi.router.get(
basename,
async (ctx, next) => {
ctx.url = 'index.html';
await next();
},
koaStatic(buildDir, {
maxage: maxAge,
defer: true,
})
);
// Allow refresh in admin page.
strapi.router.route({
method: 'GET',
path: `${basename}/*`,
handler: [
async (ctx, next) => {
const parse = path.parse(ctx.url);
strapi.router.get(
`${basename}/*`,
async (ctx, next) => {
const parse = path.parse(ctx.url);
if (parse.ext === '') {
ctx.url = 'index.html';
}
if (parse.ext === '') {
ctx.url = 'index.html';
}
await next();
},
koaStatic(buildDir, {
maxage: maxAge,
defer: true,
}),
],
});
await next();
},
koaStatic(buildDir, {
maxage: maxAge,
defer: true,
})
);
// Serve admin assets.
strapi.router.route({
method: 'GET',
path: `${basename}/*.*`,
handler: [
async (ctx, next) => {
ctx.url = path.basename(ctx.url);
strapi.router.get(
`${basename}/*.*`,
async (ctx, next) => {
ctx.url = path.basename(ctx.url);
await next();
},
koaStatic(buildDir, {
maxage: maxAge,
defer: true,
}),
],
});
await next();
},
koaStatic(buildDir, {
maxage: maxAge,
defer: true,
})
);
},
};
};

View File

@ -6,7 +6,7 @@
// Public node modules.
const _ = require('lodash');
const routerJoi = require('koa-joi-router');
const Router = require('koa-router');
/**
* Router hook
@ -32,26 +32,24 @@ module.exports = strapi => {
if (!_.isEmpty(_.get(strapi.admin, 'config.routes', false))) {
// Create router for admin.
// Prefix router with the admin's name.
const router = routerJoi();
const router = new Router({
prefix: '/admin',
});
_.forEach(strapi.admin.config.routes, value => {
composeEndpoint(value, null, router);
});
// router.prefix(strapi.config.admin.path || `/${strapi.config.paths.admin}`);
router.prefix('/admin');
// TODO:
// - Mount on main router `strapi.router.use(routerAdmin.middleware());`
// Mount admin router on Strapi router
strapi.app.use(router.middleware());
strapi.app.use(router.routes()).use(router.allowedMethods());
}
if (strapi.plugins) {
// Parse each plugin's routes.
_.forEach(strapi.plugins, (plugin, name) => {
const router = routerJoi();
const router = new Router({
prefix: `/${name}`,
});
// Exclude routes with prefix.
const excludedRoutes = _.omitBy(
@ -66,8 +64,6 @@ module.exports = strapi => {
}
);
router.prefix(`/${name}`);
// /!\ Could override main router's routes.
if (!_.isEmpty(excludedRoutes)) {
_.forEach(excludedRoutes, value => {
@ -75,16 +71,10 @@ module.exports = strapi => {
});
}
// TODO:
// - Mount on main router `strapi.router.use(router.middleware());`
// Mount plugin router
strapi.app.use(router.middleware());
strapi.app.use(router.routes()).use(router.allowedMethods());
});
}
// Let the router use our routes and allowed methods.
strapi.app.use(strapi.router.middleware());
},
};
};

View File

@ -13,11 +13,7 @@ module.exports = strapi => {
const endpoint = `${value.method} ${value.path}`;
const { policies, action, validate } = routerChecker(
value,
endpoint,
plugin
);
const { policies, action } = routerChecker(value, endpoint, plugin);
if (_.isUndefined(action) || !_.isFunction(action)) {
return strapi.log.warn(
@ -25,16 +21,6 @@ module.exports = strapi => {
);
}
router.route(
_.omitBy(
{
method: value.method,
path: value.path,
handler: _.remove([compose(policies), action], o => _.isFunction(o)),
validate,
},
_.isEmpty
)
);
router[value.method.toLowerCase()](value.path, compose(policies), action);
};
};

View File

@ -10,13 +10,10 @@ const _ = require('lodash');
// Strapi utilities.
const finder = require('strapi-utils').finder;
const regex = require('strapi-utils').regex;
const joijson = require('strapi-utils').joijson;
const policyUtils = require('strapi-utils').policy;
const { Joi } = require('koa-joi-router');
module.exports = strapi =>
function routerChecker(value, endpoint, plugin) {
const builder = joijson.builder(Joi);
const route = regex.detectRoute(endpoint);
// Define controller and action names.
@ -74,30 +71,9 @@ module.exports = strapi =>
}
});
// Init validate.
const validate = {};
if (
_.isString(_.get(value, 'config.validate')) &&
!_.isEmpty(_.get(value, 'config.validate'))
) {
const validator = _.get(
strapi.api,
currentApiName + '.validators.' + value.config.validate
);
_.merge(
validate,
_.mapValues(validator, value => {
return builder.build(value);
})
);
}
return {
route,
policies,
action,
validate,
};
};

View File

@ -12,6 +12,7 @@
"strapi": "./bin/strapi.js"
},
"dependencies": {
"@koa/cors": "^3.0.0",
"async": "^2.1.2",
"boom": "^7.3.0",
"chalk": "^2.4.1",
@ -22,7 +23,6 @@
"fs-extra": "^7.0.0",
"glob": "^7.1.2",
"inquirer": "^6.2.1",
"kcors": "^2.2.0",
"koa": "^2.1.0",
"koa-body": "^4.1.0",
"koa-compose": "^4.0.0",
@ -31,10 +31,10 @@
"koa-favicon": "^2.0.0",
"koa-i18n": "^2.1.0",
"koa-ip": "^2.0.0",
"koa-joi-router": "^6.0.0",
"koa-locale": "~1.3.0",
"koa-lusca": "~2.2.0",
"koa-qs": "^2.0.0",
"koa-router": "^7.4.0",
"koa-session": "^5.5.1",
"koa-static": "^4.0.1",
"lodash": "^4.17.5",

View File

@ -1024,15 +1024,6 @@
resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-8.0.2.tgz#f63a5ff00e891a4e7aa98f11119f9515c6672032"
integrity sha512-O6o6mrV4P65vVccxymuruucb+GhP2zl9NLCG8OdoFRS8BEGw3vwpPp20wpAtpbQQxz1CEUtmxJGgWhjq1XA3qw==
"@hapi/joi@15.0.0":
version "15.0.0"
resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-15.0.0.tgz#675d227b4c10d902fc5a96a2235665f0bc292e1b"
integrity sha512-pLCfcSeT26g59jEKZntmzlqe19dRMDNxCFKGD4CriF8+9FAD3Mq1aWNuKIFpKpX+u3x8lxLKXolDwk0gYl3b2w==
dependencies:
"@hapi/address" "2.x.x"
"@hapi/hoek" "6.x.x"
"@hapi/topo" "3.x.x"
"@hapi/joi@^15.0.3":
version "15.1.0"
resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-15.1.0.tgz#940cb749b5c55c26ab3b34ce362e82b6162c8e7a"
@ -1208,6 +1199,13 @@
dependencies:
vary "^1.1.2"
"@koa/cors@^3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@koa/cors/-/cors-3.0.0.tgz#df021b4df2dadf1e2b04d7c8ddf93ba2d42519cb"
integrity sha512-hDp+cXj6vTYSwHRJfiSpnf5dTMv3FmqNKh1or9BPJk4SHOviHnK9GoL9dT0ypt/E+hlkRkZ9edHylcosW3Ghrw==
dependencies:
vary "^1.1.2"
"@lerna/add@3.16.2":
version "3.16.2"
resolved "https://registry.yarnpkg.com/@lerna/add/-/add-3.16.2.tgz#90ecc1be7051cfcec75496ce122f656295bd6e94"
@ -3497,14 +3495,6 @@ autoprefixer@^9.5.1, autoprefixer@^9.6.1:
postcss "^7.0.17"
postcss-value-parser "^4.0.0"
await-busboy@1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/await-busboy/-/await-busboy-1.0.3.tgz#11b8941191c4b0fe5123988dab626ea88220119b"
integrity sha512-u2TaZLepph/OHrJZgD/qu0vMFl17ahkTz4HJYbnaRLqJX6q1x8SMbFNV1nJnIYRbUr3jyHuTwaCN0hIKfMA8YA==
dependencies:
black-hole-stream "0.0.1"
busboy "0.3.0"
aws-sdk@^2.382.0, aws-sdk@^2.457.0:
version "2.498.0"
resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.498.0.tgz#42e05965166a01b45e026e4922926df4cd160fc5"
@ -3790,11 +3780,6 @@ bl@~1.0.0:
dependencies:
readable-stream "~2.0.5"
black-hole-stream@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/black-hole-stream/-/black-hole-stream-0.0.1.tgz#33b7a06b9f1e7453d6041b82974481d2152aea42"
integrity sha1-M7ega58edFPWBBuCl0SB0hUq6kI=
block-stream@*:
version "0.0.9"
resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
@ -4167,13 +4152,6 @@ builtins@^1.0.3:
resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88"
integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og=
busboy@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.3.0.tgz#6ee3cb1c844fc1f691d8f9d824f70128b3b5e485"
integrity sha512-e+kzZRAbbvJPLjQz2z+zAyr78BSi9IFeBTyLwF76g78Q2zRt/RZ1NtS3MS17v2yLqYfLz69zHdC+1L4ja8PwqQ==
dependencies:
dicer "0.3.0"
busboy@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.3.1.tgz#170899274c5bf38aae27d5c62b71268cd585fd1b"
@ -4654,11 +4632,6 @@ clone-response@1.0.2:
dependencies:
mimic-response "^1.0.0"
clone@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=
clone@^1.0.2:
version "1.0.4"
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
@ -4685,16 +4658,6 @@ cluster-key-slot@^1.0.6:
resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d"
integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==
co-body@6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/co-body/-/co-body-6.0.0.tgz#965b9337d7f5655480787471f4237664820827e3"
integrity sha512-9ZIcixguuuKIptnY8yemEOuhb71L/lLf+Rl5JfJEUiDNJk0e02MBt7BPxR2GEh5mw8dPthQYR4jPI/BnS1MQgw==
dependencies:
inflation "^2.0.0"
qs "^6.5.2"
raw-body "^2.3.3"
type-is "^1.6.16"
co-body@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/co-body/-/co-body-4.2.0.tgz#74df20fa73262125dc45482af04e342ea8db3515"
@ -7430,7 +7393,7 @@ flatted@^2.0.0:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08"
integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==
flatten@1.0.2, flatten@^1.0.2:
flatten@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
integrity sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=
@ -9417,11 +9380,6 @@ is-fullwidth-code-point@^3.0.0:
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
is-gen-fn@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/is-gen-fn/-/is-gen-fn-0.0.1.tgz#f276bf2a0083571abd01add47cd4da105a64ce13"
integrity sha1-8na/KgCDVxq9Aa3UfNTaEFpkzhM=
is-generator-fn@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118"
@ -10478,11 +10436,6 @@ kareem@2.3.0:
resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.3.0.tgz#ef33c42e9024dce511eeaf440cd684f3af1fc769"
integrity sha512-6hHxsp9e6zQU8nXsP+02HGWXwTkOEw6IROhF2ZA28cYbUk4eJ6QbtZvdqZOdD9YPKghG3apk5eOCvs+tLl3lRg==
kcors@^2.2.0:
version "2.2.2"
resolved "https://registry.yarnpkg.com/kcors/-/kcors-2.2.2.tgz#b6250e7a4f0a33c8f477b7fd0dfa11a3f3ca518d"
integrity sha512-rIqbKa2S0gT0wC/790jsQM6hNpABHBNWQ7+XYS1xJV6zOGxlanW+RtCmlDn6wPZsGpRk371yy8abfBgl2OTavg==
keygrip@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.0.3.tgz#399d709f0aed2bab0a059e0cdd3a5023a053e1dc"
@ -10668,23 +10621,6 @@ koa-is-json@^1.0.0:
resolved "https://registry.yarnpkg.com/koa-is-json/-/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14"
integrity sha1-JzwH7c3Ljfaiwat9We52SRRR7BQ=
koa-joi-router@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/koa-joi-router/-/koa-joi-router-6.0.0.tgz#072ad3bfefb31b161166dfd70e567a0d86e24848"
integrity sha512-h2KSH4HfVr02wGi+AR8OIRZlJRoAzJ/6f/CXaU06EjLK3zuB2ftOw7SAhTzL7Fjsu1aM4u9EM5FtTxv984c0bg==
dependencies:
"@hapi/joi" "15.0.0"
await-busboy "1.0.3"
clone "2.1.2"
co-body "6.0.0"
debug "4.1.1"
delegates "1.0.0"
flatten "1.0.2"
is-gen-fn "0.0.1"
koa-router "7.4.0"
methods "1.1.2"
sliced "1.0.1"
koa-locale@~1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/koa-locale/-/koa-locale-1.3.0.tgz#95289ae6fa4098804a1ee8aadd46b0af1c82cbcb"
@ -10707,7 +10643,7 @@ koa-qs@^2.0.0:
merge-descriptors "~0.0.2"
qs "~2.3.3"
koa-router@7.4.0, koa-router@^7.4.0:
koa-router@^7.4.0:
version "7.4.0"
resolved "https://registry.yarnpkg.com/koa-router/-/koa-router-7.4.0.tgz#aee1f7adc02d5cb31d7d67465c9eacc825e8c5e0"
integrity sha512-IWhaDXeAnfDBEpWS6hkGdZ1ablgr6Q6pGdXCyK38RbzuH4LkUOpPqPw+3f8l8aTDrQmBQ7xJc0bs2yV4dzcO+g==
@ -11705,7 +11641,7 @@ merge2@^1.2.3:
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.3.tgz#7ee99dbd69bb6481689253f018488a1b902b0ed5"
integrity sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==
methods@1.1.2, methods@^1.0.1, methods@~1.1.2:
methods@^1.0.1, methods@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
@ -14924,7 +14860,7 @@ raw-body@2.4.0:
iconv-lite "0.4.24"
unpipe "1.0.0"
raw-body@^2.2.0, raw-body@^2.3.3:
raw-body@^2.2.0:
version "2.4.1"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.1.tgz#30ac82f98bb5ae8c152e67149dac8d55153b168c"
integrity sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA==