hapi-sequelize-crud2
Advanced tools
Comparing version 2.5.4 to 2.6.0
@@ -9,11 +9,11 @@ 'use strict'; | ||
var _oneToOne = require('./one-to-one'); | ||
var _one_to_one = require('./one_to_one'); | ||
var _oneToOne2 = _interopRequireDefault(_oneToOne); | ||
var _one_to_one2 = _interopRequireDefault(_one_to_one); | ||
var _oneToMany = require('./one-to-many'); | ||
var _one_to_many = require('./one_to_many'); | ||
var _oneToMany2 = _interopRequireDefault(_oneToMany); | ||
var _one_to_many2 = _interopRequireDefault(_one_to_many); | ||
exports.oneToOne = _oneToOne2['default']; | ||
exports.oneToMany = _oneToMany2['default']; | ||
exports.oneToOne = _one_to_one2['default']; | ||
exports.oneToMany = _one_to_many2['default']; |
@@ -19,5 +19,5 @@ 'use strict'; | ||
var _error = require('./error'); | ||
var _hoek = require('hoek'); | ||
var _error2 = _interopRequireDefault(_error); | ||
var _hoek2 = _interopRequireDefault(_hoek); | ||
@@ -28,2 +28,6 @@ var _joi = require('joi'); | ||
var _error = require('./error'); | ||
var _error2 = _interopRequireDefault(_error); | ||
var _helpers = require('./helpers'); | ||
@@ -36,19 +40,33 @@ | ||
var prefix = undefined, | ||
scopePrefix = undefined; | ||
scopePrefix = undefined, | ||
controllerOptions = undefined; | ||
var defaultControllerOptions = { | ||
index: true, | ||
get: true, | ||
count: true, | ||
scope: true, | ||
create: true, | ||
destroy: true, | ||
update: true | ||
}; | ||
var methods = {}; | ||
exports['default'] = function (server, model, options) { | ||
prefix = options.prefix; | ||
scopePrefix = options.scopePrefix; | ||
prefix = options.prefix, scopePrefix = options.scopePrefix, controllerOptions = _hoek2['default'].applyToDefaults(defaultControllerOptions, options.controllerOptions || {}); | ||
index(server, model); | ||
count(server, model); | ||
get(server, model); | ||
scope(server, model); | ||
create(server, model); | ||
destroy(server, model); | ||
update(server, model); | ||
for (var method in methods) { | ||
var methodOpts = controllerOptions[method]; | ||
if (!!methodOpts) { | ||
methodOpts = typeof methodOpts === 'object' ? methodOpts : {}; | ||
methods[method](server, model, methodOpts); | ||
} | ||
} | ||
}; | ||
var index = function index(server, model) { | ||
server.route(_createDecoratedObject([{ | ||
var index = methods.index = function (server, model, options) { | ||
var route = _hoek2['default'].applyToDefaults(_createDecoratedObject([{ | ||
key: 'method', | ||
@@ -72,3 +90,3 @@ initializer: function initializer() { | ||
case 0: | ||
_queryParams = (0, _helpers.queryParams)(request); | ||
_queryParams = (0, _helpers.queryParams)(server, request); | ||
where = _queryParams.where; | ||
@@ -157,8 +175,10 @@ offset = _queryParams.offset; | ||
} | ||
}])); | ||
}]), options); | ||
server.route(route); | ||
}; | ||
exports.index = index; | ||
var get = function get(server, model) { | ||
server.route(_createDecoratedObject([{ | ||
var get = methods.get = function (server, model, options) { | ||
var route = _hoek2['default'].applyToDefaults(_createDecoratedObject([{ | ||
key: 'method', | ||
@@ -182,3 +202,3 @@ initializer: function initializer() { | ||
case 0: | ||
_queryParams2 = (0, _helpers.queryParams)(request); | ||
_queryParams2 = (0, _helpers.queryParams)(server, request); | ||
include = _queryParams2.include; | ||
@@ -222,10 +242,12 @@ context$2$0.next = 4; | ||
} | ||
}])); | ||
}]), options); | ||
server.route(route); | ||
}; | ||
exports.get = get; | ||
var scope = function scope(server, model) { | ||
var scope = methods.scope = function (server, model, options) { | ||
var scopes = Object.keys(model.options.scopes); | ||
server.route(_createDecoratedObject([{ | ||
var route = _hoek2['default'].applyToDefaults(_createDecoratedObject([{ | ||
key: 'method', | ||
@@ -249,3 +271,3 @@ initializer: function initializer() { | ||
case 0: | ||
_queryParams3 = (0, _helpers.queryParams)(request); | ||
_queryParams3 = (0, _helpers.queryParams)(server, request); | ||
where = _queryParams3.where; | ||
@@ -321,3 +343,3 @@ offset = _queryParams3.offset; | ||
initializer: function initializer() { | ||
var _joi$string; | ||
var _Joi$string; | ||
@@ -327,3 +349,3 @@ return { | ||
params: { | ||
scope: (_joi$string = _joi2['default'].string()).valid.apply(_joi$string, _toConsumableArray(scopes)) | ||
scope: (_Joi$string = _joi2['default'].string()).valid.apply(_Joi$string, _toConsumableArray(scopes)) | ||
}, | ||
@@ -339,8 +361,10 @@ query: { | ||
} | ||
}])); | ||
}]), options); | ||
server.route(route); | ||
}; | ||
exports.scope = scope; | ||
var create = function create(server, model) { | ||
server.route(_createDecoratedObject([{ | ||
var create = methods.create = function (server, model, options) { | ||
var route = _hoek2['default'].applyToDefaults(_createDecoratedObject([{ | ||
key: 'method', | ||
@@ -377,8 +401,10 @@ initializer: function initializer() { | ||
} | ||
}])); | ||
}]), options); | ||
server.route(route); | ||
}; | ||
exports.create = create; | ||
var update = function update(server, model) { | ||
server.route(_createDecoratedObject([{ | ||
var update = methods.update = function (server, model, options) { | ||
var route = _hoek2['default'].applyToDefaults(_createDecoratedObject([{ | ||
key: 'method', | ||
@@ -431,3 +457,3 @@ initializer: function initializer() { | ||
params: { | ||
id: _joi2['default'].number().integer() | ||
id: _helpers.validation.id | ||
} | ||
@@ -437,8 +463,10 @@ } | ||
} | ||
}])); | ||
}]), options); | ||
server.route(route); | ||
}; | ||
exports.update = update; | ||
var destroy = function destroy(server, model) { | ||
server.route(_createDecoratedObject([{ | ||
var destroy = methods.destroy = function (server, model, options) { | ||
var route = _hoek2['default'].applyToDefaults(_createDecoratedObject([{ | ||
key: 'method', | ||
@@ -491,3 +519,3 @@ initializer: function initializer() { | ||
params: { | ||
id: _joi2['default'].number().integer() | ||
id: _helpers.validation.id | ||
} | ||
@@ -497,8 +525,10 @@ } | ||
} | ||
}])); | ||
}]), options); | ||
server.route(route); | ||
}; | ||
exports.destroy = destroy; | ||
var count = function count(server, model) { | ||
server.route(_createDecoratedObject([{ | ||
var count = methods.count = function (server, model, options) { | ||
var route = _hoek2['default'].applyToDefaults(_createDecoratedObject([{ | ||
key: 'method', | ||
@@ -522,3 +552,3 @@ initializer: function initializer() { | ||
case 0: | ||
_queryParams4 = (0, _helpers.queryParams)(request); | ||
_queryParams4 = (0, _helpers.queryParams)(server, request); | ||
where = _queryParams4.where; | ||
@@ -550,3 +580,5 @@ context$2$0.next = 4; | ||
} | ||
}])); | ||
}]), options); | ||
server.route(route); | ||
}; | ||
@@ -553,0 +585,0 @@ |
@@ -6,20 +6,15 @@ 'use strict'; | ||
}); | ||
var Joi = require('joi'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
var _joi = require('joi'); | ||
var _joi2 = _interopRequireDefault(_joi); | ||
var validation = { | ||
id: _joi2['default'].number().integer().min(1).required(), | ||
limit: _joi2['default'].number().integer().min(0)['default'](0, 'results offset'), | ||
offset: _joi2['default'].number().integer().min(1)['default'](20, 'number of results per set'), | ||
id: Joi.number().integer().min(1).required(), | ||
offset: Joi.number().integer().min(0)['default'](0, 'results offset'), | ||
limit: Joi.number().integer().min(1)['default'](20, 'number of results per set'), | ||
include: function include(model) { | ||
return _joi2['default'].string(); | ||
return Joi.string(); | ||
}, | ||
filter: function filter(model) { | ||
return _joi2['default'].object(); | ||
return Joi.object(); | ||
} | ||
@@ -29,12 +24,13 @@ }; | ||
exports.validation = validation; | ||
var queryParams = function queryParams(request) { | ||
var queryParams = function queryParams(server, request) { | ||
var q = request.query; | ||
var models = server.plugins['hapi-sequelize'].db.sequelize.models; | ||
return { | ||
where: q.filter, | ||
where: q.filter || {}, | ||
offset: q.offset, | ||
limit: q.limit, | ||
include: q.include ? [request.models[q.include]] : [] | ||
include: q.include ? [models[q.include]] : [] | ||
}; | ||
}; | ||
exports.queryParams = queryParams; |
'use strict'; | ||
Object.defineProperty(exports, '__esModule', { | ||
value: true | ||
}); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
var _crud = require('./crud'); | ||
var _controller_manager = require('./controller_manager'); | ||
var _crud2 = _interopRequireDefault(_crud); | ||
var _controller_manager2 = _interopRequireDefault(_controller_manager); | ||
var _fs = require('fs'); | ||
var _fs2 = _interopRequireDefault(_fs); | ||
var _hoek = require('hoek'); | ||
var _hoek2 = _interopRequireDefault(_hoek); | ||
var _url = require('url'); | ||
var _url2 = _interopRequireDefault(_url); | ||
var _qs = require('qs'); | ||
@@ -17,2 +25,6 @@ | ||
var _crud = require('./crud'); | ||
var _crud2 = _interopRequireDefault(_crud); | ||
var _snakeCase = require('snake-case'); | ||
@@ -22,26 +34,31 @@ | ||
var _url = require('url'); | ||
var internals = {}; | ||
var _url2 = _interopRequireDefault(_url); | ||
internals.onRequest = function (request, reply) { | ||
var uri = request.raw.req.url; | ||
var parsed = _url2['default'].parse(uri, false); | ||
parsed.query = _qs2['default'].parse(parsed.query); | ||
request.setUrl(parsed); | ||
var register = function register(server, options, next) { | ||
return reply['continue'](); | ||
}; | ||
internals.optionDefaults = { | ||
prefix: '', | ||
scopePrefix: 's', | ||
snakeCase: false, | ||
'private': [], | ||
controllers: 'controllers/**/*.js' | ||
}; | ||
exports.register = function (server, options, next) { | ||
if (options === undefined) options = {}; | ||
options.prefix = options.prefix || ''; | ||
options.scopePrefix = options.scopePrefix || 's'; | ||
options.snakeCase = options.snakeCase || false; | ||
options['private'] = options['private'] || []; | ||
options = _hoek2['default'].applyToDefaults(internals.optionDefaults, options); | ||
var db = server.plugins['hapi-sequelize'].db; | ||
var models = db.sequelize.models; | ||
var onRequest = function onRequest(request, reply) { | ||
var uri = request.raw.req.url; | ||
var parsed = _url2['default'].parse(uri, false); | ||
parsed.query = _qs2['default'].parse(parsed.query); | ||
request.setUrl(parsed); | ||
return reply['continue'](); | ||
}; | ||
var modelNames = Object.keys(models).filter(function (m) { | ||
return options['private'].indexOf(m) === -1; | ||
}); | ||
var convertCase = options.snakeCase ? _snakeCase2['default'] : function (str) { | ||
@@ -51,5 +68,7 @@ return str; | ||
_controller_manager2['default'].loadControllers(server, options.controllers); | ||
server.ext({ | ||
type: 'onRequest', | ||
method: onRequest | ||
method: internals.onRequest | ||
}); | ||
@@ -62,7 +81,9 @@ | ||
try { | ||
for (var _iterator = Object.keys(models).filter(function (m) { | ||
return options['private'].indexOf(m) === -1; | ||
})[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
for (var _iterator = modelNames[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
var modelName = _step.value; | ||
if (!_controller_manager2['default'].controllersEnabled(modelName)) { | ||
continue; | ||
} | ||
var model = models[modelName]; | ||
@@ -77,6 +98,14 @@ var _model$options$name = model.options.name; | ||
// Join tables | ||
if (model.options.name.singular !== model.name) continue; | ||
if (model.options.name.singular !== model.name) { | ||
continue; | ||
} | ||
options.controllerOptions = _controller_manager2['default'].controllerOptions(modelName); | ||
(0, _crud2['default'])(server, model, options); | ||
if (!_controller_manager2['default'].associationsEnabled(modelName)) { | ||
continue; | ||
} | ||
var _iteratorNormalCompletion2 = true; | ||
@@ -90,3 +119,8 @@ var _didIteratorError2 = false; | ||
if (!_controller_manager2['default'].associationEnabled(modelName, key)) { | ||
continue; | ||
} | ||
var association = model.associations[key]; | ||
var associationName = association.options.name; | ||
var associationType = association.associationType; | ||
@@ -96,4 +130,2 @@ var source = association.source; | ||
var associationName = association.options.name; | ||
association._plural = convertCase(associationName.plural); | ||
@@ -152,6 +184,4 @@ association._singular = convertCase(associationName.singular); | ||
register.attributes = { | ||
exports.register.attributes = { | ||
pkg: require('../package.json') | ||
}; | ||
exports.register = register; |
{ | ||
"name": "hapi-sequelize-crud2", | ||
"version": "2.5.4", | ||
"version": "2.6.0", | ||
"description": "Hapi plugin that automatically generates a more RESTful API for CRUD, building on hapi-sequelize-crud", | ||
@@ -12,6 +12,7 @@ "main": "build/index.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
"test": "lab -r console -o stdout -r html -o test/coverage.html -I core,Reflect,__core-js_shared__,System,_babelPolyfill,regeneratorRuntime", | ||
"clean": "rm -rf build/*" | ||
}, | ||
"repository": { | ||
"git": "https://github.com/alexanderreiff/hapi-sequelize-crud" | ||
"git": "https://github.com/alexanderreiff/hapi-sequelize-crud2" | ||
}, | ||
@@ -28,2 +29,4 @@ "files": [ | ||
"babel": "5.8.3", | ||
"babel-polyfill": "^6.6.1", | ||
"code": "^2.1.0", | ||
"ghooks": "1.0.3", | ||
@@ -33,10 +36,24 @@ "grunt": "0.4.5", | ||
"grunt-contrib-clean": "0.7.0", | ||
"grunt-contrib-watch": "0.6.1" | ||
"grunt-contrib-watch": "0.6.1", | ||
"hapi": "13.x.x", | ||
"hapi-sequelize": "^2.2.4", | ||
"http-status-codes": "^1.0.6", | ||
"lab": "^10.2.0", | ||
"sequelize": "^3.19.3", | ||
"sqlite3": "^3.1.1" | ||
}, | ||
"dependencies": { | ||
"boom": "^3.1.2", | ||
"camel-case": "^1.2.2", | ||
"glob": "^7.0.3", | ||
"hoek": "^3.0.4", | ||
"joi": "7.2.1", | ||
"qs": "^6.1.0", | ||
"snake-case": "^1.1.2" | ||
}, | ||
"peerDependencies": { | ||
"hapi": "13.x.x", | ||
"sequelize": "^3.x", | ||
"hapi-sequelize": "^2.x" | ||
} | ||
} |
152
README.md
hapi-sequelize-crud2 | ||
==================== | ||
Automatically generate a (more) RESTful API for your models and associations | ||
Automatically generate a RESTful API for your models and associations, with simple route configuration and behavior extensibility. | ||
This plugin depends on [`hapi-sequelize`](https://github.com/danecando/hapi-sequelize). | ||
This plugin depends on [`hapi-sequelize`](https://github.com/danecando/hapi-sequelize), and builds on the work of [`hapi-sequelize-crud`](https://github.com/mdibaiee/hapi-sequelize-crud). | ||
@@ -16,3 +16,3 @@ ``` | ||
// First, register hapi-sequelize | ||
await register({ | ||
await server.register({ | ||
register: require('hapi-sequelize'), | ||
@@ -23,11 +23,15 @@ options: { ... } | ||
// Then, define your associations | ||
let db = server.plugins['hapi-sequelize'].db; | ||
let models = db.sequelize.models; | ||
const db = server.plugins['hapi-sequelize'].db; | ||
const models = db.sequelize.models; | ||
associations(models); // pretend this function defines our associations | ||
// Now, register hapi-sequelize-crud2 | ||
await register({ | ||
await server.register({ | ||
register: require('hapi-sequelize-crud2'), | ||
options: { | ||
prefix: '/v1' | ||
prefix: '', // Global prefix for all routes | ||
scopePrefix: 's', // Prefix for model scope routes (see below) | ||
snakeCase: false, // Create routes with snake_case instead of default camelCase | ||
controllers: 'controllers/**/*.js', // Glob to handler controller override files (can be array) [see below] | ||
private: [] // Array of model names to exclude from route creation | ||
} | ||
@@ -37,3 +41,3 @@ }); | ||
Please note that you should register `hapi-sequelize-crud` after defining your | ||
Please note that you should register `hapi-sequelize-crud2` after defining your | ||
associations. | ||
@@ -43,40 +47,118 @@ | ||
Let's say you have a `many-to-many` association like this: | ||
Let's say you have associations like this: | ||
```javascript | ||
Team.belongsToMany(Role, { through: 'TeamRoles' }); | ||
Role.belongsToMany(Team, { through: 'TeamRoles' }); | ||
Team.belongsToMany(Role, { through: 'teamRoles' }); | ||
Team.hasOne(Player, { as: 'captain' }); | ||
``` | ||
You get these: | ||
You get these CRUD routes: | ||
``` | ||
# get an array of records | ||
GET /teams/{id}/roles | ||
GET /roles/{id}/teams | ||
# might also append query parameters to search for | ||
GET /roles/{id}/teams?members=5 | ||
| Method | Route | Name | | ||
|---|---|---| | ||
| GET | `/teams` | index<sup>1 2 3</sup> | | ||
| GET | `/teams/{id}` | get<sup>3</sup> | | ||
| POST | `/teams` | create | | ||
| PUT | `/teams/{id}` | update | | ||
| DELETE | `/teams/{id}` | destroy | | ||
| GET | `/teams/s/{scope}` | scope<sup>1 2 3</sup> | | ||
| GET | `/teams/count` | count<sup>1</sup> | | ||
# create | ||
POST /teams/{id}/roles | ||
POST /roles/{id}/teams | ||
# add to associations | ||
PUT /teams/{id}/role/{id} | ||
PUT /roles/{id}/team/{id} | ||
And these one-to-one association routes: | ||
# delete | ||
DELETE /teams/{id} | ||
DELETE /roles/{id} | ||
| Method | Route | Name | Description | | ||
|---|---|---|---| | ||
| GET | `/teams/{id}/captain` | index<sup>3</sup> | | ||
| POST | `/teams/{id}/captain` | create | Create a new related model and sets the association | | ||
| PUT | `/teams/{id}/captain/{aid}` | update | Sets the association with an existing related model | | ||
| DELETE | `/teams/{id}/captain` | destroy | Unsets the association | | ||
# un-associate | ||
DELETE /teams/{id}/roles/{id} | ||
DELETE /roles/{id}/teams/{id} | ||
And these one-to-many association routes: | ||
# count | ||
GET /teams/count | ||
GET /roles/{id}/teams/count | ||
| Method | Route | Name | Description | | ||
|---|---|---|---| | ||
| GET | `/teams/{id}/roles` | index<sup>1 2 3</sup> | | ||
| POST | `/teams/{id}/roles` | create | Create a new related model and adds it to the associations | | ||
| PUT | `/teams/{id}/roles/{aid}` | update | Sets the association with an existing related model | | ||
| PUT | `/teams/{id}/roles` | updateMany | Sets the association with a many related models, as provided by id[] querystring parameter | | ||
| DELETE | `/teams/{id}/roles/{aid}` | destroy | Unsets the association | | ||
| DELETE | `/teams/{id}/roles` | destroyMany | Unsets all associations, optionally limited to those given by id[] querystring parameter | | ||
| GET | `/teams/{id}/roles/count` | count<sup>1</sup> | Counts the number of associated models | | ||
# you can specify a prefix to change the URLs like this: | ||
GET /v1/teams/{id}/roles | ||
<sup>1</sup> Accepts a query string parameter object `filter` to limit results by given criteria, e.g. `?filter[status]=active` | ||
<sup>2</sup> Accepts query string parameters `limit` and `offset` to control paginated results | ||
<sup>3</sup> Accepts a querystring parameter `include` to include a related model with the returned parent model | ||
##Custom Route Configuration | ||
Automatic route handling is convenient for getting a basic API in place during development. But | ||
in a production application, authentication, ACL and caching concerns need to be addressed. | ||
Taking advantage of Hapi's convention over configuration approach to route set-up, you can easy | ||
extend and override the plugin's default route options and handler. | ||
Simply create a file named modelName.js (or model_name.js if you prefer) in your controllers path | ||
defined in the plugin options, and your options will be mixed in during route registration. A | ||
controller should export a function that accepts two arguments, a Hapi server instance and the model | ||
object, and returns an object mapping route names to Hapi route configuration object partials or | ||
`false` to disable a route. | ||
For example, a read-only endpoint with limited scope access may look like: | ||
```javascript | ||
// This standard Hapi package make composing | ||
// route configuration options easy | ||
const Hoek = require('hoek'); | ||
const Joi = require('joi'); | ||
modules.export = function(server, Team) { | ||
const plural = Team.options.name.plural; | ||
const readConfig = { | ||
cache: { | ||
expiresIn: 30 * 1000, | ||
private: 'private' | ||
} | ||
}; | ||
return { | ||
index: readConfig, | ||
get: readConfig, | ||
scope: Hoek.applyToDefaults(readConfig, { | ||
config: { | ||
validation: { | ||
params: { | ||
scope: Joi.string().valid('scope1', 'scope2') | ||
} | ||
} | ||
} | ||
}), | ||
count: Hoek.applyToDefaults(readConfig, { | ||
path: `${plural}/total`, | ||
handler: function(request, reply) { | ||
... | ||
const total = ...; | ||
reply({total: total}); | ||
} | ||
}), | ||
create: false, | ||
update: false, | ||
destroy: false, | ||
associations: { | ||
captain: { | ||
create: false, | ||
update: false, | ||
destroy: false | ||
}, | ||
roles: false | ||
} | ||
}; | ||
}); | ||
``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
55906
10
1395
1
161
10
14
3
1
+ Addedcamel-case@^1.2.2
+ Addedglob@^7.0.3
+ Addedhoek@^3.0.4
+ Added@hapi/address@1.0.1(transitive)
+ Added@types/geojson@1.0.6(transitive)
+ Addedaccept@2.2.3(transitive)
+ Addedammo@2.1.2(transitive)
+ Addedb64@3.1.1(transitive)
+ Addedbalanced-match@1.0.2(transitive)
+ Addedbluebird@3.7.2(transitive)
+ Addedboom@4.3.15.3.3(transitive)
+ Addedbrace-expansion@1.1.11(transitive)
+ Addedcall@3.0.4(transitive)
+ Addedcamel-case@1.2.2(transitive)
+ Addedcatbox@7.2.1(transitive)
+ Addedcatbox-memory@2.1.1(transitive)
+ Addedconcat-map@0.0.1(transitive)
+ Addedcontent@3.1.2(transitive)
+ Addedcryptiles@3.2.1(transitive)
+ Addeddebug@2.6.9(transitive)
+ Addeddepd@1.1.2(transitive)
+ Addeddottie@1.1.1(transitive)
+ Addedfs.realpath@1.0.0(transitive)
+ Addedgeneric-pool@2.4.2(transitive)
+ Addedglob@5.0.157.2.3(transitive)
+ Addedhapi@13.5.3(transitive)
+ Addedhapi-sequelize@2.2.4(transitive)
+ Addedheavy@4.1.1(transitive)
+ Addedhoek@2.16.3(transitive)
+ Addedinflection@1.13.4(transitive)
+ Addedinflight@1.0.6(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addediron@4.1.1(transitive)
+ Addeditems@2.2.1(transitive)
+ Addedjoi@12.1.18.4.29.2.0(transitive)
+ Addedkilt@2.0.2(transitive)
+ Addedlodash@4.17.21(transitive)
+ Addedmime-db@1.53.0(transitive)
+ Addedmimos@3.1.1(transitive)
+ Addedminimatch@3.1.2(transitive)
+ Addedmoment-timezone@0.5.46(transitive)
+ Addedms@2.0.0(transitive)
+ Addednigel@2.1.1(transitive)
+ Addedonce@1.4.0(transitive)
+ Addedpath-is-absolute@1.0.1(transitive)
+ Addedpeekaboo@2.0.2(transitive)
+ Addedpez@2.2.2(transitive)
+ Addedretry-as-promised@2.3.2(transitive)
+ Addedsemver@5.7.2(transitive)
+ Addedsequelize@3.35.1(transitive)
+ Addedshimmer@1.1.0(transitive)
+ Addedshot@3.5.2(transitive)
+ Addedsqlizr@1.2.0(transitive)
+ Addedstatehood@4.1.0(transitive)
+ Addedsubtext@4.4.1(transitive)
+ Addedterraformer@1.0.12(transitive)
+ Addedterraformer-wkt-parser@1.2.1(transitive)
+ Addedtoposort-class@1.0.1(transitive)
+ Addedupper-case@1.1.3(transitive)
+ Addeduuid@3.4.0(transitive)
+ Addedvalidator@5.7.0(transitive)
+ Addedvise@2.1.1(transitive)
+ Addedwkx@0.2.0(transitive)
+ Addedwrappy@1.0.2(transitive)
+ Addedwreck@12.6.2(transitive)