engine.io
Advanced tools
Comparing version
0.3.0 / 2012-10-04 | ||
================== | ||
* socket: `writeBuffer` now gets sliced, and is recoverable after `close` [afshinm] | ||
* server: expect ping from client and send interval with handshake [cadorn] | ||
* polling-jsonp: prevent client breakage with utf8 whitespace | ||
* socket: fix `flush` and `drain` events | ||
* socket: add `send` callback [afshinm] | ||
* transport: avoid unhandled error events for stale transports | ||
* README: documentation improvements [EugenDueck] | ||
0.2.2 / 2012-08-26 | ||
@@ -3,0 +14,0 @@ ================== |
@@ -1,2 +0,1 @@ | ||
/** | ||
@@ -6,2 +5,2 @@ * Exposes the client parser to avoid code repetition. | ||
module.exports = require('engine.io-client').parser; | ||
module.exports = require('engine.io-client/lib/parser'); |
@@ -10,2 +10,3 @@ | ||
, crypto = require('crypto') | ||
, base64id = require('base64id') | ||
, transports = require('./transports') | ||
@@ -115,18 +116,2 @@ , EventEmitter = require('events').EventEmitter | ||
/** | ||
* Generates an id. | ||
* | ||
* @api private | ||
*/ | ||
Server.prototype.id = function(){ | ||
var rand = new Buffer(15); | ||
this.sequenceNumber = (this.sequenceNumber + 1) | 0; | ||
rand.writeInt32BE(this.sequenceNumber, 11); | ||
crypto.randomBytes(12).copy(rand); | ||
var id = rand.toString('base64').replace(/\//g, '_').replace(/\+/g, '-'); | ||
if (this.clients[id]) return this.id(); | ||
return id; | ||
}; | ||
/** | ||
* Closes all clients. | ||
@@ -183,3 +168,3 @@ * | ||
Server.prototype.handshake = function(transport, req){ | ||
var id = this.id(); | ||
var id = base64id.generateId(); | ||
@@ -186,0 +171,0 @@ debug('handshaking client "%d"', id); |
@@ -26,2 +26,3 @@ /** | ||
this.writeBuffer = []; | ||
this.packetsFn = []; | ||
@@ -62,2 +63,3 @@ this.setTransport(transport); | ||
, upgrades: this.getAvailableUpgrades() | ||
, pingInterval: this.server.pingInterval | ||
, pingTimeout: this.server.pingTimeout | ||
@@ -67,3 +69,3 @@ })); | ||
this.emit('open'); | ||
this.ping(); | ||
this.setPingTimeout(); | ||
}; | ||
@@ -81,6 +83,8 @@ | ||
switch (packet.type) { | ||
case 'pong': | ||
debug('got pong'); | ||
case 'ping': | ||
debug('got ping'); | ||
this.sendPacket('pong'); | ||
this.emit('heartbeat'); | ||
this.ping(); | ||
this.setPingTimeout(); | ||
break; | ||
@@ -107,3 +111,3 @@ | ||
/** | ||
* Pings a client. | ||
* Sets and resets ping timeout timer based on client pings. | ||
* | ||
@@ -113,14 +117,8 @@ * @api private | ||
Socket.prototype.ping = function () { | ||
clearTimeout(this.pingIntervalTimer); | ||
Socket.prototype.setPingTimeout = function () { | ||
var self = this; | ||
this.pingIntervalTimer = setTimeout(function () { | ||
debug('writing ping packet - expected pong in %sms', self.server.pingTimeout); | ||
self.sendPacket('ping'); | ||
clearTimeout(self.pingTimeoutTimer); | ||
self.pingTimeoutTimer = setTimeout(function () { | ||
self.onClose('ping timeout'); | ||
}, self.server.pingTimeout); | ||
}, this.server.pingInterval); | ||
clearTimeout(self.pingTimeoutTimer); | ||
self.pingTimeoutTimer = setTimeout(function () { | ||
self.onClose('ping timeout'); | ||
}, self.server.pingInterval + self.server.pingTimeout); | ||
}; | ||
@@ -141,2 +139,4 @@ | ||
this.transport.once('close', this.onClose.bind(this, 'transport close')); | ||
//this function will manage packet events (also message callbacks) | ||
this.setupSendCallback(); | ||
}; | ||
@@ -183,3 +183,3 @@ | ||
self.setTransport(transport); | ||
self.ping(); | ||
self.setPingTimeout(); | ||
self.flush(); | ||
@@ -218,2 +218,3 @@ clearTimeout(upgradeTimeout); | ||
if ('closed' != this.readyState) { | ||
this.packetsFn = []; | ||
this.clearTransport(); | ||
@@ -226,5 +227,26 @@ this.readyState = 'closed'; | ||
/** | ||
* Setup and manage send callback | ||
* | ||
* @api private | ||
*/ | ||
Socket.prototype.setupSendCallback = function () { | ||
var self = this; | ||
//the message was sent successfully, execute the callback | ||
this.transport.on('drain', function() { | ||
if (self.packetsFn.length > 0) { | ||
var seqFn = self.packetsFn.splice(0,1)[0]; | ||
if ('function' == typeof seqFn) { | ||
debug('executing send callback'); | ||
seqFn(self.transport); | ||
} | ||
} | ||
}); | ||
}; | ||
/** | ||
* Sends a message packet. | ||
* | ||
* @param {String} message | ||
* @param {Function} callback | ||
* @return {Socket} for chaining | ||
@@ -234,4 +256,4 @@ * @api public | ||
Socket.prototype.send = function (data) { | ||
this.sendPacket('message', data); | ||
Socket.prototype.send = function (data, callback) { | ||
this.sendPacket('message', data, callback); | ||
return this; | ||
@@ -248,6 +270,10 @@ }; | ||
Socket.prototype.sendPacket = function (type, data) { | ||
Socket.prototype.sendPacket = function (type, data, callback) { | ||
if ('closing' != this.readyState) { | ||
debug('sending packet "%s" (%s)', type, data); | ||
this.writeBuffer.push({ type: type, data: data }); | ||
//add send callback to object | ||
if (callback) { | ||
this.packetsFn.push(callback); | ||
} | ||
this.flush(); | ||
@@ -254,0 +280,0 @@ } |
@@ -57,4 +57,11 @@ | ||
JSONP.prototype.doWrite = function (data) { | ||
data = this.head + JSON.stringify(data) + this.foot; | ||
// we must output valid javascript, not valid json | ||
// see: http://timelessrepo.com/json-isnt-a-javascript-subset | ||
var js = JSON.stringify(data) | ||
.replace(/\u2028/g, '\\u2028') | ||
.replace(/\u2029/g, '\\u2029'); | ||
// prepare response | ||
data = this.head + js + this.foot; | ||
// explicit UTF-8 is required for pages not served under utf | ||
@@ -61,0 +68,0 @@ var headers = { |
{ | ||
"name": "engine.io" | ||
, "version": "0.2.2" | ||
, "version": "0.3.0" | ||
, "description": "The realtime engine behind Socket.IO. Provides the foundation of a bidirectional connection between client and server" | ||
@@ -8,8 +8,10 @@ , "main": "./lib/engine.io" | ||
, "contributors": [ | ||
{ "name": "Eugen Dueck", "web": "https://github.com/EugenDueck" } | ||
{ "name": "Eugen Dueck", "web": "https://github.com/EugenDueck" }, | ||
{ "name": "Afshin Mehrabani", "web": "https://github.com/afshinm" } | ||
] | ||
, "dependencies": { | ||
"debug": "0.6.0" | ||
, "engine.io-client": "0.2.2" | ||
, "engine.io-client": "0.3.0" | ||
, "ws": "~0.4.21" | ||
, "base64id": "0.1.0" | ||
} | ||
@@ -16,0 +18,0 @@ , "devDependencies": { |
@@ -61,3 +61,3 @@ # Engine.IO: the realtime engine | ||
<script> | ||
var socket = new eio.Socket({ host: 'localhost', port: 80 }); | ||
var socket = new eio.Socket('ws://localhost/'); | ||
socket.on('open', function () { | ||
@@ -137,7 +137,5 @@ socket.on('message', function (data) { }); | ||
- **Options** | ||
- `path` (`String`) default prefix path (`/engine.io`) | ||
- `resource` (`String`): name of resource for this server (`default`). | ||
Setting a resource allows you to initialize multiple engine.io | ||
endpoints on the same host without them interfering, and without | ||
changing the `path` directly. | ||
endpoints on the same host without them interfering. | ||
- `policyFile` (`Boolean`): whether to handle policy file requests (`true`) | ||
@@ -253,2 +251,3 @@ - `destroyUpgrade` (`Boolean`): destroy unhandled upgrade requests (`true`) | ||
- `String`: a string or any object implementing `toString()`, with outgoing data | ||
- `Function`: optional, a callback executed when the message gets flushed out by the transport | ||
- **Returns** `Socket` for chaining | ||
@@ -269,2 +268,14 @@ - `close` | ||
## Debug / logging | ||
Engine.IO is powered by [debug](http://github.com/visionmedia/debug). | ||
In order to see all the debug output, run your app with the env variable | ||
`DEBUG` including the desired scope. | ||
To see the output from all of Engine.IO's debugging scopes you can use: | ||
``` | ||
DEBUG=engine* node myapp | ||
``` | ||
## Transports | ||
@@ -271,0 +282,0 @@ |
/** | ||
* Instrument. | ||
*/ | ||
var fs = require('fs'); | ||
if (process.env.DEBUG) { | ||
require.extensions['.js'] = function(mod, filename){ | ||
var js = fs.readFileSync(filename, 'utf8'); | ||
// Profiling support | ||
js = js.replace(/^ *\/\/ *(start|end): *([^\n]+)/gm, function(_, type, expr){ | ||
switch (type) { | ||
case 'start': return 'console.time(' + expr + ');'; | ||
case 'end': return 'console.timeEnd(' + expr + ');'; | ||
} | ||
}); | ||
// Debugging | ||
js = js.replace(/^ *\/\/ *debug: *([^\n,]+) *([^\n]+)?/gm, function(_, fmt, args){ | ||
fmt = fmt.replace(/"/g, '\\"'); | ||
return 'console.error(" client\033[90m ' + fmt + '\033[0m"' + (args || '') + ');'; | ||
}); | ||
js = js.replace(/^ *\/\/ *assert: ([^,]+) *, *([^\n]+)/gm, function(_, expr, msg){ | ||
return 'if (!(' + expr + ')) console.error(" client assert\033[31m %s. (%s)\033[0m", ' + msg + ', "' + expr + '");'; | ||
}); | ||
mod._compile(js, filename); | ||
}; | ||
} | ||
/** | ||
* Expose `eio` global. | ||
*/ | ||
eio = require('../index'); | ||
global.eio = require('../index'); | ||
@@ -44,3 +12,3 @@ /** | ||
eioc = require('engine.io-client'); | ||
global.eioc = require('engine.io-client'); | ||
@@ -51,3 +19,3 @@ /** | ||
request = require('superagent'); | ||
global.request = require('superagent'); | ||
@@ -58,3 +26,3 @@ /** | ||
expect = require('expect.js'); | ||
global.expect = require('expect.js'); | ||
@@ -65,3 +33,3 @@ /** | ||
listen = function (opts, fn) { | ||
global.listen = function (opts, fn) { | ||
if ('function' == typeof opts) { | ||
@@ -72,3 +40,3 @@ fn = opts; | ||
var e = eio.listen(null, opts, function () { | ||
var e = global.eio.listen(null, opts, function () { | ||
fn(e.httpServer.address().port); | ||
@@ -78,3 +46,3 @@ }); | ||
return e; | ||
} | ||
}; | ||
@@ -81,0 +49,0 @@ /** |
@@ -0,1 +1,2 @@ | ||
/*global eio,listen,request,expect*/ | ||
@@ -7,3 +8,3 @@ /** | ||
var net = require('net') | ||
, http = require('http') | ||
, http = require('http'); | ||
@@ -10,0 +11,0 @@ /** |
@@ -0,1 +1,2 @@ | ||
/*global eio,eioc,listen,request,expect*/ | ||
@@ -8,3 +9,3 @@ /** | ||
, parser = eio.parser | ||
, WebSocket = require('ws') | ||
, WebSocket = require('ws'); | ||
@@ -21,3 +22,3 @@ /** | ||
request.get('http://localhost:%d/engine.io/default/'.s(port)) | ||
.send({ transport: 'tobi' }) // no tobi transport - outrageous | ||
.query({ transport: 'tobi' }) // no tobi transport - outrageous | ||
.end(function (res) { | ||
@@ -34,3 +35,3 @@ expect(res.status).to.be(500); | ||
request.get('http://localhost:%d/engine.io/default/'.s(port)) | ||
.send({ transport: 'constructor' }) | ||
.query({ transport: 'constructor' }) | ||
.end(function (res) { | ||
@@ -46,3 +47,3 @@ expect(res.status).to.be(500); | ||
request.get('http://localhost:%d/engine.io/default/'.s(port)) | ||
.send({ transport: 'polling', sid: 'test' }) | ||
.query({ transport: 'polling', sid: 'test' }) | ||
.end(function (res) { | ||
@@ -60,3 +61,3 @@ expect(res.status).to.be(500); | ||
request.get('http://localhost:%d/engine.io/default/'.s(port)) | ||
.send({ transport: 'polling' }) | ||
.query({ transport: 'polling' }) | ||
.end(function (res) { | ||
@@ -74,3 +75,3 @@ // hack-obtain sid | ||
request.get('http://localhost:%d/engine.io/default/'.s(port)) | ||
.send({ transport: 'polling' }) | ||
.query({ transport: 'polling' }) | ||
.end(function (res) { | ||
@@ -87,3 +88,3 @@ var sid = res.text.match(/"sid":"([^"]+)"/)[1]; | ||
request.get('http://localhost:%d/engine.io/default/'.s(port)) | ||
.send({ transport: 'polling' }) | ||
.query({ transport: 'polling' }) | ||
.end(function (res) { | ||
@@ -219,3 +220,3 @@ expect(res.headers['set-cookie']).to.be(undefined); | ||
it('should trigger on server if the client does not pong', function (done) { | ||
var opts = { allowUpgrades: false, pingInterval: 5, pingTimeout: 5 } | ||
var opts = { allowUpgrades: false, pingInterval: 5, pingTimeout: 5 }; | ||
var engine = listen(opts, function (port) { | ||
@@ -234,3 +235,3 @@ var socket = new eioc.Socket('http://localhost:%d'.s(port)); | ||
it('should trigger on client if server does not meet ping timeout', function (done) { | ||
var opts = { allowUpgrades: false, pingTimeout: 10 }; | ||
var opts = { allowUpgrades: false, pingInterval: 5, pingTimeout: 5 }; | ||
var engine = listen(opts, function (port) { | ||
@@ -253,3 +254,3 @@ var socket = new eioc.Socket('ws://localhost:%d'.s(port)); | ||
var socket = new eioc.Socket('ws://localhost:%d'.s(port)) | ||
, total = 2 | ||
, total = 2; | ||
@@ -276,3 +277,3 @@ function onClose (reason, err) { | ||
var socket = new eioc.Socket('ws://localhost:%d'.s(port)) | ||
, total = 2 | ||
, total = 2; | ||
@@ -302,3 +303,3 @@ engine.on('connection', function (conn) { | ||
var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] }) | ||
, total = 2 | ||
, total = 2; | ||
@@ -327,3 +328,3 @@ engine.on('connection', function (conn) { | ||
var socket = new eioc.Socket('ws://localhost:%d'.s(port)) | ||
, total = 2 | ||
, total = 2; | ||
@@ -354,3 +355,3 @@ engine.on('connection', function (conn) { | ||
var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] }) | ||
, total = 2 | ||
, total = 2; | ||
@@ -390,7 +391,7 @@ engine.on('connection', function (conn) { | ||
it('should trigger if a poll request is ongoing and the underlying' | ||
+ ' socket closes, as in a browser tab close', function (done) { | ||
it('should trigger if a poll request is ongoing and the underlying' + | ||
' socket closes, as in a browser tab close', function (done) { | ||
var engine = listen({ allowUpgrades: false }, function (port) { | ||
var socket = new eioc.Socket('ws://localhost:%d'.s(port)) | ||
, serverSocket | ||
, serverSocket; | ||
@@ -436,3 +437,3 @@ engine.on('connection', function(socket){ | ||
return oldRequest.apply(this, arguments); | ||
} | ||
}; | ||
@@ -446,3 +447,3 @@ engine.on('connection', function(socket){ | ||
var socket = new eioc.Socket('ws://localhost:%d'.s(port)) | ||
var socket = new eioc.Socket('ws://localhost:%d'.s(port)); | ||
socket.on('open', function(){ | ||
@@ -458,2 +459,108 @@ socket.send('test'); | ||
}); | ||
it('should not trigger early with connection `ping timeout` after post handshake timeout', function (done) { | ||
// First timeout should trigger after `pingInterval + pingTimeout`, not just `pingTimeout`. | ||
var opts = { allowUpgrades: false, pingInterval: 300, pingTimeout: 100 }; | ||
var engine = listen(opts, function (port) { | ||
var socket = new eioc.Socket('ws://localhost:%d'.s(port)); | ||
var clientCloseReason = null; | ||
socket.on('handshake', function() { | ||
socket.onPacket = function(){}; | ||
}); | ||
socket.on('open', function () { | ||
socket.on('close', function (reason) { | ||
clientCloseReason = reason; | ||
}); | ||
}); | ||
setTimeout(function() { | ||
expect(clientCloseReason).to.be(null); | ||
done(); | ||
}, 200); | ||
}); | ||
}); | ||
it('should not trigger early with connection `ping timeout` after post ping timeout', function (done) { | ||
// Ping timeout should trigger after `pingInterval + pingTimeout`, not just `pingTimeout`. | ||
var opts = { allowUpgrades: false, pingInterval: 300, pingTimeout: 100 }; | ||
var engine = listen(opts, function (port) { | ||
var socket = new eioc.Socket('ws://localhost:%d'.s(port)); | ||
var clientCloseReason = null; | ||
engine.on('connection', function(conn){ | ||
conn.on('heartbeat', function() { | ||
conn.onPacket = function(){}; | ||
}); | ||
}); | ||
socket.on('open', function () { | ||
socket.on('close', function (reason) { | ||
clientCloseReason = reason; | ||
}); | ||
}); | ||
setTimeout(function() { | ||
expect(clientCloseReason).to.be(null); | ||
done(); | ||
}, 300); | ||
}); | ||
}); | ||
it('should trigger early with connection `transport close` after missing pong', function (done) { | ||
// Ping timeout should trigger after `pingInterval + pingTimeout`, not just `pingTimeout`. | ||
var opts = { allowUpgrades: false, pingInterval: 300, pingTimeout: 100 }; | ||
var engine = listen(opts, function (port) { | ||
var socket = new eioc.Socket('ws://localhost:%d'.s(port)); | ||
var clientCloseReason = null; | ||
socket.on('open', function () { | ||
socket.on('close', function (reason) { | ||
clientCloseReason = reason; | ||
}); | ||
}); | ||
engine.on('connection', function(conn){ | ||
conn.on('heartbeat', function() { | ||
setTimeout(function() { | ||
conn.close(); | ||
}, 20); | ||
setTimeout(function() { | ||
expect(clientCloseReason).to.be("transport close"); | ||
done(); | ||
}, 150); | ||
}); | ||
}); | ||
}); | ||
}); | ||
it('should trigger with connection `ping timeout` after `pingInterval + pingTimeout`', function (done) { | ||
var opts = { allowUpgrades: false, pingInterval: 30, pingTimeout: 10 }; | ||
var engine = listen(opts, function (port) { | ||
var socket = new eioc.Socket('ws://localhost:%d'.s(port)); | ||
var clientCloseReason = null; | ||
socket.on('open', function () { | ||
socket.on('close', function (reason) { | ||
clientCloseReason = reason; | ||
}); | ||
}); | ||
engine.on('connection', function(conn){ | ||
conn.once('heartbeat', function() { | ||
setTimeout(function() { | ||
socket.onPacket = function(){}; | ||
expect(clientCloseReason).to.be(null); | ||
}, 15); | ||
setTimeout(function() { | ||
expect(clientCloseReason).to.be(null); | ||
}, 35); | ||
setTimeout(function() { | ||
expect(clientCloseReason).to.be("ping timeout"); | ||
done(); | ||
}, 50); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
@@ -481,3 +588,3 @@ | ||
, expected = ['a', 'b', 'c'] | ||
, i = 0 | ||
, i = 0; | ||
@@ -556,3 +663,4 @@ engine.on('connection', function (conn) { | ||
, expected = ['a', 'b', 'c'] | ||
, i = 0 | ||
, i = 0; | ||
engine.on('connection', function (conn) { | ||
@@ -574,2 +682,3 @@ conn.send('a'); | ||
}); | ||
socket.on('open', function () { | ||
@@ -616,2 +725,146 @@ socket.on('message', function (msg) { | ||
describe('send', function() { | ||
describe('callback', function() { | ||
it('should execute when message sent (polling)', function (done) { | ||
var engine = listen({ allowUpgrades: false }, function (port) { | ||
var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['polling'] }); | ||
var i = 0; | ||
var j = 0; | ||
engine.on('connection', function (conn) { | ||
conn.send('a', function (transport) { | ||
i++; | ||
}); | ||
}); | ||
socket.on('open', function () { | ||
socket.on('message', function (msg) { | ||
j++; | ||
}); | ||
}); | ||
setTimeout(function() { | ||
expect(i).to.be(j); | ||
done(); | ||
}, 10); | ||
}); | ||
}); | ||
it('should execute when message sent (websocket)', function (done) { | ||
var engine = listen({ allowUpgrades: false }, function (port) { | ||
var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] }); | ||
var i = 0; | ||
var j = 0; | ||
engine.on('connection', function (conn) { | ||
conn.send('a', function (transport) { | ||
i++; | ||
}); | ||
}); | ||
socket.on('open', function () { | ||
socket.on('message', function (msg) { | ||
j++; | ||
}); | ||
}); | ||
setTimeout(function () { | ||
expect(i).to.be(j); | ||
done(); | ||
}, 10); | ||
}); | ||
}); | ||
it('should execute once for each send', function (done) { | ||
var engine = listen(function (port) { | ||
var socket = new eioc.Socket('ws://localhost:%d'.s(port)); | ||
var i = 0; | ||
var ic = 0; | ||
var j = 0; | ||
var jc = 0; | ||
engine.on('connection', function (conn) { | ||
conn.send('b', function (transport) { | ||
jc++; | ||
}); | ||
conn.send('a', function (transport) { | ||
ic++; | ||
}); | ||
}); | ||
socket.on('open', function () { | ||
socket.on('message', function (msg) { | ||
if (msg == 'a') { | ||
i++; | ||
} else if (msg == 'b') { | ||
j++; | ||
} | ||
}); | ||
}); | ||
setTimeout(function () { | ||
expect(i).to.be(ic); | ||
expect(j).to.be(jc); | ||
done(); | ||
}, 100); | ||
}); | ||
}); | ||
it('should execute in multipart packet', function (done) { | ||
var engine = listen(function (port) { | ||
var socket = new eioc.Socket('ws://localhost:%d'.s(port)); | ||
var i = 0; | ||
var j = 0; | ||
engine.on('connection', function (conn) { | ||
conn.send('b', function (transport) { | ||
i++; | ||
}); | ||
conn.send('a', function (transport) { | ||
i++; | ||
}); | ||
}); | ||
socket.on('open', function () { | ||
socket.on('message', function (msg) { | ||
j++; | ||
}); | ||
}); | ||
setTimeout(function () { | ||
expect(i).to.be(j); | ||
done(); | ||
}, 200); | ||
}); | ||
}); | ||
it('should clean callback references when socket gets closed with pending callbacks', function (done) { | ||
var engine = listen({ allowUpgrades: false }, function (port) { | ||
var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['polling'] }); | ||
engine.on('connection', function (conn) { | ||
socket.transport.on('pollComplete', function () { | ||
conn.send('a', function (transport) { | ||
done(new Error('Test invalidation')); | ||
}); | ||
if (!conn.writeBuffer.length) { | ||
done(new Error('Test invalidation')); | ||
} | ||
// force to close the socket when we have one or more packet(s) in buffer | ||
socket.close(); | ||
}); | ||
conn.on('close', function (reason) { | ||
expect(conn.packetsFn).to.be.empty(); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
describe('upgrade', function () { | ||
@@ -618,0 +871,0 @@ it('should upgrade', function (done) { |
Sorry, the diff of this file is not supported yet
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
89083
10.55%2318
9.91%499
2.25%5
-28.57%4
33.33%+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
Updated