hapi-darwin
Advanced tools
Comparing version 1.0.2 to 1.1.0
263
index.js
@@ -1,251 +0,36 @@ | ||
/* Hapi-darwin 1.0.2 */ | ||
/* Multiple mode have lots of problems */ | ||
/* | ||
darwin dont need eventEmitter because we using async...await | ||
additional darwin handling errors with try...catch | ||
*/ | ||
'use strict'; | ||
import os from 'os'; | ||
import * as fs from 'fs'; | ||
import mkdirp from 'mkdirp'; | ||
import { promisify } from 'util'; | ||
import { basename, extname, join } from 'path'; | ||
import fileType from 'file-type'; | ||
import readChunk from 'read-chunk'; | ||
import imageMagick from 'imagemagick'; | ||
const uploader = require('./lib/uploader'); | ||
const internals = {}; | ||
const register = (server, options, next) => { | ||
const sizeOf = promisify(require('image-size')); | ||
internals.uploader = (file, options = {}) => { | ||
if (!file) throw new Error('No file(s) recived'); | ||
internals.options = Object.assign({ | ||
tmp: os.tmpdir(), | ||
name: undefined, | ||
filter: /\.(jpg|jpeg|png|gif)$/, | ||
multiple: false, | ||
options = { | ||
dest: `./images`, | ||
names: undefined, | ||
safeName: true, | ||
delOrginal: false, // when using `imageVersions` | ||
formats: ['jpeg', 'png', 'gif', 'webp'], | ||
maxFiles: 1, | ||
minFileSize: 0.001 * 1024 * 1024, // 10 KB | ||
maxFileSize: 1 * 1024 * 1024, // 1 MB | ||
minHeight: 10, // in pixels | ||
maxHeight: 10000, // in pixels | ||
minWidth: 10, // in pixels | ||
maxWidth: 10000, // in pixels | ||
destination: './public/storage/null', | ||
urlDestination: 'https://hapi-darwin/public/storage/null', | ||
// imageVersions: { | ||
// ['thumbnail-720']: { | ||
// width: 2 * 720, | ||
// height: 720, | ||
// imageArgs: ['-auto-orient'] | ||
// }, | ||
// ['thumbnail-360']: { | ||
// width: 2 * 360, | ||
// height: 360, | ||
// imageArgs: ['-auto-orient'] | ||
// } | ||
// }, | ||
imageVersions: undefined | ||
}, internals.options, options); | ||
minPixels: 1e2, | ||
maxPixels: 1e6, | ||
versions: [], | ||
addOriginal: false, | ||
...options | ||
}; | ||
if (Array.isArray(file) && internals.options.multiple) { | ||
server.expose({ | ||
uploader: (files, opts = {}) => uploader(files, { ...options, ...opts }) | ||
}); | ||
if (file.length > internals.options.maxFiles) throw new Error('Maximum files recived'); | ||
const promises = file.map(each => internals._fileHandler(each)); | ||
return Promise.all(promises); | ||
} else { | ||
if (file.length > 1) throw new Error('Maximum files recived'); | ||
return internals._fileHandler(file); | ||
} | ||
} | ||
internals.setOptions = (options) => { | ||
internals.options = Object.assign({}, options); | ||
next && next(); | ||
}; | ||
internals.validateBeforReciving = (fileName) => { | ||
if (!fileName.match(internals.options.filter)) return false; | ||
return true; | ||
register.attributes = { | ||
once: true, | ||
pkg: require('./package.json'), | ||
name: '@ecmacommunity/hapi-darwin' | ||
}; | ||
internals.validateAfterRecived = async (fileDetails) => { | ||
const dimensions = await sizeOf(fileDetails.path); | ||
const buffer = readChunk.sync(fileDetails.path, 0, 4100); | ||
const file = fileType(buffer); | ||
let error; | ||
if (internals.options.minFileSize && internals.options.minFileSize > fileDetails.size) { | ||
error = 'File is too small'; | ||
} else if (internals.options.maxFileSize && internals.options.maxFileSize < fileDetails.size) { | ||
error = 'File is too big'; | ||
} else if (!internals.options.filter.test(`x.${file.ext}`)) { | ||
error = 'Filetype not allowed'; | ||
} else if (internals.options.minHeight && internals.options.minHeight > dimensions.height) { | ||
error = `Minimum height should be ${internals.options.minHeight}px`; | ||
} else if (internals.options.maxHeight && internals.options.maxHeight < dimensions.height) { | ||
error = `Maximum height should be ${internals.options.maxHeight}px`; | ||
} else if (internals.options.minWidth && internals.options.minWidth > dimensions.width) { | ||
error = `Minimum width should be ${internals.options.minWidth}px`; | ||
} else if (internals.options.maxWidth && internals.options.maxWidth < dimensions.width) { | ||
error = `Maximum width should be ${internals.options.maxWidth}px`; | ||
} | ||
return error; | ||
module.exports = { | ||
register, | ||
...register.attributes | ||
}; | ||
internals.safeNameFs = async (filename) => { | ||
// Prevent directory traversal and creating hidden system files: | ||
let name = basename(filename.toString()).replace(/^\.+/, ''); | ||
// Prevent overwriting existing files: | ||
while (fs.existsSync(join(internals.options.destination, name))) { | ||
name = name.replace(/(?:(?:_\(([\d]+)\))?(\.[^.]+))?$/, (s, index, ext) => `_(${(parseInt(index, 10) || 0) + 1})${ext || ''}`); | ||
} | ||
return name; | ||
}; | ||
internals._fileHandler = async (file) => { | ||
const orignalname = file.hapi.filename; | ||
let filename = internals.options.name ? `${internals.options.name}${extname(orignalname)}` : orignalname; | ||
if (internals.options.safeName) { | ||
filename = await internals.safeNameFs(filename); | ||
} | ||
const path = join(internals.options.destination, filename); | ||
const tmpName = `_darwin_${Date.now()}_${filename}`; | ||
const tmpPath = join(internals.options.tmp, tmpName); | ||
const fileStream = fs.createWriteStream(tmpPath); | ||
const imageVersions = internals.options.imageVersions ? Object.keys(internals.options.imageVersions) : []; | ||
if (!internals.validateBeforReciving(orignalname)) { | ||
throw new Error('Filetype not allowed'); | ||
} | ||
return new Promise((resolve, reject) => { | ||
file.on('error', err => { | ||
reject(err); | ||
}); | ||
file.pipe(fileStream); | ||
file.on('end', async err => { | ||
const fileDetails = { | ||
fieldname: file.hapi.name, | ||
originalname: file.hapi.filename, | ||
filename, | ||
mimetype: file.hapi.headers['content-type'], | ||
destination: internals.options.destination, | ||
urlDestination: internals.options.urlDestination, | ||
path, | ||
url: join(internals.options.urlDestination, filename), | ||
size: fs.statSync(tmpPath).size, | ||
delOrginal: internals.options.delOrginal ? true : false, | ||
versions: imageVersions.length > 0 ? {} : undefined | ||
} | ||
const finish = () => { resolve(fileDetails) } | ||
const validate = await internals.validateAfterRecived({ | ||
path: tmpPath, | ||
size: fileDetails.size | ||
}); | ||
if (validate) { | ||
await internals.deleteFileFs(tmpPath); | ||
return reject(new Error(validate)); | ||
} | ||
mkdirp(internals.options.destination, (err, made) => { | ||
fs.rename(tmpPath, path, err => { | ||
if (!err) { | ||
generateVersions(); | ||
} else { | ||
const is = fs.createReadStream(tmpPath); | ||
const os = fs.createWriteStream(path); | ||
is.on('end', async err => { | ||
if (!err) { | ||
await internals.deleteFileFs(path); | ||
generateVersions(); | ||
} | ||
}); | ||
is.pipe(os); | ||
} | ||
}); | ||
}); | ||
const generateVersions = () => { | ||
if (internals.options.imageVersions === undefined) finish(); | ||
else { | ||
let counter = 0; | ||
imageVersions.forEach(version => { | ||
mkdirp(join(internals.options.destination, version), (err, made) => { | ||
const opts = internals.options.imageVersions[version]; | ||
imageMagick.resize({ | ||
width: opts.width, | ||
height: opts.height, | ||
srcPath: join(internals.options.destination, filename), | ||
dstPath: join(internals.options.destination, version, filename), | ||
customArgs: opts.imageArgs || ['-auto-orient'] | ||
}, async (err, stdout, stderr) => { | ||
if (err) throw err; | ||
counter++; | ||
fileDetails.versions[version] = { | ||
destination: join(internals.options.destination, version), | ||
urlDestination: join(internals.options.urlDestination, version), | ||
path: join(internals.options.destination, version, filename), | ||
url: join(internals.options.urlDestination, version, filename) | ||
} | ||
if (imageVersions.length === counter) { | ||
if (internals.options.delOrginal) await internals.deleteFileFs(path); | ||
finish(); | ||
} | ||
}); | ||
}); | ||
}); | ||
} | ||
} | ||
}) | ||
}) | ||
} | ||
internals.deleteFileFs = async (filePath) => { | ||
fs.unlinkSync(filePath); | ||
}; | ||
export function register(server, options, next) { | ||
internals.setOptions(options); | ||
server.expose('uploader', internals.uploader); | ||
server.expose('deleteFileFs', internals.deleteFileFs); | ||
next(); | ||
} | ||
exports.register.attributes = { | ||
name: 'hapi-darwin' | ||
}; |
{ | ||
"name": "hapi-darwin", | ||
"version": "1.0.2", | ||
"version": "1.1.0", | ||
"description": "simple image storage", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "lab -c -L", | ||
"test-cover": "lab -c -r html -o ./test/artifacts/coverage.html && open ./test/artifacts/coverage.html" | ||
"test": "lab -c -L -a code" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/tavousi/hapi-darwin" | ||
"url": "https://github.com/escommunity/hapi-darwin.git" | ||
}, | ||
"author": "Seyed Amirhossein Tavousi", | ||
"license": "MIT", | ||
"keywords": [ | ||
"hapi", | ||
"upload" | ||
], | ||
"bugs": { | ||
"url": "https://github.com/tavousi/hapi-darwin/issues" | ||
"url": "https://github.com/escommunity/hapi-darwin/issues" | ||
}, | ||
"homepage": "https://github.com/tavousi/hapi-darwin", | ||
"homepage": "https://github.com/escommunity/hapi-darwin", | ||
"license": "MIT", | ||
"engines": { | ||
"node": ">=4.0.0" | ||
"node": ">=8.0.0" | ||
}, | ||
"dependencies": { | ||
"globby": "^8.0.0", | ||
"mkdirp": "^0.5.0", | ||
"sharp": "^0.20.0" | ||
}, | ||
"devDependencies": { | ||
"hapi": "15.x.x", | ||
"code": "3.x.x", | ||
"lab": "11.x.x" | ||
}, | ||
"dependencies": { | ||
"file-type": "^7.4.0", | ||
"image-size": "^0.6.1", | ||
"imagemagick": "^0.1.3", | ||
"mkdirp": "^0.5.1", | ||
"read-chunk": "^2.1.0" | ||
"code": "^5.0.0", | ||
"del": "^3.0.0", | ||
"eslint-plugin-hapi": "^4.1.0", | ||
"hapi": "^17.0.0", | ||
"lab": "^15.0.0" | ||
} | ||
} |
200
README.md
# hapi-darwin | ||
image storage | ||
A Hapi plugin for image storage | ||
[](https://david-dm.org/tavousi/hapi-darwin) | ||
[](https://david-dm.org/tavousi/hapi-darwin?type=dev) | ||
[](https://travis-ci.org/tavousi/hapi-darwin) | ||
[](https://david-dm.org/ecmascriptforever/hapi-darwin) | ||
[](https://david-dm.org/ecmascriptforever/hapi-darwin?type=dev) | ||
[](https://travis-ci.org/ecmascriptforever/hapi-darwin) | ||
## Install | ||
```bash | ||
$ npm install hapi-darwin | ||
$ npm install @ecmacommunity/hapi-darwin | ||
``` | ||
## Register | ||
```js | ||
await server.register({ | ||
plugin: require('@ecmacommunity/hapi-darwin'), | ||
options: { | ||
// Any uploader method options | ||
dest: './path/to/destination', | ||
formats: ['jpeg', 'png'] | ||
} | ||
}); | ||
``` | ||
## Usage | ||
```js | ||
server.route({ | ||
method: 'POST', | ||
path: '/upload', | ||
config: { | ||
payload: { | ||
maxBytes: 1110.5 * 1024 * 1024, // 500KB | ||
output: 'stream', | ||
allow: 'multipart/form-data' // important | ||
}, | ||
cors: { | ||
origin: ['*'], | ||
credentials: true, | ||
additionalHeaders: ['content-type'] | ||
} | ||
}, | ||
handler: async function (request, reply) { | ||
'use strict'; | ||
try { | ||
const uploader = request.server.plugins['hapi-darwin'].uploader; | ||
server.route({ | ||
method: 'POST', | ||
path: '/path/to/endpoint', | ||
options: { | ||
payload: { | ||
allow: 'multipart/form-data', | ||
output: 'stream' | ||
} | ||
}, | ||
handler: async ({ payload }, h) => { | ||
const data = request.payload; | ||
const file = data['avatar']; | ||
const { uploader } = server.plugins['@ecmacommunity/hapi-darwin']; | ||
const fileName = `${Date.now()}-drwin`; | ||
try { | ||
return await uploader(payload.avatar, { names: 'avatar' }); | ||
} catch (err) { | ||
// ... | ||
} | ||
} | ||
}) | ||
``` | ||
const fileOptions = { | ||
name: fileName, | ||
destination: './public/storage/course' | ||
} | ||
## API | ||
const result = await uploader(file, fileOptions); | ||
### uploader(files, [options]) | ||
reply(result); | ||
Returns a Promise for `object` or `object[]` or `object[][]` with: | ||
} catch (err) { | ||
reply(Boom.badRequest(err.message, err)); | ||
} | ||
- `filename` (string) - corrected filename | ||
- `path` (string) - absolute path of uploaded version | ||
} | ||
}); | ||
``` | ||
#### files | ||
Type: `Readable` `Readable[]` | ||
## Config | ||
#### options | ||
Type: `object` | ||
##### dest | ||
Type: `string` | ||
Default: `./images` | ||
Destination directory. | ||
##### names | ||
Type: `string` `string[]` | ||
Default: `files.hapi.filename`. | ||
Name(s) of input files to be used. | ||
##### safeName | ||
Type: `boolean` | ||
Default: `true` | ||
Whether replace new file with older exist or generate a unique filename. | ||
##### formats | ||
Type: `string[]` | ||
Default: `['jpeg', 'png', 'gif', 'webp']` | ||
File types that are allowed (it don't check extension). | ||
##### maxFiles | ||
Type: `number` | ||
Default: `1` | ||
Maximum input files can be uploaded. | ||
##### minPixels | ||
Type: `number` | ||
Default: `1e2` | ||
Minimum pixels can be manipulated. | ||
##### maxPixels | ||
Type: `number` | ||
Default: `1e6` | ||
Maximum pixels can be manipulated. | ||
##### versions | ||
Type: `object[]` | ||
Default: `[]` | ||
Define `array` of version `object` with: | ||
- `width` (number) - pixels width the version image should be. Use `null` or `undefined` to auto-scale the width to match the height. | ||
- `height` (number) - pixels height the version image should be. Use `null` or `undefined` to auto-scale the height to match the width. | ||
- `enlargement` (boolean) - enlarge the output image if the input image width or height are already less than the required dimensions; default is false. | ||
- `suffix` (string) - suffix of version filename. | ||
Example: | ||
```js | ||
internals.options = Object.assign({ | ||
tmp: os.tmpdir(), | ||
name: undefined, | ||
filter: /\.(jpg|jpeg|png|gif)$/, | ||
multiple: false, | ||
safeName: true, | ||
delOrginal: false, // when using `imageVersions` | ||
maxFiles: 1, | ||
minFileSize: 0.001 * 1024 * 1024, // 10 KB | ||
maxFileSize: 1 * 1024 * 1024, // 1 MB | ||
minHeight: 10, // in pixels | ||
maxHeight: 10000, // in pixels | ||
minWidth: 10, // in pixels | ||
maxWidth: 10000, // in pixels | ||
destination: './public/storage/null', | ||
urlDestination: 'https://hapi-darwin/public/storage/null', | ||
imageVersions: { | ||
['thumbnail-720']: { | ||
width: 2 * 720, | ||
height: 720, | ||
imageArgs: ['-auto-orient'] | ||
}, | ||
['thumbnail-360']: { | ||
width: 2 * 360, | ||
height: 360, | ||
imageArgs: ['-auto-orient'] | ||
} | ||
}, | ||
// imageVersions: undefined | ||
}, internals.options, options); | ||
versions: [ | ||
{ width: 128, height: 128 }, | ||
{ width: 64, suffix: 'thumbnail' } | ||
] | ||
``` | ||
##### addOriginal | ||
Type: `boolean` | ||
Default: `false` | ||
Whether adding the original input file to the destination directory or not. | ||
## License | ||
MIT |
'use strict'; | ||
const Lab = require('lab'); | ||
const Code = require('code'); | ||
const Hapi = require('hapi'); | ||
const Plugin = require('..'); | ||
const { expect } = require('code'); | ||
const { describe, it } = exports.lab = require('lab').script(); | ||
const Plugin = require('../'); | ||
const lab = exports.lab = Lab.script(); | ||
describe('Plugin Registration', () => { | ||
it('should registers successfully and expose upload method', () => { | ||
lab.experiment('Plugin Registration', () => { | ||
const server = new Hapi.Server(); | ||
lab.test('it registers successfully', (done) => { | ||
expect(async () => await server.register(Plugin)).to.not.throws(); | ||
const server = new Hapi.Server(); | ||
server.register(Plugin, (err) => { | ||
const { uploader } = server.plugins[Plugin.name]; | ||
Code.expect(err).to.not.exist(); | ||
done(); | ||
}); | ||
expect(uploader).to.be.function(); | ||
expect(uploader()).to.rejects(); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
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
No contributors or author data
MaintenancePackage does not specify a list of contributors or an author in package.json.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
720593
3
14
319
161
5
3
1
+ Addedglobby@^8.0.0
+ Addedsharp@^0.20.0
+ Added@mrmlnc/readdir-enhanced@2.2.1(transitive)
+ Added@nodelib/fs.stat@1.1.3(transitive)
+ Addedansi-regex@2.1.1(transitive)
+ Addedaproba@1.2.0(transitive)
+ Addedare-we-there-yet@1.1.7(transitive)
+ Addedarr-diff@4.0.0(transitive)
+ Addedarr-flatten@1.1.0(transitive)
+ Addedarr-union@3.1.0(transitive)
+ Addedarray-union@1.0.2(transitive)
+ Addedarray-uniq@1.0.3(transitive)
+ Addedarray-unique@0.3.2(transitive)
+ Addedarrify@1.0.1(transitive)
+ Addedassign-symbols@1.0.0(transitive)
+ Addedatob@2.1.2(transitive)
+ Addedbalanced-match@1.0.2(transitive)
+ Addedbase@0.11.2(transitive)
+ Addedbl@1.2.3(transitive)
+ Addedbrace-expansion@1.1.11(transitive)
+ Addedbraces@2.3.2(transitive)
+ Addedbuffer-alloc@1.2.0(transitive)
+ Addedbuffer-alloc-unsafe@1.1.0(transitive)
+ Addedbuffer-fill@1.0.0(transitive)
+ Addedcache-base@1.0.1(transitive)
+ Addedcall-me-maybe@1.0.2(transitive)
+ Addedchownr@1.1.4(transitive)
+ Addedclass-utils@0.3.6(transitive)
+ Addedcode-point-at@1.1.0(transitive)
+ Addedcollection-visit@1.0.0(transitive)
+ Addedcolor@3.2.1(transitive)
+ Addedcolor-convert@1.9.3(transitive)
+ Addedcolor-name@1.1.3(transitive)
+ Addedcolor-string@1.9.1(transitive)
+ Addedcomponent-emitter@1.3.1(transitive)
+ Addedconcat-map@0.0.1(transitive)
+ Addedconsole-control-strings@1.1.0(transitive)
+ Addedcopy-descriptor@0.1.1(transitive)
+ Addedcore-util-is@1.0.3(transitive)
+ Addeddebug@2.6.9(transitive)
+ Addeddecode-uri-component@0.2.2(transitive)
+ Addeddecompress-response@3.3.0(transitive)
+ Addeddeep-extend@0.6.0(transitive)
+ Addeddefine-property@0.2.51.0.02.0.2(transitive)
+ Addeddelegates@1.0.0(transitive)
+ Addeddetect-libc@1.0.3(transitive)
+ Addeddir-glob@2.0.0(transitive)
+ Addedend-of-stream@1.4.4(transitive)
+ Addedexpand-brackets@2.1.4(transitive)
+ Addedexpand-template@1.1.1(transitive)
+ Addedextend-shallow@2.0.13.0.2(transitive)
+ Addedextglob@2.0.4(transitive)
+ Addedfast-glob@2.2.7(transitive)
+ Addedfill-range@4.0.0(transitive)
+ Addedfor-in@1.0.2(transitive)
+ Addedfragment-cache@0.2.1(transitive)
+ Addedfs-constants@1.0.0(transitive)
+ Addedfs-copy-file-sync@1.1.1(transitive)
+ Addedfs-minipass@1.2.7(transitive)
+ Addedfs.realpath@1.0.0(transitive)
+ Addedfunction-bind@1.1.2(transitive)
+ Addedgauge@2.7.4(transitive)
+ Addedget-value@2.0.6(transitive)
+ Addedgithub-from-package@0.0.0(transitive)
+ Addedglob@7.2.3(transitive)
+ Addedglob-parent@3.1.0(transitive)
+ Addedglob-to-regexp@0.3.0(transitive)
+ Addedglobby@8.0.2(transitive)
+ Addedhas-unicode@2.0.1(transitive)
+ Addedhas-value@0.3.11.0.0(transitive)
+ Addedhas-values@0.1.41.0.0(transitive)
+ Addedhasown@2.0.2(transitive)
+ Addedignore@3.3.10(transitive)
+ Addedinflight@1.0.6(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedini@1.3.8(transitive)
+ Addedis-accessor-descriptor@1.0.1(transitive)
+ Addedis-arrayish@0.3.2(transitive)
+ Addedis-buffer@1.1.6(transitive)
+ Addedis-data-descriptor@1.0.1(transitive)
+ Addedis-descriptor@0.1.71.0.3(transitive)
+ Addedis-extendable@0.1.11.0.1(transitive)
+ Addedis-extglob@2.1.1(transitive)
+ Addedis-fullwidth-code-point@1.0.0(transitive)
+ Addedis-glob@3.1.04.0.3(transitive)
+ Addedis-number@3.0.0(transitive)
+ Addedis-plain-object@2.0.4(transitive)
+ Addedis-windows@1.0.2(transitive)
+ Addedisarray@1.0.0(transitive)
+ Addedisobject@2.1.03.0.1(transitive)
+ Addedkind-of@3.2.24.0.06.0.3(transitive)
+ Addedmap-cache@0.2.2(transitive)
+ Addedmap-visit@1.0.0(transitive)
+ Addedmerge2@1.4.1(transitive)
+ Addedmicromatch@3.1.10(transitive)
+ Addedmimic-response@1.0.1(transitive)
+ Addedminimatch@3.1.2(transitive)
+ Addedminipass@2.9.0(transitive)
+ Addedminizlib@1.3.3(transitive)
+ Addedmixin-deep@1.3.2(transitive)
+ Addedms@2.0.0(transitive)
+ Addednan@2.22.2(transitive)
+ Addednanomatch@1.2.13(transitive)
+ Addednode-abi@2.30.1(transitive)
+ Addednoop-logger@0.1.1(transitive)
+ Addednpmlog@4.1.2(transitive)
+ Addednumber-is-nan@1.0.1(transitive)
+ Addedobject-assign@4.1.1(transitive)
+ Addedobject-copy@0.1.0(transitive)
+ Addedobject-visit@1.0.1(transitive)
+ Addedobject.pick@1.3.0(transitive)
+ Addedonce@1.4.0(transitive)
+ Addedos-homedir@1.0.2(transitive)
+ Addedpascalcase@0.1.1(transitive)
+ Addedpath-dirname@1.0.2(transitive)
+ Addedpath-is-absolute@1.0.1(transitive)
+ Addedpath-type@3.0.0(transitive)
+ Addedposix-character-classes@0.1.1(transitive)
+ Addedprebuild-install@4.0.0(transitive)
+ Addedprocess-nextick-args@2.0.1(transitive)
+ Addedpump@1.0.32.0.1(transitive)
+ Addedrc@1.2.8(transitive)
+ Addedreadable-stream@2.3.8(transitive)
+ Addedregex-not@1.0.2(transitive)
+ Addedrepeat-element@1.1.4(transitive)
+ Addedrepeat-string@1.6.1(transitive)
+ Addedresolve-url@0.2.1(transitive)
+ Addedret@0.1.15(transitive)
+ Addedsafe-buffer@5.1.2(transitive)
+ Addedsafe-regex@1.1.0(transitive)
+ Addedsemver@5.7.2(transitive)
+ Addedset-blocking@2.0.0(transitive)
+ Addedset-value@2.0.1(transitive)
+ Addedsharp@0.20.8(transitive)
+ Addedsignal-exit@3.0.7(transitive)
+ Addedsimple-concat@1.0.1(transitive)
+ Addedsimple-get@2.8.2(transitive)
+ Addedsimple-swizzle@0.2.2(transitive)
+ Addedslash@1.0.0(transitive)
+ Addedsnapdragon@0.8.2(transitive)
+ Addedsnapdragon-node@2.1.1(transitive)
+ Addedsnapdragon-util@3.0.1(transitive)
+ Addedsource-map@0.5.7(transitive)
+ Addedsource-map-resolve@0.5.3(transitive)
+ Addedsource-map-url@0.4.1(transitive)
+ Addedsplit-string@3.1.0(transitive)
+ Addedstatic-extend@0.1.2(transitive)
+ Addedstring-width@1.0.2(transitive)
+ Addedstring_decoder@1.1.1(transitive)
+ Addedstrip-ansi@3.0.1(transitive)
+ Addedstrip-json-comments@2.0.1(transitive)
+ Addedtar@4.4.19(transitive)
+ Addedtar-fs@1.16.4(transitive)
+ Addedtar-stream@1.6.2(transitive)
+ Addedto-buffer@1.1.1(transitive)
+ Addedto-object-path@0.3.0(transitive)
+ Addedto-regex@3.0.2(transitive)
+ Addedto-regex-range@2.1.1(transitive)
+ Addedtunnel-agent@0.6.0(transitive)
+ Addedunion-value@1.0.1(transitive)
+ Addedunset-value@1.0.0(transitive)
+ Addedurix@0.1.0(transitive)
+ Addeduse@3.1.1(transitive)
+ Addedutil-deprecate@1.0.2(transitive)
+ Addedwhich-pm-runs@1.1.0(transitive)
+ Addedwide-align@1.1.5(transitive)
+ Addedwrappy@1.0.2(transitive)
+ Addedxtend@4.0.2(transitive)
+ Addedyallist@3.1.1(transitive)
- Removedfile-type@^7.4.0
- Removedimage-size@^0.6.1
- Removedimagemagick@^0.1.3
- Removedread-chunk@^2.1.0
- Removedfile-type@7.7.1(transitive)
- Removedimage-size@0.6.3(transitive)
- Removedimagemagick@0.1.3(transitive)
- Removedread-chunk@2.1.0(transitive)
Updatedmkdirp@^0.5.0