Socket
Socket
Sign inDemoInstall

tcomb

Package Overview
Dependencies
Maintainers
1
Versions
74
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tcomb - npm Package Compare versions

Comparing version 2.4.1 to 2.5.0

9

CHANGELOG.md

@@ -15,2 +15,11 @@ # Changelog

## v2.5.0
- **New Feature**
- check if the type returned by a union dispatch function is correct, fix #136 (thanks @fcracker79)
- added `refinement` alias to `subtype` (which is deprecated), fix #140
- **Internal**
- optimisations: for identity types return early in production, fix #135 (thanks @fcracker79)
- exposed `getDefaultName` on combinator constructors
## v2.4.1

@@ -17,0 +26,0 @@

36

GUIDE.md

@@ -27,11 +27,11 @@ # Setup

* `t.String`: strings (short alias `t.Str`)
* `t.Number`: numbers (short alias `t.Num`)
* `t.Boolean`: booleans (short alias `t.Bool`)
* `t.Array`: arrays (short alias `t.Arr`)
* `t.Object`: plain objects (short alias `t.Obj`)
* `t.Function`: functions (short alias `t.Func`)
* `t.Error`: errors (short alias `t.Err`)
* `t.RegExp`: regular expressions (short alias `t.Re`)
* `t.Date`: dates (short alias `t.Dat`)
* `t.String`: strings (deprecated alias `t.Str`)
* `t.Number`: numbers (deprecated alias `t.Num`)
* `t.Boolean`: booleans (deprecated alias `t.Bool`)
* `t.Array`: arrays (deprecated alias `t.Arr`)
* `t.Object`: plain objects (deprecated alias `t.Obj`)
* `t.Function`: functions (deprecated alias `t.Func`)
* `t.Error`: errors (deprecated alias `t.Err`)
* `t.RegExp`: regular expressions (deprecated alias `t.Re`)
* `t.Date`: dates (deprecated alias `t.Dat`)

@@ -43,3 +43,3 @@ There are 2 additional irriducible types defined in tcomb:

* `t.Nil`: `null` or `undefined`
* `t.Any`: any type
* `t.Any`: any value

@@ -150,5 +150,5 @@ ## Type checking with the `is` function

## The subtype combinator
## The refinement combinator (deprecated alias `subtype`)
You can refine a type using the `subtype(type, predicate, name)` combinator where:
You can refine a type using the `refinement(type, predicate, name)` combinator where:

@@ -163,3 +163,3 @@ * `type` is a type already defined

// defines a type representing positive numbers
var Positive = t.subtype(t.Number, (n) => n >= 0, 'Positive');
var Positive = t.refinement(t.Number, (n) => n >= 0, 'Positive');

@@ -170,3 +170,3 @@ Positive.is(1); // => true

Subtypes have the following `meta` object:
Refinements have the following `meta` object:

@@ -446,4 +446,4 @@ ```js

```js
var Min = t.subtype(t.String, function (s) { return s.length > 2; }, 'Min');
var Max = t.subtype(t.String, function (s) { return s.length < 5; }, 'Max');
var Min = t.refinement(t.String, function (s) { return s.length > 2; }, 'Min');
var Max = t.refinement(t.String, function (s) { return s.length < 5; }, 'Max');
var MinMax = t.intersection([Min, Max], 'MinMax');

@@ -534,3 +534,3 @@

// An `ExcitedString` is a `t.String` containing an exclamation mark
var ExcitedString = t.subtype(t.String, function (s) { return s.indexOf('!') !== -1; }, 'ExcitedString');
var ExcitedString = t.refinement(t.String, function (s) { return s.indexOf('!') !== -1; }, 'ExcitedString');

@@ -573,3 +573,3 @@ // An `Exciter` takes a `t.String` and returns an `ExcitedString`

// Raises error:
// Invalid `Hello?` supplied to `ExcitedString`, insert a valid value for the subtype
// Invalid `Hello?` supplied to `ExcitedString`, insert a valid value for the refinement
simpleQuestionator('Hello');

@@ -576,0 +576,0 @@

@@ -5,3 +5,3 @@ /*! @preserve

*
* Copyright (c) 2014 Giulio Canti
* Copyright (c) 2014-2015 Giulio Canti
*

@@ -12,7 +12,8 @@ */

// configurable
// overrideable by the user
exports.stringify = function stringify(x) {
try { // handle "Converting circular structure to JSON" error
return JSON.stringify(x, null, 2);
} catch (e) {
}
catch (e) {
return String(x);

@@ -22,6 +23,2 @@ }

function isInstanceOf(x, constructor) {
return x instanceof constructor;
}
function isNil(x) {

@@ -48,3 +45,3 @@ return x === null || x === void 0;

function isArray(x) {
return isInstanceOf(x, Array);
return x instanceof Array;
}

@@ -61,11 +58,11 @@

function isStruct(x) {
return isType(x) && (x.meta.kind === 'struct');
return isType(x) && ( x.meta.kind === 'struct' );
}
function isMaybe(x) {
return isType(x) && (x.meta.kind === 'maybe');
return isType(x) && ( x.meta.kind === 'maybe' );
}
function isUnion(x) {
return isType(x) && (x.meta.kind === 'union');
return isType(x) && ( x.meta.kind === 'union' );
}

@@ -77,7 +74,19 @@

// Returns true if x is of type `type`
// returns true if x is an instance of type
function is(x, type) {
return isType(type) ? type.is(x) : isInstanceOf(x, type); // type should be a class constructor
if (isType(type)) {
return type.is(x);
}
return x instanceof type; // type should be a class constructor
}
// return true if the type constructor behaves like the identity function (exceptions are the structs)
function isIdentity(type) {
if (isType(type)) {
return type.meta.identity;
}
return true; // ES6 classes are identity for tcomb
}
// creates an instance of a type, handling the optional new operator
function create(type, value, path) {

@@ -90,5 +99,5 @@ if (isType(type)) {

if (process.env.NODE_ENV !== 'production') {
// type should be a class constructor and value some instance, just check membership and return the value
// here type should be a class constructor and value some instance, just check membership and return the value
path = path || [getFunctionName(type)];
assert(isInstanceOf(value, type), function () { return 'Invalid value ' + exports.stringify(value) + ' supplied to ' + path.join('/'); });
assert(value instanceof type, function () { return 'Invalid value ' + exports.stringify(value) + ' supplied to ' + path.join('/'); });
}

@@ -104,7 +113,9 @@

function getTypeName(constructor) {
if (isType(constructor)) { return constructor.displayName; }
if (isType(constructor)) {
return constructor.displayName;
}
return getFunctionName(constructor);
}
// configurable
// overrideable by the user
exports.fail = function fail(message) {

@@ -116,6 +127,6 @@ throw new TypeError('[tcomb] ' + message);

if (guard !== true) {
if (isFunction(message)) {
if (isFunction(message)) { // handle lazy messages
message = message();
}
else if (isNil(message)) {
else if (isNil(message)) { // use a default message
message = 'Assert failed (turn on "Pause on exceptions" in your Source panel)';

@@ -127,3 +138,3 @@ }

// safe mixin: cannot override props unless specified
// safe mixin, cannot override props unless specified
function mixin(target, source, overwrite) {

@@ -145,8 +156,12 @@ if (isNil(source)) { return target; }

function forbidNewOperator(x, type) {
assert(!isInstanceOf(x, type), function () { return 'Cannot use the new operator to instantiate the type ' + getTypeName(type); });
assert(!(x instanceof type), function () { return 'Cannot use the new operator to instantiate the type ' + getTypeName(type); });
}
function getShallowCopy(x) {
if (isArray(x)) { return x.concat(); }
if (isObject(x)) { return mixin({}, x); }
if (isArray(x)) {
return x.concat();
}
if (isObject(x)) {
return mixin({}, x);
}
return x;

@@ -275,3 +290,4 @@ }

kind: 'irreducible',
name: name
name: name,
identity: true
};

@@ -305,19 +321,13 @@

var Err = irreducible('Error', function (x) {
return isInstanceOf(x, Error);
return x instanceof Error;
});
var Re = irreducible('RegExp', function (x) {
return isInstanceOf(x, RegExp);
return x instanceof RegExp;
});
var Dat = irreducible('Date', function (x) {
return isInstanceOf(x, Date);
return x instanceof Date;
});
function getDefaultStructName(props) {
return '{' + Object.keys(props).map(function (prop) {
return prop + ': ' + getTypeName(props[prop]);
}).join(', ') + '}';
}
function struct(props, name) {

@@ -330,7 +340,7 @@

var displayName = name || getDefaultStructName(props);
var displayName = name || struct.getDefaultName(props);
function Struct(value, path) {
if (Struct.is(value)) { // makes Struct idempotent
if (Struct.is(value)) { // implements idempotency
return value;

@@ -344,3 +354,3 @@ }

if (!isInstanceOf(this, Struct)) { // makes `new` optional
if (!(this instanceof Struct)) { // `new` is optional
return new Struct(value);

@@ -366,3 +376,4 @@ }

props: props,
name: name
name: name,
identity: false
};

@@ -373,3 +384,3 @@

Struct.is = function (x) {
return isInstanceOf(x, Struct);
return x instanceof Struct;
};

@@ -404,5 +415,7 @@

function getDefaultUnionName(types) {
return types.map(getTypeName).join(' | ');
}
struct.getDefaultName = function (props) {
return '{' + Object.keys(props).map(function (prop) {
return prop + ': ' + getTypeName(props[prop]);
}).join(', ') + '}';
};

@@ -416,8 +429,11 @@ function union(types, name) {

var displayName = name || getDefaultUnionName(types);
var displayName = name || union.getDefaultName(types);
var identity = types.every(isIdentity);
function Union(value, path) {
if (process.env.NODE_ENV !== 'production') {
forbidNewOperator(this, Union);
if (process.env.NODE_ENV === 'production') {
if (identity) {
return value;
}
}

@@ -428,4 +444,6 @@

if (process.env.NODE_ENV !== 'production') {
forbidNewOperator(this, Union);
path = path || [displayName];
assert(isType(type), function () { return 'Invalid value ' + exports.stringify(value) + ' supplied to ' + path.join('/'); });
assert(isType(type), function () { return 'Invalid value ' + exports.stringify(value) + ' supplied to ' + path.join('/') + ' (no constructor found)'; });
assert(types.some(function (t) { return t === type; }), function () { return 'Invalid constructor ' + getTypeName(type) + ' returned by ' + path.join('/') + '.dispatch(x) function'; });
path[path.length - 1] += '(' + getTypeName(type) + ')';

@@ -440,3 +458,4 @@ }

types: types,
name: name
name: name,
identity: identity
};

@@ -455,3 +474,3 @@

var type = types[i];
if (isUnion(type)) {
if (isUnion(type)) { // handle union of unions
var t = type.dispatch(x);

@@ -475,5 +494,5 @@ if (!isNil(t)) {

function getDefaultIntersectionName(types) {
return types.map(getTypeName).join(' & ');
}
union.getDefaultName = function (types) {
return types.map(getTypeName).join(' | ');
};

@@ -487,3 +506,3 @@ function intersection(types, name) {

var displayName = name || getDefaultIntersectionName(types);
var displayName = name || intersection.getDefaultName(types);

@@ -504,3 +523,4 @@ function Intersection(value, path) {

types: types,
name: name
name: name,
identity: true
};

@@ -523,12 +543,8 @@

function getDefaultMaybeName(type) {
return '?' + getTypeName(type);
}
intersection.getDefaultName = function (types) {
return types.map(getTypeName).join(' & ');
};
function maybe(type, name) {
if (process.env.NODE_ENV !== 'production') {
assert(isFunction(type), function () { return 'Invalid argument type ' + exports.stringify(type) + ' supplied to maybe(type, [name]) combinator (expected a type)'; });
}
if (isMaybe(type) || type === Any || type === Nil) { // makes the combinator idempotent and handle Any, Nil

@@ -539,6 +555,7 @@ return type;

if (process.env.NODE_ENV !== 'production') {
assert(isFunction(type), function () { return 'Invalid argument type ' + exports.stringify(type) + ' supplied to maybe(type, [name]) combinator (expected a type)'; });
assert(isTypeName(name), function () { return 'Invalid argument name ' + exports.stringify(name) + ' supplied to maybe(type, [name]) combinator (expected a string)'; });
}
var displayName = name || getDefaultMaybeName(type);
var displayName = name || maybe.getDefaultName(type);

@@ -555,3 +572,4 @@ function Maybe(value, path) {

type: type,
name: name
name: name,
identity: isIdentity(type)
};

@@ -568,5 +586,5 @@

function getDefaultEnumsName(map) {
return Object.keys(map).map(function (k) { return exports.stringify(k); }).join(' | ');
}
maybe.getDefaultName = function (type) {
return '?' + getTypeName(type);
};

@@ -580,3 +598,3 @@ function enums(map, name) {

var displayName = name || getDefaultEnumsName(map);
var displayName = name || enums.getDefaultName(map);

@@ -597,3 +615,4 @@ function Enums(value, path) {

map: map,
name: name
name: name,
identity: true
};

@@ -610,2 +629,6 @@

enums.getDefaultName = function (map) {
return Object.keys(map).map(function (k) { return exports.stringify(k); }).join(' | ');
};
enums.of = function (keys, name) {

@@ -620,6 +643,2 @@ keys = isString(keys) ? keys.split(' ') : keys;

function getDefaultTupleName(types) {
return '[' + types.map(getTypeName).join(', ') + ']';
}
function tuple(types, name) {

@@ -632,12 +651,13 @@

var displayName = name || getDefaultTupleName(types);
var displayName = name || tuple.getDefaultName(types);
var identity = types.every(isIdentity);
function isTuple(x) {
return types.every(function (type, i) {
return is(x[i], type);
});
}
function Tuple(value, path) {
if (process.env.NODE_ENV === 'production') {
if (identity) {
return value;
}
}
if (process.env.NODE_ENV !== 'production') {

@@ -648,21 +668,21 @@ path = path || [displayName];

if (isTuple(value)) { // makes Tuple idempotent
if (process.env.NODE_ENV !== 'production') {
Object.freeze(value);
}
return value;
var idempotent = true;
var ret = [];
for (var i = 0, len = types.length; i < len; i++) {
var expected = types[i];
var actual = value[i];
var instance = create(expected, actual, ( process.env.NODE_ENV !== 'production' ? path.concat(i + ': ' + getTypeName(expected)) : null ));
idempotent = idempotent && ( actual === instance );
ret.push(instance);
}
var arr = [], expected, actual;
for (var i = 0, len = types.length; i < len; i++) {
expected = types[i];
actual = value[i];
arr.push(create(expected, actual, ( process.env.NODE_ENV !== 'production' ? path.concat(i + ': ' + getTypeName(expected)) : null )));
if (idempotent) { // implements idempotency
ret = value;
}
if (process.env.NODE_ENV !== 'production') {
Object.freeze(arr);
Object.freeze(ret);
}
return arr;
return ret;
}

@@ -673,3 +693,4 @@

types: types,
name: name
name: name,
identity: identity
};

@@ -682,3 +703,5 @@

x.length === types.length &&
isTuple(x);
types.every(function (type, i) {
return is(x[i], type);
});
};

@@ -693,20 +716,21 @@

function getDefaultSubtypeName(type, predicate) {
return '{' + getTypeName(type) + ' | ' + getFunctionName(predicate) + '}';
}
tuple.getDefaultName = function (types) {
return '[' + types.map(getTypeName).join(', ') + ']';
};
function subtype(type, predicate, name) {
function refinement(type, predicate, name) {
if (process.env.NODE_ENV !== 'production') {
assert(isFunction(type), function () { return 'Invalid argument type ' + exports.stringify(type) + ' supplied to subtype(type, predicate, [name]) combinator (expected a type)'; });
assert(isFunction(predicate), function () { return 'Invalid argument predicate supplied to subtype(type, predicate, [name]) combinator (expected a function)'; });
assert(isTypeName(name), function () { return 'Invalid argument name ' + exports.stringify(name) + ' supplied to subtype(type, predicate, [name]) combinator (expected a string)'; });
assert(isFunction(type), function () { return 'Invalid argument type ' + exports.stringify(type) + ' supplied to refinement(type, predicate, [name]) combinator (expected a type)'; });
assert(isFunction(predicate), function () { return 'Invalid argument predicate supplied to refinement(type, predicate, [name]) combinator (expected a function)'; });
assert(isTypeName(name), function () { return 'Invalid argument name ' + exports.stringify(name) + ' supplied to refinement(type, predicate, [name]) combinator (expected a string)'; });
}
var displayName = name || getDefaultSubtypeName(type, predicate);
var displayName = name || refinement.getDefaultName(type, predicate);
var identity = isIdentity(type);
function Subtype(value, path) {
function Refinement(value, path) {
if (process.env.NODE_ENV !== 'production') {
forbidNewOperator(this, Subtype);
forbidNewOperator(this, Refinement);
path = path || [displayName];

@@ -724,25 +748,26 @@ }

Subtype.meta = {
Refinement.meta = {
kind: 'subtype',
type: type,
predicate: predicate,
name: name
name: name,
identity: identity
};
Subtype.displayName = displayName;
Refinement.displayName = displayName;
Subtype.is = function (x) {
Refinement.is = function (x) {
return is(x, type) && predicate(x);
};
Subtype.update = function (instance, spec) {
return Subtype(exports.update(instance, spec));
Refinement.update = function (instance, spec) {
return Refinement(exports.update(instance, spec));
};
return Subtype;
return Refinement;
}
function getDefaultListName(type) {
return 'Array<' + getTypeName(type) + '>';
}
refinement.getDefaultName = function (type, predicate) {
return '{' + getTypeName(type) + ' | ' + getFunctionName(predicate) + '}';
};

@@ -756,13 +781,14 @@ function list(type, name) {

var displayName = name || getDefaultListName(type);
var displayName = name || list.getDefaultName(type);
var typeNameCache = getTypeName(type);
var identity = isIdentity(type); // the list is identity iif type is identity
function isList(x) {
return x.every(function (e) {
return is(e, type);
});
}
function List(value, path) {
if (process.env.NODE_ENV === 'production') {
if (identity) {
return value; // just trust the input if elements must not be hydrated
}
}
if (process.env.NODE_ENV !== 'production') {

@@ -773,20 +799,20 @@ path = path || [displayName];

if (isList(value)) { // makes List idempotent
if (process.env.NODE_ENV !== 'production') {
Object.freeze(value);
}
return value;
}
var arr = [];
var idempotent = true; // will remain true if I can reutilise the input
var ret = []; // make a temporary copy, will be discarded if idempotent remains true
for (var i = 0, len = value.length; i < len; i++ ) {
var actual = value[i];
arr.push(create(type, actual, ( process.env.NODE_ENV !== 'production' ? path.concat(i + ': ' + typeNameCache) : null )));
var instance = create(type, actual, ( process.env.NODE_ENV !== 'production' ? path.concat(i + ': ' + typeNameCache) : null ));
idempotent = idempotent && ( actual === instance );
ret.push(instance);
}
if (idempotent) { // implements idempotency
ret = value;
}
if (process.env.NODE_ENV !== 'production') {
Object.freeze(arr);
Object.freeze(ret);
}
return arr;
return ret;
}

@@ -797,3 +823,4 @@

type: type,
name: name
name: name,
identity: identity
};

@@ -804,3 +831,5 @@

List.is = function (x) {
return isArray(x) && isList(x);
return isArray(x) && x.every(function (e) {
return is(e, type);
});
};

@@ -815,5 +844,5 @@

function getDefaultDictName(domain, codomain) {
return '{[key: ' + getTypeName(domain) + ']: ' + getTypeName(codomain) + '}';
}
list.getDefaultName = function (type) {
return 'Array<' + getTypeName(type) + '>';
};

@@ -828,19 +857,15 @@ function dict(domain, codomain, name) {

var displayName = name || getDefaultDictName(domain, codomain);
var displayName = name || dict.getDefaultName(domain, codomain);
var domainNameCache = getTypeName(domain);
var codomainNameCache = getTypeName(codomain);
var identity = isIdentity(domain) && isIdentity(codomain);
function isDict(x) {
for (var k in x) {
if (x.hasOwnProperty(k)) {
if (!is(k, domain) || !is(x[k], codomain)) {
return false;
}
function Dict(value, path) {
if (process.env.NODE_ENV === 'production') {
if (identity) {
return value; // just trust the input if elements must not be hydrated
}
}
return true;
}
function Dict(value, path) {
if (process.env.NODE_ENV !== 'production') {

@@ -851,10 +876,4 @@ path = path || [displayName];

if (isDict(value)) { // makes Dict idempotent
if (process.env.NODE_ENV !== 'production') {
Object.freeze(value);
}
return value;
}
var obj = {};
var idempotent = true; // will remain true if I can reutilise the input
var ret = {}; // make a temporary copy, will be discarded if idempotent remains true
for (var k in value) {

@@ -864,11 +883,17 @@ if (value.hasOwnProperty(k)) {

var actual = value[k];
obj[k] = create(codomain, actual, ( process.env.NODE_ENV !== 'production' ? path.concat(k + ': ' + codomainNameCache) : null ));
var instance = create(codomain, actual, ( process.env.NODE_ENV !== 'production' ? path.concat(k + ': ' + codomainNameCache) : null ));
idempotent = idempotent && ( actual === instance );
ret[k] = instance;
}
}
if (idempotent) { // implements idempotency
ret = value;
}
if (process.env.NODE_ENV !== 'production') {
Object.freeze(obj);
Object.freeze(ret);
}
return obj;
return ret;
}

@@ -880,3 +905,4 @@

codomain: codomain,
name: name
name: name,
identity: identity
};

@@ -887,3 +913,13 @@

Dict.is = function (x) {
return isObject(x) && isDict(x);
if (!isObject(x)) {
return false;
}
for (var k in x) {
if (x.hasOwnProperty(k)) {
if (!is(k, domain) || !is(x[k], codomain)) {
return false;
}
}
}
return true;
};

@@ -898,2 +934,6 @@

dict.getDefaultName = function (domain, codomain) {
return '{[key: ' + getTypeName(domain) + ']: ' + getTypeName(codomain) + '}';
};
function isInstrumented(f) {

@@ -903,6 +943,2 @@ return isFunction(f) && isObject(f.instrumentation);

function getDefaultFuncName(domain, codomain) {
return '(' + domain.map(getTypeName).join(', ') + ') => ' + getTypeName(codomain);
}
function func(domain, codomain, name) {

@@ -918,8 +954,8 @@

var displayName = name || getDefaultFuncName(domain, codomain);
var displayName = name || func.getDefaultName(domain, codomain);
function FuncType(value, uncurried) {
function FuncType(value, curried) {
if (!isInstrumented(value)) { // automatically instrument the function
return FuncType.of(value, uncurried);
return FuncType.of(value, curried);
}

@@ -998,2 +1034,6 @@

func.getDefaultName = function (domain, codomain) {
return '(' + domain.map(getTypeName).join(', ') + ') => ' + getTypeName(codomain);
};
function match(x) {

@@ -1038,19 +1078,19 @@ var type, guard, f, count;

Nil: Nil,
Str: Str,
Str: Str, // deprecated
String: Str,
Num: Num,
Num: Num, // deprecated
Number: Num,
Bool: Bool,
Bool: Bool, // deprecated
Boolean: Bool,
Arr: Arr,
Arr: Arr, // deprecated
Array: Arr,
Obj: Obj,
Obj: Obj, // deprecated
Object: Obj,
Func: Func,
Func: Func, // deprecated
Function: Func,
Err: Err,
Err: Err, // deprecated
Error: Err,
Re: Re,
Re: Re, // deprecated
RegExp: Re,
Dat: Dat,
Dat: Dat, // deprecated
Date: Dat,

@@ -1063,3 +1103,4 @@ irreducible: irreducible,

tuple: tuple,
subtype: subtype,
subtype: refinement, // deprecated
refinement: refinement,
list: list,

@@ -1066,0 +1107,0 @@ dict: dict,

{
"name": "tcomb",
"version": "2.4.1",
"version": "2.5.0",
"description": "Type checking and DDD for JavaScript",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -16,3 +16,3 @@ [![build status](https://img.shields.io/travis/gcanti/tcomb/master.svg?style=flat-square)](https://travis-ci.org/gcanti/tcomb)

// a user defined type
var Integer = t.subtype(t.Number, function (n) { return n % 1 === 0; }, 'Integer'); // <= give a name for better debug messages
var Integer = t.refinement(t.Number, function (n) { return n % 1 === 0; }, 'Integer'); // <= give a name for better debug messages

@@ -55,3 +55,3 @@ // a struct

* enums
* subtypes
* refinements
* unions

@@ -58,0 +58,0 @@ * intersections

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