Socket
Socket
Sign inDemoInstall

agentkeepalive

Package Overview
Dependencies
Maintainers
1
Versions
49
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

agentkeepalive - npm Package Compare versions

Comparing version 2.2.0 to 3.0.0

9

History.md
3.0.0 / 2016-12-20
==================
* fix: emit agent socket close event
* test: add remove excess calls to removeSocket
* test: use egg-ci
* test: refactor test with eslint rules
* feat: merge _http_agent.js from 7.2.1
2.2.0 / 2016-06-26

@@ -3,0 +12,0 @@ ==================

2

index.js

@@ -0,2 +1,4 @@

'use strict';
module.exports = require('./lib/agent');
module.exports.HttpsAgent = require('./lib/https_agent');

232

lib/_http_agent.js

@@ -22,10 +22,10 @@ // Copyright Joyent, Inc. and other Node contributors.

// copy from https://github.com/nodejs/node/blob/v4.x/lib/_http_agent.js
// patch from https://github.com/nodejs/node/blob/v7.2.1/lib/_http_agent.js
'use strict';
var net = require('net');
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var debug = require('./utils').debug;
const net = require('net');
const util = require('util');
const EventEmitter = require('events');
const debug = util.debuglog('http');

@@ -64,9 +64,11 @@ // New Agent code.

self.keepAlive = self.options.keepAlive || false;
self.maxSockets = self.options.maxSockets || Agent.defaultMaxSockets;
self.maxFreeSockets = self.options.maxFreeSockets || 256;
// [patch start]
// free keep-alive socket timeout. By default free socket do not have a timeout.
// keepAliveTimeout should be rename to `freeSocketKeepAliveTimeout`
self.keepAliveTimeout = self.options.keepAliveTimeout || 0;
self.freeSocketKeepAliveTimeout = self.options.freeSocketKeepAliveTimeout || 0;
// working socket timeout. By default working socket do not have a timeout.
self.timeout = self.options.timeout || 0;
self.maxSockets = self.options.maxSockets || Agent.defaultMaxSockets;
self.maxFreeSockets = self.options.maxFreeSockets || 256;
// [patch end]

@@ -77,4 +79,7 @@ self.on('free', function(socket, options) {

if (!socket.destroyed &&
if (socket.writable &&
self.requests[name] && self.requests[name].length) {
// [patch start]
debug('continue handle next request');
// [patch end]
self.requests[name].shift().onSocket(socket);

@@ -85,3 +90,2 @@ if (self.requests[name].length === 0) {

}
debug('continue handle next request');
} else {

@@ -93,4 +97,4 @@ // If there are no pending requests, then put it in

req.shouldKeepAlive &&
!socket.destroyed &&
self.options.keepAlive) {
socket.writable &&
self.keepAlive) {
var freeSockets = self.freeSockets[name];

@@ -101,6 +105,4 @@ var freeLen = freeSockets ? freeSockets.length : 0;

count += self.sockets[name].length;
// console.log(count, freeLen, self.maxSockets, self.maxFreeSockets)
if (count > self.maxSockets || freeLen >= self.maxFreeSockets) {
// console.log('hit max sockets', count, freeLen, self.maxSockets, self.maxFreeSockets);
self.removeSocket(socket, options);
socket.destroy();

@@ -111,3 +113,3 @@ } else {

socket.setKeepAlive(true, self.keepAliveMsecs);
socket.unref && socket.unref();
socket.unref();
socket._httpMessage = null;

@@ -117,2 +119,3 @@ self.removeSocket(socket, options);

// [patch start]
// Add a default error handler to avoid Unhandled 'error' event throw on idle socket

@@ -124,8 +127,7 @@ // https://github.com/node-modules/agentkeepalive/issues/25

}
// set free keepalive timer
socket.setTimeout(self.keepAliveTimeout);
socket.setTimeout(self.freeSocketKeepAliveTimeout);
// [patch end]
}
} else {
self.removeSocket(socket, options);
socket.destroy();

@@ -140,2 +142,3 @@ }

// [patch start]
function freeSocketErrorListener(err) {

@@ -147,2 +150,3 @@ var socket = this;

}
// [patch end]

@@ -154,22 +158,23 @@ Agent.defaultMaxSockets = Infinity;

// Get the key for a given set of request options
Agent.prototype.getName = function(options) {
var name = '';
Agent.prototype.getName = function getName(options) {
var name = options.host || 'localhost';
if (options.host)
name += options.host;
else
name += 'localhost';
name += ':';
if (options.port)
name += options.port;
name += ':';
if (options.localAddress)
name += options.localAddress;
name += ':';
// Pacify parallel/test-http-agent-getname by only appending
// the ':' when options.family is set.
if (options.family === 4 || options.family === 6)
name += ':' + options.family;
return name;
};
Agent.prototype.addRequest = function(req, options) {
// Legacy API: addRequest(req, host, port, path)
Agent.prototype.addRequest = function addRequest(req, options) {
// Legacy API: addRequest(req, host, port, localAddress)
if (typeof options === 'string') {

@@ -179,3 +184,3 @@ options = {

port: arguments[2],
path: arguments[3]
localAddress: arguments[3]
};

@@ -187,2 +192,10 @@ }

if (!options.servername) {
options.servername = options.host;
const hostHeader = req.getHeader('host');
if (hostHeader) {
options.servername = hostHeader.replace(/:.*$/, '');
}
}
var name = this.getName(options);

@@ -201,6 +214,8 @@ if (!this.sockets[name]) {

// [patch start]
// remove free socket error event handler
socket.removeListener('error', freeSocketErrorListener);
// restart the default timer
socket.setTimeout(this.timeout);
// [patch end]

@@ -211,3 +226,3 @@ // don't leak

socket.ref && socket.ref();
socket.ref();
req.onSocket(socket);

@@ -218,3 +233,11 @@ this.sockets[name].push(socket);

// If we are under maxSockets create a new one.
req.onSocket(this.createSocket(req, options));
this.createSocket(req, options, function(err, newSocket) {
if (err) {
process.nextTick(function() {
req.emit('error', err);
});
return;
}
req.onSocket(newSocket);
});
} else {

@@ -230,3 +253,3 @@ debug('wait for socket');

Agent.prototype.createSocket = function(req, options) {
Agent.prototype.createSocket = function createSocket(req, options, cb) {
var self = this;

@@ -238,7 +261,5 @@ options = util._extend({}, options);

options.servername = options.host;
if (req) {
var hostHeader = req.getHeader('host');
if (hostHeader) {
options.servername = hostHeader.replace(/:.*$/, '');
}
const hostHeader = req.getHeader('host');
if (hostHeader) {
options.servername = hostHeader.replace(/:.*$/, '');
}

@@ -248,67 +269,81 @@ }

var name = self.getName(options);
options._agentKey = name;
debug('createConnection', name, options);
options.encoding = null;
var s = self.createConnection(options);
if (!self.sockets[name]) {
self.sockets[name] = [];
}
this.sockets[name].push(s);
debug('sockets', name, this.sockets[name].length);
var called = false;
const newSocket = self.createConnection(options, oncreate);
if (newSocket)
oncreate(null, newSocket);
function oncreate(err, s) {
if (called)
return;
called = true;
if (err)
return cb(err);
if (!self.sockets[name]) {
self.sockets[name] = [];
}
self.sockets[name].push(s);
debug('sockets', name, self.sockets[name].length);
function onFree() {
self.emit('free', s, options);
}
s.on('free', onFree);
function onFree() {
self.emit('free', s, options);
}
s.on('free', onFree);
function onClose(err) {
debug('CLIENT socket onClose');
// fix: socket.destroyed always be undefined on 0.10.x
if (typeof s.destroyed !== 'boolean') {
s.destroyed = true;
function onClose(err) {
debug('CLIENT socket onClose');
// This is the only place where sockets get removed from the Agent.
// If you want to remove a socket from the pool, just close it.
// All socket errors end in a close event anyway.
self.removeSocket(s, options);
// [patch start]
self.emit('close');
// [patch end]
}
s.on('close', onClose);
// This is the only place where sockets get removed from the Agent.
// If you want to remove a socket from the pool, just close it.
// All socket errors end in a close event anyway.
self.removeSocket(s, options);
self.emit('close');
}
s.on('close', onClose);
// [patch start]
// start socket timeout handler
function onTimeout() {
debug('CLIENT socket onTimeout');
s.destroy();
// Remove it from freeSockets immediately to prevent new requests from being sent through this socket.
self.removeSocket(s, options);
self.emit('timeout');
}
s.on('timeout', onTimeout);
// set the default timer
s.setTimeout(self.timeout);
// [patch end]
function onTimeout() {
debug('CLIENT socket onTimeout');
s.destroy();
// Remove it from freeSockets immediately to prevent new requests from being sent through this socket.
self.removeSocket(s, options);
self.emit('timeout');
}
s.on('timeout', onTimeout);
// set the default timer
s.setTimeout(self.timeout);
function onRemove() {
// We need this function for cases like HTTP 'upgrade'
// (defined by WebSockets) where we need to remove a socket from the
// pool because it'll be locked up indefinitely
debug('CLIENT socket onRemove');
self.removeSocket(s, options);
s.removeListener('close', onClose);
s.removeListener('free', onFree);
s.removeListener('agentRemove', onRemove);
function onRemove() {
// We need this function for cases like HTTP 'upgrade'
// (defined by WebSockets) where we need to remove a socket from the
// pool because it'll be locked up indefinitely
debug('CLIENT socket onRemove');
self.removeSocket(s, options);
s.removeListener('close', onClose);
s.removeListener('free', onFree);
s.removeListener('agentRemove', onRemove);
// remove timer
s.setTimeout(0, onTimeout);
// [patch start]
// remove socket timeout handler
s.setTimeout(0, onTimeout);
// [patch end]
}
s.on('agentRemove', onRemove);
cb(null, s);
}
s.on('agentRemove', onRemove);
return s;
};
Agent.prototype.removeSocket = function(s, options) {
var freeLen, sockLen;
Agent.prototype.removeSocket = function removeSocket(s, options) {
var name = this.getName(options);
debug('removeSocket', name, 'destroyed:', s.destroyed);
debug('removeSocket', name, 'writable:', s.writable);
var sets = [this.sockets];
// If the socket was destroyed, remove it from the free buffers too.
if (s.destroyed)
if (!s.writable)
sets.push(this.freeSockets);

@@ -318,2 +353,3 @@

var sockets = sets[sk];
if (sockets[name]) {

@@ -330,4 +366,6 @@ var index = sockets[name].indexOf(s);

freeLen = this.freeSockets[name] ? this.freeSockets[name].length : 0;
sockLen = freeLen + this.sockets[name] ? this.sockets[name].length : 0;
// [patch start]
var freeLen = this.freeSockets[name] ? this.freeSockets[name].length : 0;
var sockLen = freeLen + this.sockets[name] ? this.sockets[name].length : 0;
// [patch end]

@@ -338,7 +376,15 @@ if (this.requests[name] && this.requests[name].length && sockLen < this.maxSockets) {

// If we have pending requests and a socket gets closed make a new one
this.createSocket(req, options).emit('free');
this.createSocket(req, options, function(err, newSocket) {
if (err) {
process.nextTick(function() {
req.emit('error', err);
});
return;
}
newSocket.emit('free');
});
}
};
Agent.prototype.destroy = function() {
Agent.prototype.destroy = function destroy() {
var sets = [this.freeSockets, this.sockets];

@@ -345,0 +391,0 @@ for (var s = 0; s < sets.length; s++) {

@@ -7,6 +7,2 @@ /**

* * https://github.com/joyent/node/blob/master/lib/_http_agent.js
*
* Copyright(c) 2012 - 2014 fengmk2 <fengmk2@gmail.com>
* Copyright(c) node-modules
* MIT Licensed
*/

@@ -16,81 +12,88 @@

/**
* Module dependencies.
*/
const OriginalAgent = require('./_http_agent').Agent;
var https = require('https');
var utils = require('./utils');
var OriginalAgent = require('./_http_agent').Agent;
var OriginalHttpsAgent = https.Agent;
class Agent extends OriginalAgent {
constructor(options) {
options = options || {};
options.keepAlive = options.keepAlive !== false;
// default is keep-alive and 15s free socket timeout
if (options.freeSocketKeepAliveTimeout === undefined) {
options.freeSocketKeepAliveTimeout = 15000;
}
// Legacy API: keepAliveTimeout should be rename to `freeSocketKeepAliveTimeout`
if (options.keepAliveTimeout) {
options.freeSocketKeepAliveTimeout = options.keepAliveTimeout;
}
module.exports = Agent;
// Sets the socket to timeout after timeout milliseconds of inactivity on the socket.
// By default is double free socket keepalive timeout.
if (options.timeout === undefined) {
options.timeout = options.freeSocketKeepAliveTimeout * 2;
// make sure socket default inactivity timeout >= 30000
if (options.timeout < 30000) {
options.timeout = 30000;
}
}
function Agent(options) {
if (!(this instanceof Agent)) {
return new Agent(options);
super(options);
this.createSocketCount = 0;
this.createSocketErrorCount = 0;
this.closeSocketCount = 0;
// socket error event count
this.errorSocketCount = 0;
this.requestCount = 0;
this.timeoutSocketCount = 0;
this.on('free', s => {
this.requestCount++;
// last enter free queue timestamp
s.lastFreeTime = Date.now();
});
this.on('timeout', () => {
this.timeoutSocketCount++;
});
this.on('close', () => {
this.closeSocketCount++;
});
this.on('error', () => {
this.errorSocketCount++;
});
}
options = options || {};
options.keepAlive = options.keepAlive !== false;
// default is keep-alive and 15s free socket timeout
if (options.keepAliveTimeout === undefined) {
options.keepAliveTimeout = 15000;
createSocket(req, options, cb) {
super.createSocket(req, options, (err, socket) => {
if (err) {
this.createSocketErrorCount++;
return cb(err);
}
if (this.keepAlive) {
// Disable Nagle's algorithm: http://blog.caustik.com/2012/04/08/scaling-node-js-to-100k-concurrent-connections/
// https://fengmk2.com/benchmark/nagle-algorithm-delayed-ack-mock.html
socket.setNoDelay(true);
}
this.createSocketCount++;
cb(null, socket);
});
}
// default timeout is double keepalive timeout
if (options.timeout === undefined) {
options.timeout = options.keepAliveTimeout * 2;
getCurrentStatus() {
return {
createSocketCount: this.createSocketCount,
createSocketErrorCount: this.createSocketErrorCount,
closeSocketCount: this.closeSocketCount,
errorSocketCount: this.errorSocketCount,
timeoutSocketCount: this.timeoutSocketCount,
requestCount: this.requestCount,
freeSockets: inspect(this.freeSockets),
sockets: inspect(this.sockets),
requests: inspect(this.requests),
};
}
OriginalAgent.call(this, options);
var self = this;
self.createSocketCount = 0;
self.closeSocketCount = 0;
// socket error event count
self.errorSocketCount = 0;
self.requestCount = 0;
self.timeoutSocketCount = 0;
self.on('free', function () {
self.requestCount++;
});
self.on('timeout', function () {
self.timeoutSocketCount++;
});
self.on('close', function () {
self.closeSocketCount++;
});
self.on('error', function () {
self.errorSocketCount++;
});
}
utils.inherits(Agent, OriginalAgent);
module.exports = Agent;
Agent.prototype.createSocket = function (req, options) {
var socket = OriginalAgent.prototype.createSocket.call(this, req, options);
if (this.keepAlive) {
// Disable Nagle's algorithm: http://blog.caustik.com/2012/04/08/scaling-node-js-to-100k-concurrent-connections/
// http://fengmk2.com/benchmark/nagle-algorithm-delayed-ack-mock.html
socket.setNoDelay(true);
}
this.createSocketCount++;
return socket;
};
Agent.prototype.getCurrentStatus = function () {
return {
createSocketCount: this.createSocketCount,
closeSocketCount: this.closeSocketCount,
errorSocketCount: this.errorSocketCount,
timeoutSocketCount: this.timeoutSocketCount,
requestCount: this.requestCount,
freeSockets: inspect(this.freeSockets),
sockets: inspect(this.sockets),
requests: inspect(this.requests)
};
};
function inspect(obj) {
var res = {};
for (var key in obj) {
const res = {};
for (const key in obj) {
res[key] = obj[key].length;

@@ -97,0 +100,0 @@ }

/**
* Https Agent base on custom http agent
*
* Copyright(c) node-modules and other contributors.
* MIT Licensed
*
* Authors:
* fengmk2 <m@fengmk2.com> (http://fengmk2.com)
*/

@@ -13,84 +7,37 @@

/**
* Module dependencies.
*/
const https = require('https');
const HttpAgent = require('./agent');
const OriginalHttpsAgent = https.Agent;
var https = require('https');
var utils = require('./utils');
var HttpAgent = require('./agent');
var OriginalHttpsAgent = https.Agent;
class HttpsAgent extends HttpAgent {
constructor(options) {
super(options);
var HttpsAgent;
if (utils.isNode10) {
// node v0.10
HttpsAgent = function HttpsAgent(options) {
HttpAgent.call(this, options);
this.defaultPort = 443;
this.protocol = 'https:';
};
utils.inherits(HttpsAgent, HttpAgent);
HttpsAgent.prototype.createConnection = https.globalAgent.createConnection;
HttpsAgent.prototype.getName = function(options) {
var name = HttpAgent.prototype.getName.call(this, options);
name += ':';
if (options.ca)
name += options.ca;
name += ':';
if (options.cert)
name += options.cert;
name += ':';
if (options.ciphers)
name += options.ciphers;
name += ':';
if (options.key)
name += options.key;
name += ':';
if (options.pfx)
name += options.pfx;
name += ':';
if (options.rejectUnauthorized !== undefined)
name += options.rejectUnauthorized;
return name;
};
} else {
HttpsAgent = function HttpsAgent(options) {
HttpAgent.call(this, options);
this.defaultPort = 443;
this.protocol = 'https:';
this.maxCachedSessions = this.options.maxCachedSessions;
if (this.maxCachedSessions === undefined)
if (this.maxCachedSessions === undefined) {
this.maxCachedSessions = 100;
}
this._sessionCache = {
map: {},
list: []
list: [],
};
};
}
}
utils.inherits(HttpsAgent, HttpAgent);
[
'createConnection',
'getName',
'_getSession',
'_cacheSession',
// https://github.com/nodejs/node/pull/4982
'_evictSession',
].forEach(function(method) {
if (typeof OriginalHttpsAgent.prototype[method] === 'function') {
HttpsAgent.prototype[method] = OriginalHttpsAgent.prototype[method];
}
});
[
'createConnection',
'getName',
'_getSession',
'_cacheSession',
// https://github.com/nodejs/node/pull/4982
'_evictSession',
].forEach(function(method) {
if (typeof OriginalHttpsAgent.prototype[method] === 'function') {
HttpsAgent.prototype[method] = OriginalHttpsAgent.prototype[method];
}
});
}
module.exports = HttpsAgent;
{
"name": "agentkeepalive",
"version": "2.2.0",
"version": "3.0.0",
"description": "Missing keepalive http.Agent",

@@ -13,7 +13,6 @@ "main": "index.js",

"scripts": {
"test": "mocha -R spec -t 5000 -r should-http test/*.test.js",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- -t 5000 -r should-http test/*.test.js",
"ci": "npm run lint && npm run test-cov",
"lint": "jshint .",
"codecov": "npm i codecov && codecov"
"test": "egg-bin test",
"cov": "egg-bin cov",
"ci": "npm run lint && npm run cov",
"lint": "eslint lib test index.js"
},

@@ -36,14 +35,16 @@ "repository": {

"devDependencies": {
"istanbul": "*",
"mocha": "*",
"pedding": "1",
"should": "4",
"should-http": "~0.0.2",
"jshint": "^2.9.1"
"egg-bin": "^1.9.1",
"egg-ci": "^1.1.0",
"eslint": "^3.12.2",
"eslint-config-egg": "^3.2.0",
"pedding": "1"
},
"engines": {
"node": ">= 0.10.0"
"node": ">= 4.0.0"
},
"author": "fengmk2 <fengmk2@gmail.com> (http://fengmk2.com)",
"ci": {
"version": "4.3.2, 4, 6, 7"
},
"author": "fengmk2 <fengmk2@gmail.com> (https://fengmk2.com)",
"license": "MIT"
}

@@ -28,2 +28,9 @@ # agentkeepalive

## What's different from original `http.Agent`?
- `keepAlive=true` by default
- Disable Nagle's algorithm: `socket.setNoDelay(true)`
- Add free socket timeout: avoid long time inactivity socket leak in the free-sockets queue.
- Add active socket timeout: avoid long time inactivity socket leak in the active-sockets queue.
## Install

@@ -40,8 +47,8 @@

* `keepAlive` {Boolean} Keep sockets around in a pool to be used by
other requests in the future. Default = `true`
other requests in the future. Default = `true`.
* `keepAliveMsecs` {Number} When using HTTP KeepAlive, how often
to send TCP KeepAlive packets over sockets being kept alive.
Default = `1000`. Only relevant if `keepAlive` is set to `true`.
* `keepAliveTimeout`: {Number} Sets the free socket to timeout
after `keepAliveTimeout` milliseconds of inactivity on the free socket.
* `freeSocketKeepAliveTimeout`: {Number} Sets the free socket to timeout
after `freeSocketKeepAliveTimeout` milliseconds of inactivity on the free socket.
Default is `15000`.

@@ -51,3 +58,3 @@ Only relevant if `keepAlive` is set to `true`.

after `timeout` milliseconds of inactivity on the working socket.
Default is `keepAliveTimeout * 2`.
Default is `freeSocketKeepAliveTimeout * 2`.
* `maxSockets` {Number} Maximum number of sockets to allow per

@@ -62,13 +69,13 @@ host. Default = `Infinity`.

```js
var http = require('http');
var Agent = require('agentkeepalive');
const http = require('http');
const Agent = require('agentkeepalive');
var keepaliveAgent = new Agent({
const keepaliveAgent = new Agent({
maxSockets: 100,
maxFreeSockets: 10,
timeout: 60000,
keepAliveTimeout: 30000 // free socket keepalive for 30 seconds
freeSocketKeepAliveTimeout: 30000, // free socket keepalive for 30 seconds
});
var options = {
const options = {
host: 'cnodejs.org',

@@ -78,6 +85,6 @@ port: 80,

method: 'GET',
agent: keepaliveAgent
agent: keepaliveAgent,
};
var req = http.request(options, function (res) {
const req = http.request(options, res => {
console.log('STATUS: ' + res.statusCode);

@@ -90,4 +97,3 @@ console.log('HEADERS: ' + JSON.stringify(res.headers));

});
req.on('error', function (e) {
req.on('error', e => {
console.log('problem with request: ' + e.message);

@@ -97,5 +103,4 @@ });

setTimeout(function () {
console.log('keep alive sockets:');
console.log(keepaliveAgent.unusedSockets);
setTimeout(() => {
console.log('agent status: %j', keepaliveAgent.getCurrentStatus());
}, 2000);

@@ -115,4 +120,4 @@

requestCount: 5,
freeSockets: { 'localhost:57479::': 3 },
sockets: { 'localhost:57479::': 5 },
freeSockets: { 'localhost:57479:': 3 },
sockets: { 'localhost:57479:': 5 },
requests: {}

@@ -125,8 +130,8 @@ }

```js
var https = require('https');
var HttpsAgent = require('agentkeepalive').HttpsAgent;
const https = require('https');
const HttpsAgent = require('agentkeepalive').HttpsAgent;
var keepaliveAgent = new HttpsAgent();
const keepaliveAgent = new HttpsAgent();
// https://www.google.com/search?q=nodejs&sugexp=chrome,mod=12&sourceid=chrome&ie=UTF-8
var options = {
const options = {
host: 'www.google.com',

@@ -136,10 +141,10 @@ port: 443,

method: 'GET',
agent: keepaliveAgent
agent: keepaliveAgent,
};
var req = https.request(options, function (res) {
const req = https.request(options, res => {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
res.on('data', chunk => {
console.log('BODY: ' + chunk);

@@ -149,3 +154,3 @@ });

req.on('error', function (e) {
req.on('error', e => {
console.log('problem with request: ' + e.message);

@@ -155,6 +160,4 @@ });

setTimeout(function () {
console.log('keep alive sockets:');
console.log(keepaliveAgent.unusedSockets);
process.exit();
setTimeout(() => {
console.log('agent status: %j', keepaliveAgent.getCurrentStatus());
}, 2000);

@@ -161,0 +164,0 @@ ```

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc