Comparing version 1.0.0-rc.6 to 1.0.0-rc.7
{ | ||
"name": "fastboot", | ||
"version": "1.0.0-rc.6", | ||
"version": "1.0.0-rc.7", | ||
"description": "Library for rendering Ember apps in node.js", | ||
@@ -35,5 +35,4 @@ "main": "src/index.js", | ||
"express-cluster": "0.0.4", | ||
"glob": "^4.0.5", | ||
"minimist": "^1.2.0", | ||
"najax": "^1.0.1", | ||
"najax": "^1.0.2", | ||
"rsvp": "^3.0.16", | ||
@@ -40,0 +39,0 @@ "simple-dom": "^0.3.0", |
@@ -5,3 +5,2 @@ 'use strict'; | ||
const path = require('path'); | ||
const RSVP = require('rsvp'); | ||
const chalk = require('chalk'); | ||
@@ -72,3 +71,3 @@ | ||
let globals = { | ||
najax: najax, | ||
najax, | ||
FastBoot: { | ||
@@ -79,11 +78,6 @@ require: sandboxRequire, | ||
}; | ||
for (let key in sandboxGlobals) { | ||
if (sandboxGlobals.hasOwnProperty(key)) { | ||
globals[key] = sandboxGlobals[key]; | ||
} | ||
} | ||
return new sandboxClass({ | ||
globals: globals | ||
}); | ||
globals = Object.assign(globals, sandboxGlobals); | ||
return new sandboxClass({ globals }); | ||
} | ||
@@ -227,2 +221,6 @@ | ||
* | ||
* Ember apps can manually defer rendering in FastBoot mode if they're waiting | ||
* on something async the router doesn't know about. This function fetches | ||
* that promise for deferred rendering from the app. | ||
* | ||
* @param {string} path the URL path to render, like `/photos/1` | ||
@@ -248,6 +246,4 @@ * @param {Object} fastbootInfo An object holding per request info | ||
.then(() => instance.visit(path, bootOptions)) | ||
.then(() => waitForApp(instance)) | ||
.then(() => { | ||
return instance; | ||
}); | ||
.then(() => fastbootInfo.deferredPromise) | ||
.then(() => instance); | ||
} | ||
@@ -282,3 +278,3 @@ | ||
let disableShoebox = options.disableShoebox || false; | ||
let destroyAppInstanceInMs = options.destroyAppInstanceInMs; | ||
let destroyAppInstanceInMs = parseInt(options.destroyAppInstanceInMs, 10); | ||
@@ -302,10 +298,8 @@ let shouldRender = (options.shouldRender !== undefined) ? options.shouldRender : true; | ||
let destroyAppInstanceTimer; | ||
if (parseInt(destroyAppInstanceInMs, 10) > 0) { | ||
if (destroyAppInstanceInMs > 0) { | ||
// start a timer to destroy the appInstance forcefully in the given ms. | ||
// This is a failure mechanism so that node process doesn't get wedged if the `visit` never completes. | ||
destroyAppInstanceTimer = setTimeout(function() { | ||
if (instance && !result.instanceDestroyed) { | ||
result.instanceDestroyed = true; | ||
if (result._destroyAppInstance()) { | ||
result.error = new Error('App instance was forcefully destroyed in ' + destroyAppInstanceInMs + 'ms'); | ||
instance.destroy(); | ||
} | ||
@@ -315,7 +309,3 @@ }, destroyAppInstanceInMs); | ||
let instance; | ||
return this.visitRoute(path, fastbootInfo, bootOptions, result) | ||
.then(appInstance => { | ||
instance = appInstance; | ||
}) | ||
.then(() => { | ||
@@ -330,6 +320,3 @@ if (!disableShoebox) { | ||
.finally(() => { | ||
if (instance && !result.instanceDestroyed) { | ||
result.instanceDestroyed = true; | ||
instance.destroy(); | ||
if (result._destroyAppInstance()) { | ||
if (destroyAppInstanceTimer) { | ||
@@ -383,16 +370,14 @@ clearTimeout(destroyAppInstanceTimer); | ||
var appFiles = []; | ||
debug("reading array of app file paths from manifest"); | ||
manifest.appFiles.forEach(function(appFile) { | ||
appFiles.push(path.join(distPath, appFile)); | ||
var appFiles = manifest.appFiles.map(function(appFile) { | ||
return path.join(distPath, appFile); | ||
}); | ||
var vendorFiles = []; | ||
debug("reading array of vendor file paths from manifest"); | ||
manifest.vendorFiles.forEach(function(vendorFile) { | ||
vendorFiles.push(path.join(distPath, vendorFile)); | ||
var vendorFiles = manifest.vendorFiles.map(function(vendorFile) { | ||
return path.join(distPath, vendorFile); | ||
}); | ||
return { | ||
appFiles: appFiles, | ||
appFiles: appFiles, | ||
vendorFiles: vendorFiles, | ||
@@ -434,15 +419,2 @@ htmlFile: path.join(distPath, manifest.htmlFile), | ||
/* | ||
* Ember apps can manually defer rendering in FastBoot mode if they're waiting | ||
* on something async the router doesn't know about. This function fetches | ||
* that promise for deferred rendering from the app. | ||
*/ | ||
function waitForApp(instance) { | ||
let fastbootInfo = instance.lookup('info:-fastboot'); | ||
return fastbootInfo.deferredPromise.then(function() { | ||
return instance; | ||
}); | ||
} | ||
/* | ||
* Writes the shoebox into the DOM for the browser rendered app to consume. | ||
@@ -455,9 +427,10 @@ * Uses a script tag with custom type so that the browser will treat as plain | ||
*/ | ||
const hasOwnProperty = Object.prototype.hasOwnProperty; // jshint ignore:line | ||
function createShoebox(doc, fastbootInfo) { | ||
let shoebox = fastbootInfo.shoebox; | ||
if (!shoebox) { return RSVP.resolve(); } | ||
if (!shoebox) { return; } | ||
for (let key in shoebox) { | ||
if (!shoebox.hasOwnProperty(key)) { continue; } | ||
if (!hasOwnProperty.call(shoebox, key)) { continue; } // TODO: remove this later #144, ember-fastboot/ember-cli-fastboot/pull/417 | ||
let value = shoebox[key]; | ||
@@ -475,4 +448,2 @@ let textValue = JSON.stringify(value); | ||
} | ||
return RSVP.resolve(); | ||
} | ||
@@ -479,0 +450,0 @@ |
@@ -5,90 +5,93 @@ 'use strict'; | ||
// https://developer.mozilla.org/en-US/docs/Web/API/Headers | ||
function FastBootHeaders(headers) { | ||
headers = headers || {}; | ||
this.headers = {}; | ||
class FastBootHeaders { | ||
constructor(headers) { | ||
headers = headers || {}; | ||
this.headers = {}; | ||
for (var header in headers) { | ||
let value = headers[header]; | ||
for (var header in headers) { | ||
let value = headers[header]; | ||
// Express gives us either a string | ||
// or an array of strings if there are multiple values. | ||
// We want to support the Header spec | ||
// so we will coerce to an array always. | ||
if (typeof value === 'string') { | ||
value = [value]; | ||
// Express gives us either a string | ||
// or an array of strings if there are multiple values. | ||
// We want to support the Header spec | ||
// so we will coerce to an array always. | ||
if (typeof value === 'string') { | ||
value = [value]; | ||
} | ||
this.headers[header] = value; | ||
} | ||
} | ||
this.headers[header] = value; | ||
append(header, value) { | ||
let _header = header.toLowerCase(); | ||
if (!this.has(_header)) { | ||
this.headers[_header] = []; | ||
} | ||
this.headers[_header].push(value); | ||
} | ||
} | ||
FastBootHeaders.prototype.append = function(header, value) { | ||
header = header.toLowerCase(); | ||
if (!this.has(header)) { | ||
this.headers[header] = []; | ||
delete(header) { | ||
delete this.headers[header.toLowerCase()]; | ||
} | ||
this.headers[header].push(value); | ||
}; | ||
entries() { | ||
var entries = []; | ||
FastBootHeaders.prototype.delete = function(header) { | ||
delete this.headers[header.toLowerCase()]; | ||
}; | ||
for(var key in this.headers) { | ||
var values = this.headers[key]; | ||
for(var index = 0; index < values.length; ++index ) { | ||
entries.push([key, values[index]]); | ||
} | ||
} | ||
FastBootHeaders.prototype.entries = function() { | ||
var entries = []; | ||
return entries[Symbol.iterator](); | ||
} | ||
for(var key in this.headers) { | ||
var values = this.headers[key]; | ||
for(var index = 0; index < values.length; ++index ) { | ||
entries.push([key, values[index]]); | ||
} | ||
get(header) { | ||
return this.getAll(header)[0] || null; | ||
} | ||
return entries[Symbol.iterator](); | ||
}; | ||
getAll(header) { | ||
return this.headers[header.toLowerCase()] || []; | ||
} | ||
FastBootHeaders.prototype.get = function(header) { | ||
return this.getAll(header)[0] || null; | ||
}; | ||
has(header) { | ||
return this.headers[header.toLowerCase()] !== undefined; | ||
} | ||
FastBootHeaders.prototype.getAll = function(header) { | ||
return this.headers[header.toLowerCase()] || []; | ||
}; | ||
keys() { | ||
var entries = []; | ||
FastBootHeaders.prototype.has = function(header) { | ||
return this.headers[header.toLowerCase()] !== undefined; | ||
}; | ||
for(var key in this.headers) { | ||
var values = this.headers[key]; | ||
for(var index = 0; index < values.length; ++index ) { | ||
entries.push(key); | ||
} | ||
} | ||
FastBootHeaders.prototype.keys = function() { | ||
var entries = []; | ||
return entries[Symbol.iterator](); | ||
} | ||
for(var key in this.headers) { | ||
var values = this.headers[key]; | ||
for(var index = 0; index < values.length; ++index ) { | ||
entries.push(key); | ||
} | ||
set(header, value) { | ||
header = header.toLowerCase(); | ||
this.headers[header] = [value]; | ||
} | ||
return entries[Symbol.iterator](); | ||
}; | ||
values() { | ||
var entries = []; | ||
FastBootHeaders.prototype.set = function(header, value) { | ||
header = header.toLowerCase(); | ||
this.headers[header] = [value]; | ||
}; | ||
for(var key in this.headers) { | ||
var values = this.headers[key]; | ||
for(var index = 0; index < values.length; ++index ) { | ||
entries.push(values[index]); | ||
} | ||
} | ||
FastBootHeaders.prototype.values = function() { | ||
var entries = []; | ||
for(var key in this.headers) { | ||
var values = this.headers[key]; | ||
for(var index = 0; index < values.length; ++index ) { | ||
entries.push(values[index]); | ||
} | ||
return entries[Symbol.iterator](); | ||
} | ||
} | ||
return entries[Symbol.iterator](); | ||
}; | ||
module.exports = FastBootHeaders; |
'use strict'; | ||
var RSVP = require('rsvp'); | ||
var FastBootRequest = require('./fastboot-request'); | ||
var FastBootResponse = require('./fastboot-response'); | ||
const RSVP = require('rsvp'); | ||
const FastBootRequest = require('./fastboot-request'); | ||
const FastBootResponse = require('./fastboot-response'); | ||
@@ -18,31 +18,33 @@ /* | ||
*/ | ||
function FastBootInfo(request, response, options) { | ||
class FastBootInfo { | ||
constructor(request, response, options) { | ||
this.deferredPromise = RSVP.resolve(); | ||
let hostWhitelist = options.hostWhitelist; | ||
let metadata = options.metadata; | ||
if (request) { | ||
this.request = new FastBootRequest(request, hostWhitelist); | ||
} | ||
this.deferredPromise = RSVP.resolve(); | ||
let hostWhitelist = options.hostWhitelist; | ||
let metadata = options.metadata; | ||
if (request) { | ||
this.request = new FastBootRequest(request, hostWhitelist); | ||
this.response = new FastBootResponse(response || {}); | ||
this.metadata = metadata; | ||
} | ||
this.response = new FastBootResponse(response || {}); | ||
this.metadata = metadata; | ||
deferRendering(promise) { | ||
this.deferredPromise = this.deferredPromise.then(function() { | ||
return promise; | ||
}); | ||
} | ||
/* | ||
* Registers this FastBootInfo instance in the registry of an Ember | ||
* ApplicationInstance. It is configured to be injected into the FastBoot | ||
* service, ensuring it is available inside instance initializers. | ||
*/ | ||
register(instance) { | ||
instance.register('info:-fastboot', this, { instantiate: false }); | ||
instance.inject('service:fastboot', '_fastbootInfo', 'info:-fastboot'); | ||
} | ||
} | ||
FastBootInfo.prototype.deferRendering = function(promise) { | ||
this.deferredPromise = this.deferredPromise.then(function() { | ||
return promise; | ||
}); | ||
}; | ||
/* | ||
* Registers this FastBootInfo instance in the registry of an Ember | ||
* ApplicationInstance. It is configured to be injected into the FastBoot | ||
* service, ensuring it is available inside instance initializers. | ||
*/ | ||
FastBootInfo.prototype.register = function(instance) { | ||
instance.register('info:-fastboot', this, { instantiate: false }); | ||
instance.inject('service:fastboot', '_fastbootInfo', 'info:-fastboot'); | ||
}; | ||
module.exports = FastBootInfo; |
@@ -1,60 +0,62 @@ | ||
var cookie = require('cookie'); | ||
var FastBootHeaders = require('./fastboot-headers'); | ||
'use strict'; | ||
function FastBootRequest(request, hostWhitelist) { | ||
this.hostWhitelist = hostWhitelist; | ||
const cookie = require('cookie'); | ||
const FastBootHeaders = require('./fastboot-headers'); | ||
this.protocol = request.protocol; | ||
this.headers = new FastBootHeaders(request.headers); | ||
this.queryParams = request.query; | ||
this.path = request.url; | ||
this.method = request.method; | ||
this.body = request.body; | ||
class FastBootRequest { | ||
constructor(request, hostWhitelist) { | ||
this.hostWhitelist = hostWhitelist; | ||
this.cookies = this.extractCookies(request); | ||
} | ||
this.protocol = request.protocol; | ||
this.headers = new FastBootHeaders(request.headers); | ||
this.queryParams = request.query; | ||
this.path = request.url; | ||
this.method = request.method; | ||
this.body = request.body; | ||
FastBootRequest.prototype.host = function() { | ||
if (!this.hostWhitelist) { | ||
throw new Error('You must provide a hostWhitelist to retrieve the host'); | ||
this.cookies = this.extractCookies(request); | ||
} | ||
var host = this.headers.get('host'); | ||
host() { | ||
if (!this.hostWhitelist) { | ||
throw new Error('You must provide a hostWhitelist to retrieve the host'); | ||
} | ||
var matchFound = this.hostWhitelist.reduce(function(previous, currentEntry) { | ||
if (currentEntry[0] === '/' && | ||
currentEntry.slice(-1) === '/') { | ||
// RegExp as string | ||
var regexp = new RegExp(currentEntry.slice(1, -1)); | ||
var host = this.headers.get('host'); | ||
var matchFound = this.hostWhitelist.some(function(entry) { | ||
if (entry[0] === '/' && entry.slice(-1) === '/') { | ||
var regexp = new RegExp(entry.slice(1, -1)); | ||
return regexp.test(host); | ||
} else { | ||
return entry === host; | ||
} | ||
}); | ||
return previous || regexp.test(host); | ||
} else { | ||
return previous || currentEntry === host; | ||
if (!matchFound) { | ||
throw new Error(`The host header did not match a hostWhitelist entry. Host header: ${host}`); | ||
} | ||
}, false); | ||
if (!matchFound) { | ||
throw new Error(`The host header did not match a hostWhitelist entry. Host header: ${host}`); | ||
return host; | ||
} | ||
return host; | ||
}; | ||
extractCookies(request) { | ||
// If cookie-parser middleware has already parsed the cookies, | ||
// just use that. | ||
if (request.cookies) { | ||
return request.cookies; | ||
} | ||
FastBootRequest.prototype.extractCookies = function(request) { | ||
// If cookie-parser middleware has already parsed the cookies, | ||
// just use that. | ||
if (request.cookies) { | ||
return request.cookies; | ||
} | ||
// Otherwise, try to parse the cookies ourselves, if they exist. | ||
var cookies = request.headers.cookie; | ||
if (cookies) { | ||
return cookie.parse(cookies); | ||
} | ||
// Otherwise, try to parse the cookies ourselves, if they exist. | ||
var cookies = request.headers.cookie; | ||
if (cookies) { | ||
return cookie.parse(cookies); | ||
// Return an empty object instead of undefined if no cookies are present. | ||
return {}; | ||
} | ||
// Return an empty object instead of undefined if no cookies are present. | ||
return {}; | ||
}; | ||
} | ||
module.exports = FastBootRequest; |
@@ -1,8 +0,12 @@ | ||
var FastBootHeaders = require('./fastboot-headers'); | ||
'use strict'; | ||
function FastbootResponse(response) { | ||
this.headers = new FastBootHeaders(response._headers); | ||
this.statusCode = 200; | ||
const FastBootHeaders = require('./fastboot-headers'); | ||
class FastbootResponse { | ||
constructor(response) { | ||
this.headers = new FastBootHeaders(response._headers); | ||
this.statusCode = 200; | ||
} | ||
} | ||
module.exports = FastbootResponse; |
@@ -1,2 +0,2 @@ | ||
var sourceMapSupport = require('source-map-support'); | ||
const sourceMapSupport = require('source-map-support'); | ||
@@ -3,0 +3,0 @@ function prepareStackTrace(error, stack) { |
@@ -14,3 +14,3 @@ 'use strict'; | ||
this.instanceBooted = false; | ||
this.instanceDestroyed = false; | ||
this._instanceDestroyed = false; | ||
this._doc = options.doc; | ||
@@ -47,3 +47,3 @@ this._html = options.html; | ||
return Promise.resolve(insertIntoIndexHTML(this._html, this._head, this._body)); | ||
return insertIntoIndexHTML(this._html, this._head, this._body); | ||
} | ||
@@ -102,2 +102,11 @@ | ||
_destroyAppInstance() { | ||
if (this.instance && !this._instanceDestroyed) { | ||
this._instanceDestroyed = true; | ||
this.instance.destroy(); | ||
return true; | ||
} | ||
return false; | ||
} | ||
_finalizeHTML() { | ||
@@ -118,20 +127,32 @@ let head = this._doc.head; | ||
/** | ||
* `String.replace()` converts '$$' to '$', so we must escape each '$' as '$$'; | ||
* but because we’re using `String.replace()` to do it, we must use '$$$'! | ||
*/ | ||
function escapeForStringReplace(string) { | ||
return string.replace(/\$/g, '$$$'); | ||
function missingTag(tag) { | ||
return Promise.reject(new Error(`Fastboot was not able to find ${tag} in base HTML. It could not replace the contents.`)); | ||
} | ||
function insertIntoIndexHTML(html, head, body) { | ||
html = html.replace("<!-- EMBER_CLI_FASTBOOT_BODY -->", escapeForStringReplace(body)); | ||
if (!html) { return Promise.resolve(html); } | ||
let isBodyReplaced = false; | ||
let isHeadReplaced = false; | ||
if (head) { | ||
html = html.replace("<!-- EMBER_CLI_FASTBOOT_HEAD -->", escapeForStringReplace(head)); | ||
html = html.replace(/<\!-- EMBER_CLI_FASTBOOT_(HEAD|BODY) -->/g, function(match, tag) { | ||
if (tag === 'HEAD' && head && !isHeadReplaced) { | ||
isHeadReplaced = true; | ||
return head; | ||
} else if (tag === 'BODY' && body && !isBodyReplaced) { | ||
isBodyReplaced = true; | ||
return body; | ||
} | ||
return ''; | ||
}); | ||
if (head && !isHeadReplaced) { | ||
return missingTag('<!--EMBER_CLI_FASTBOOT_HEAD-->'); | ||
} | ||
if (body && !isBodyReplaced) { | ||
return missingTag('<!--EMBER_CLI_FASTBOOT_BODY-->'); | ||
} | ||
return html; | ||
return Promise.resolve(html); | ||
} | ||
module.exports = Result; |
@@ -1,50 +0,52 @@ | ||
var chalk = require('chalk'); | ||
'use strict'; | ||
function Sandbox() { | ||
} | ||
const chalk = require('chalk'); | ||
Sandbox.prototype.init = function(options) { | ||
this.globals = options.globals; | ||
this.sandbox = this.buildSandbox(); | ||
}; | ||
class Sandbox { | ||
Sandbox.prototype.buildSandbox = function() { | ||
var console = this.buildWrappedConsole(); | ||
var sourceMapSupport = require('./install-source-map-support'); | ||
var URL = require('url'); | ||
var globals = this.globals; | ||
constructor(options) { | ||
this.globals = options.globals; | ||
this.sandbox = this.buildSandbox(); | ||
} | ||
var sandbox = { | ||
sourceMapSupport: sourceMapSupport, | ||
console: console, | ||
setTimeout: setTimeout, | ||
clearTimeout: clearTimeout, | ||
URL: URL, | ||
buildSandbox() { | ||
var console = this.buildWrappedConsole(); | ||
var sourceMapSupport = require('./install-source-map-support'); | ||
var URL = require('url'); | ||
var globals = this.globals; | ||
// Convince jQuery not to assume it's in a browser | ||
module: { exports: {} } | ||
}; | ||
var sandbox = { | ||
sourceMapSupport: sourceMapSupport, | ||
console: console, | ||
setTimeout: setTimeout, | ||
clearTimeout: clearTimeout, | ||
URL: URL, | ||
for (var key in globals) { | ||
sandbox[key] = globals[key]; | ||
} | ||
// Convince jQuery not to assume it's in a browser | ||
module: { exports: {} } | ||
}; | ||
// Set the global as `window`. | ||
sandbox.window = sandbox; | ||
sandbox.window.self = sandbox; | ||
for (var key in globals) { | ||
sandbox[key] = globals[key]; | ||
} | ||
return sandbox; | ||
}; | ||
// Set the global as `window`. | ||
sandbox.window = sandbox; | ||
sandbox.window.self = sandbox; | ||
Sandbox.prototype.buildWrappedConsole = function() { | ||
var wrappedConsole = Object.create(console); | ||
wrappedConsole.error = function() { | ||
console.error.apply(console, Array.prototype.map.call(arguments, function(a) { | ||
return typeof a === 'string' ? chalk.red(a) : a; | ||
})); | ||
}; | ||
return sandbox; | ||
} | ||
return wrappedConsole; | ||
}; | ||
buildWrappedConsole() { | ||
var wrappedConsole = Object.create(console); | ||
wrappedConsole.error = function() { | ||
console.error.apply(console, Array.prototype.map.call(arguments, function(a) { | ||
return typeof a === 'string' ? chalk.red(a) : a; | ||
})); | ||
}; | ||
return wrappedConsole; | ||
} | ||
} | ||
module.exports = Sandbox; |
@@ -1,21 +0,23 @@ | ||
var vm = require('vm'); | ||
var Sandbox = require('./sandbox'); | ||
'use strict'; | ||
function VMSandbox(options) { | ||
this.init(options); | ||
vm.createContext(this.sandbox); | ||
} | ||
const vm = require('vm'); | ||
const Sandbox = require('./sandbox'); | ||
VMSandbox.prototype = Object.create(Sandbox.prototype); | ||
VMSandbox.prototype.constructor = Sandbox; | ||
class VMSandbox extends Sandbox { | ||
constructor(options) { | ||
super(options); | ||
vm.createContext(this.sandbox); | ||
} | ||
VMSandbox.prototype.eval = function(source, filePath) { | ||
var fileScript = new vm.Script(source, { filename: filePath }); | ||
fileScript.runInContext(this.sandbox); | ||
}; | ||
eval(source, filePath) { | ||
var fileScript = new vm.Script(source, { filename: filePath }); | ||
fileScript.runInContext(this.sandbox); | ||
} | ||
VMSandbox.prototype.run = function(cb) { | ||
return cb.call(this.sandbox, this.sandbox); | ||
}; | ||
run(cb) { | ||
return cb.call(this.sandbox, this.sandbox); | ||
} | ||
} | ||
module.exports = VMSandbox; |
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
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a 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
11
6
65415
18
898
1
- Removedglob@^4.0.5
- Removedbalanced-match@1.0.2(transitive)
- Removedbrace-expansion@1.1.11(transitive)
- Removedconcat-map@0.0.1(transitive)
- Removedglob@4.5.3(transitive)
- Removedinflight@1.0.6(transitive)
- Removedminimatch@2.0.10(transitive)
- Removedonce@1.4.0(transitive)
- Removedwrappy@1.0.2(transitive)
Updatednajax@^1.0.2