Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

troika-animation

Package Overview
Dependencies
Maintainers
1
Versions
43
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

troika-animation - npm Package Compare versions

Comparing version 0.16.0 to 0.17.0

4

__tests__/Interpolators.test.js

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

import {number, color} from '../src/Interpolators'
import {number, color} from '../src/Interpolators.js'

@@ -45,2 +45,2 @@ test('number interpolator', () => {

})
})
})

@@ -1,3 +0,3 @@

import MultiTween from '../src/MultiTween'
import Tween from '../src/Tween'
import MultiTween from '../src/MultiTween.js'
import Tween from '../src/Tween.js'

@@ -4,0 +4,0 @@

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

import Tween from '../src/Tween'
import Tween from '../src/Tween.js'

@@ -289,2 +289,2 @@

})
})
})

@@ -11,7 +11,5 @@ /*

var pow = Math.pow;
var PI = Math.PI;
var sqrt = Math.sqrt;
var HALF_PI = PI / 2;
var TWO_PI = PI * 2;
const {pow, PI, sqrt} = Math;
const HALF_PI = PI / 2;
const TWO_PI = PI * 2;

@@ -21,67 +19,76 @@

function makeInOut(inFn, outFn) {
return function (t) { return t < 0.5 ? inFn(t * 2) * 0.5 : outFn(t * 2 - 1) * 0.5 + 0.5; }
return t => t < 0.5 ? inFn(t * 2) * 0.5 : outFn(t * 2 - 1) * 0.5 + 0.5
}
function makeExpIn(exp) {
return function (t) { return pow(t, exp); }
return t => pow(t, exp)
}
function makeExpOut(exp) {
return function (t) { return 1 - pow(1 - t, exp); }
return t => 1 - pow(1 - t, exp)
}
function makeExpInOut(exp) {
return function (t) { return t < 0.5 ?
return t => t < 0.5 ?
pow(t * 2, exp) * 0.5 :
(1 - pow(1 - (t * 2 - 1), exp)) * 0.5 + 0.5; }
(1 - pow(1 - (t * 2 - 1), exp)) * 0.5 + 0.5
}
var linear = function (t) { return t; };
const linear = t => t;
var easeInQuad = makeExpIn(2);
var easeOutQuad = makeExpOut(2);
var easeInOutQuad = makeExpInOut(2);
const easeInQuad = makeExpIn(2);
const easeOutQuad = makeExpOut(2);
const easeInOutQuad = makeExpInOut(2);
var easeInCubic = makeExpIn(3);
var easeOutCubic = makeExpOut(3);
var easeInOutCubic = makeExpInOut(3);
const easeInCubic = makeExpIn(3);
const easeOutCubic = makeExpOut(3);
const easeInOutCubic = makeExpInOut(3);
var easeInQuart = makeExpIn(4);
var easeOutQuart = makeExpOut(4);
var easeInOutQuart = makeExpInOut(4);
const easeInQuart = makeExpIn(4);
const easeOutQuart = makeExpOut(4);
const easeInOutQuart = makeExpInOut(4);
var easeInQuint = makeExpIn(5);
var easeOutQuint = makeExpOut(5);
var easeInOutQuint = makeExpInOut(5);
const easeInQuint = makeExpIn(5);
const easeOutQuint = makeExpOut(5);
const easeInOutQuint = makeExpInOut(5);
var easeInSine = function (t) { return 1 - Math.cos(t * (HALF_PI)); };
var easeOutSine = function (t) { return Math.sin(t * (HALF_PI)); };
var easeInOutSine = function (t) { return -0.5 * (Math.cos(PI * t) - 1); };
const easeInSine = t => 1 - Math.cos(t * (HALF_PI));
const easeOutSine = t => Math.sin(t * (HALF_PI));
const easeInOutSine = t => -0.5 * (Math.cos(PI * t) - 1);
var easeInExpo = function (t) { return (t === 0) ? 0 : pow(2, 10 * (t - 1)); };
const easeInExpo = t =>
(t === 0) ? 0 : pow(2, 10 * (t - 1));
var easeOutExpo = function (t) { return (t === 1) ? 1 : 1 - pow(2, -10 * t); };
const easeOutExpo = t =>
(t === 1) ? 1 : 1 - pow(2, -10 * t);
var easeInOutExpo = function (t) { return (t === 0 || t === 1) ? t :
const easeInOutExpo = t =>
(t === 0 || t === 1) ? t :
t < 0.5 ?
pow(2, 10 * (t * 2 - 1)) * 0.5 :
(1 - pow(2, -10 * (t * 2 - 1))) * 0.5 + 0.5; };
(1 - pow(2, -10 * (t * 2 - 1))) * 0.5 + 0.5;
var easeInCirc = function (t) { return 1 - sqrt(1 - t * t); };
const easeInCirc = t =>
1 - sqrt(1 - t * t);
var easeOutCirc = function (t) { return sqrt(1 - pow(t - 1, 2)); };
const easeOutCirc = t =>
sqrt(1 - pow(t - 1, 2));
var easeInOutCirc = makeInOut(easeInCirc, easeOutCirc);
const easeInOutCirc = makeInOut(easeInCirc, easeOutCirc);
var easeInElastic = function (t) { return (t === 0 || t === 1) ? t : 1 - easeOutElastic(1 - t); };
const easeInElastic = t =>
(t === 0 || t === 1) ? t : 1 - easeOutElastic(1 - t);
var easeOutElastic = function (t) { return (t === 0 || t === 1) ? t :
Math.pow(2, -10 * t) * Math.sin((t - 0.075) * TWO_PI / 0.3) + 1; };
const easeOutElastic = t =>
(t === 0 || t === 1) ? t :
Math.pow(2, -10 * t) * Math.sin((t - 0.075) * TWO_PI / 0.3) + 1;
var easeInOutElastic = makeInOut(easeInElastic, easeOutElastic);
const easeInOutElastic = makeInOut(easeInElastic, easeOutElastic);
var easeInBack = function (t) { return t * t * (2.70158 * t - 1.70158); };
const easeInBack = t =>
t * t * (2.70158 * t - 1.70158);
var easeOutBack = function (t) { return (t -= 1) * t * (2.70158 * t + 1.70158) + 1; };
const easeOutBack = t =>
(t -= 1) * t * (2.70158 * t + 1.70158) + 1;
var easeInOutBack = function (t) {
var s = 1.70158 * 1.525;
const easeInOutBack = t => {
const s = 1.70158 * 1.525;
return (t *= 2) < 1 ?

@@ -92,5 +99,7 @@ 0.5 * (t * t * ((s + 1) * t - s)) :

var easeInBounce = function (t) { return 1 - easeOutBounce(1 - t); };
const easeInBounce = t =>
1 - easeOutBounce(1 - t);
var easeOutBounce = function (t) { return t < (1 / 2.75) ?
const easeOutBounce = t =>
t < (1 / 2.75) ?
(7.5625 * t * t) :

@@ -101,5 +110,5 @@ t < (2 / 2.75) ?

(7.5625 * (t -= (2.25 / 2.75)) * t + .9375) :
(7.5625 * (t -= (2.625 / 2.75)) * t + .984375); };
(7.5625 * (t -= (2.625 / 2.75)) * t + .984375);
var easeInOutBounce = makeInOut(easeInBounce, easeOutBounce);
const easeInOutBounce = makeInOut(easeInBounce, easeOutBounce);

@@ -259,9 +268,9 @@ // Aliases...?

*/
var colorValueToNumber = (function() {
var colorCanvas, colorCanvasCtx;
const colorValueToNumber = (function() {
let colorCanvas, colorCanvasCtx;
// Cache for evaluated string values
var stringCache = Object.create(null);
var stringCacheSize = 0;
var stringCacheMaxSize = 2048;
let stringCache = Object.create(null);
let stringCacheSize = 0;
const stringCacheMaxSize = 2048;

@@ -286,4 +295,4 @@ return function(value) {

colorCanvasCtx.fillRect(0, 0, 1, 1);
var colorData = colorCanvasCtx.getImageData(0, 0, 1, 1).data;
var result = rgbToNumber(colorData[0], colorData[1], colorData[2]);
const colorData = colorCanvasCtx.getImageData(0, 0, 1, 1).data;
const result = rgbToNumber(colorData[0], colorData[1], colorData[2]);

@@ -323,4 +332,4 @@ // Enforce max cache size - for now this invalidates the entire cache when reaching

var linear$1 = function (v) { return v; };
var maxSafeInteger = 0x1fffffffffffff;
const linear$1 = v => v;
const maxSafeInteger = 0x1fffffffffffff;

@@ -351,57 +360,52 @@ /**

*/
var Tween = function Tween(callback, fromValue, toValue, duration, delay, easing, iterations, direction, interpolate) {
if ( duration === void 0 ) duration=750;
if ( delay === void 0 ) delay=0;
if ( easing === void 0 ) easing=linear$1;
if ( iterations === void 0 ) iterations=1;
if ( direction === void 0 ) direction='forward';
if ( interpolate === void 0 ) interpolate='number';
class Tween {
constructor(callback, fromValue, toValue, duration=750, delay=0, easing=linear$1, iterations=1, direction='forward', interpolate='number') {
this.callback = callback;
this.fromValue = fromValue;
this.toValue = toValue;
this.duration = duration;
this.delay = delay;
this.easing = typeof easing === 'string' ? (Easings[easing] || linear$1) : easing;
this.iterations = iterations;
this.direction = direction;
this.interpolate = typeof interpolate === 'function' ? interpolate : Interpolators[interpolate] || number;
this.callback = callback;
this.fromValue = fromValue;
this.toValue = toValue;
this.duration = duration;
this.delay = delay;
this.easing = typeof easing === 'string' ? (Easings[easing] || linear$1) : easing;
this.iterations = iterations;
this.direction = direction;
this.interpolate = typeof interpolate === 'function' ? interpolate : Interpolators[interpolate] || number;
/**
* @property totalElapsed
* @type {number}
* The total duration of this tween from 0 to its completion, taking into account its `duration`, `delay`, and
* `iterations`. This is calculated once upon instantiation, and may be used to determine whether the tween is
* finished or not at a given time.
*/
this.totalElapsed = this.iterations < maxSafeInteger ? this.delay + (this.duration * this.iterations) : maxSafeInteger;
}
/**
* @property totalElapsed
* @type {number}
* The total duration of this tween from 0 to its completion, taking into account its `duration`, `delay`, and
* `iterations`. This is calculated once upon instantiation, and may be used to determine whether the tween is
* finished or not at a given time.
* For a given elapsed time relative to the start of the tween, calculates the value at that time and calls the
* `callback` function with that value. If the given time is during the `delay` period, the callback will not be
* invoked.
* @param {number} time
*/
this.totalElapsed = this.iterations < maxSafeInteger ? this.delay + (this.duration * this.iterations) : maxSafeInteger;
};
/**
* For a given elapsed time relative to the start of the tween, calculates the value at that time and calls the
* `callback` function with that value. If the given time is during the `delay` period, the callback will not be
* invoked.
* @param {number} time
*/
Tween.prototype.gotoElapsedTime = function gotoElapsedTime (time) {
var duration = this.duration;
var delay = this.delay;
if (time >= delay) {
time = Math.min(time, this.totalElapsed) - delay; //never go past final value
var progress = (time % duration) / duration;
if (progress === 0 && time !== 0) { progress = 1; }
progress = this.easing(progress);
if (this.direction === 'reverse' || (this.direction === 'alternate' && Math.ceil(time / duration) % 2 === 0)) {
progress = 1 - progress;
gotoElapsedTime(time) {
let duration = this.duration;
let delay = this.delay;
if (time >= delay) {
time = Math.min(time, this.totalElapsed) - delay; //never go past final value
let progress = (time % duration) / duration;
if (progress === 0 && time !== 0) progress = 1;
progress = this.easing(progress);
if (this.direction === 'reverse' || (this.direction === 'alternate' && Math.ceil(time / duration) % 2 === 0)) {
progress = 1 - progress;
}
this.callback(this.interpolate(this.fromValue, this.toValue, progress));
}
this.callback(this.interpolate(this.fromValue, this.toValue, progress));
}
};
/**
* Like `gotoElapsedTime` but goes to the very end of the tween.
*/
Tween.prototype.gotoEnd = function gotoEnd () {
this.gotoElapsedTime(this.totalElapsed);
};
/**
* Like `gotoElapsedTime` but goes to the very end of the tween.
*/
gotoEnd() {
this.gotoElapsedTime(this.totalElapsed);
}
}

@@ -412,7 +416,7 @@ /**

*/
var MultiTween = /*@__PURE__*/(function (Tween) {
function MultiTween(tweens, duration, delay, easing, iterations, direction) {
class MultiTween extends Tween {
constructor(tweens, duration, delay, easing, iterations, direction) {
if (typeof duration !== 'number') {
// Calculate duration based on the longest individual total duration
duration = tweens.reduce(function (dur, tween) { return Math.max(dur, tween.totalElapsed); }, 0);
duration = tweens.reduce((dur, tween) => Math.max(dur, tween.totalElapsed), 0);
}

@@ -425,3 +429,3 @@ if (duration === Infinity) {

// Tween the total duration time
Tween.call(this, null, 0, duration, duration, delay, easing, iterations, direction);
super(null, 0, duration, duration, delay, easing, iterations, direction);
if (tweens.length === 1) {

@@ -436,7 +440,3 @@ this.callback = tweens[0].gotoElapsedTime.bind(tweens[0]);

if ( Tween ) MultiTween.__proto__ = Tween;
MultiTween.prototype = Object.create( Tween && Tween.prototype );
MultiTween.prototype.constructor = MultiTween;
MultiTween.prototype._syncTweens = function _syncTweens (time) {
_syncTweens(time) {
// NOTE: forward iteration is important here so the tweens are evaluated in order

@@ -447,10 +447,8 @@ // of when they end; that way later tweens will take precedence over earlier ones.

// slightly prior to their end state.
for (var i = 0, len = this.tweens.length; i < len; i++) {
for (let i = 0, len = this.tweens.length; i < len; i++) {
this.tweens[i].gotoElapsedTime(time);
}
};
}
}
return MultiTween;
}(Tween));
function endTimeComparator(a, b) {

@@ -460,5 +458,5 @@ return a.totalElapsed - b.totalElapsed

var runners = [];
var nextFrameTimer = null;
var hasStoppedRunners = false;
let runners = [];
let nextFrameTimer = null;
let hasStoppedRunners = false;

@@ -471,3 +469,3 @@ function noop() {}

function tick() {
var now = Date.now();
let now = Date.now();
nextFrameTimer = null;

@@ -483,3 +481,3 @@

// Sync each runner, filtering out empty ones as we go
for (var i = runners.length; i-- > 0;) {
for (let i = runners.length; i-- > 0;) {
runners[i]._tick(now);

@@ -492,3 +490,3 @@ }

var _scheduler = window;
let _scheduler = window;

@@ -541,120 +539,122 @@ /**

*/
var Runner = function Runner() {
this.tweens = [];
};
class Runner {
constructor() {
this.tweens = [];
}
Runner.prototype.destructor = function destructor () {
this.tweens = null;
stopRunner(this);
this.start = this.stop = this.pause = this._tick = noop;
};
/**
* Add a tween to the runner. It will be invoked on the next frame, not immediately.
* @param {Tween} tween
*/
Runner.prototype.start = function start (tween) {
// If previously paused, update start time to account for the duration of the pause
if (tween.runner$paused && tween.runner$started) {
tween.runner$started += (Date.now() - tween.runner$paused);
} else {
this.tweens.push(tween);
destructor() {
this.tweens = null;
stopRunner(this);
this.start = this.stop = this.pause = this._tick = noop;
}
tween.runner$paused = null;
tween.runner$stopped = false;
// add runner to running runners
startRunner(this);
};
/**
* Add a tween to the runner. It will be invoked on the next frame, not immediately.
* @param {Tween} tween
*/
start(tween) {
// If previously paused, update start time to account for the duration of the pause
if (tween.runner$paused && tween.runner$started) {
tween.runner$started += (Date.now() - tween.runner$paused);
} else {
this.tweens.push(tween);
}
tween.runner$paused = null;
tween.runner$stopped = false;
/**
* Remove a tween from the runner.
* @param tween
*/
Runner.prototype.stop = function stop (tween) {
// queue tween for removal from list on next tick
tween.runner$stopped = true;
tween.runner$paused = null;
};
// add runner to running runners
startRunner(this);
}
/**
* Pause a tween; call `runner.start(tween)` to unpause it
* @param tween
*/
Runner.prototype.pause = function pause (tween) {
if (!tween.runner$paused) {
tween.runner$paused = Date.now();
/**
* Remove a tween from the runner.
* @param tween
*/
stop(tween) {
// queue tween for removal from list on next tick
tween.runner$stopped = true;
tween.runner$paused = null;
}
};
/**
* Stop all running tweens.
*/
Runner.prototype.stopAll = function stopAll () {
if (this.tweens) {
this.tweens.forEach(this.stop, this);
/**
* Pause a tween; call `runner.start(tween)` to unpause it
* @param tween
*/
pause(tween) {
if (!tween.runner$paused) {
tween.runner$paused = Date.now();
}
}
};
Runner.prototype._tick = function _tick (now) {
var tweens = this.tweens;
var hasStoppedTweens = false;
var hasRunningTweens = false;
/**
* Stop all running tweens.
*/
stopAll() {
if (this.tweens) {
this.tweens.forEach(this.stop, this);
}
}
// Sync each tween, filtering out old finished ones as we go
for (var i = 0, len = tweens.length; i < len; i++) {
var tween = tweens[i];
if (!tween.runner$stopped && !tween.runner$paused) {
// Sync the tween to current time
var elapsed = now - (tween.runner$started || (tween.runner$started = now));
tween.gotoElapsedTime(elapsed);
hasRunningTweens = true;
_tick(now) {
let tweens = this.tweens;
let hasStoppedTweens = false;
let hasRunningTweens = false;
// Queue for removal if we're past its end time
if (elapsed > tween.totalElapsed) {
this.stop(tween);
if (tween.onDone) {
tween.onDone();
// Sync each tween, filtering out old finished ones as we go
for (let i = 0, len = tweens.length; i < len; i++) {
let tween = tweens[i];
if (!tween.runner$stopped && !tween.runner$paused) {
// Sync the tween to current time
let elapsed = now - (tween.runner$started || (tween.runner$started = now));
tween.gotoElapsedTime(elapsed);
hasRunningTweens = true;
// Queue for removal if we're past its end time
if (elapsed > tween.totalElapsed) {
this.stop(tween);
if (tween.onDone) {
tween.onDone();
}
}
}
if (tween.runner$stopped) {
hasStoppedTweens = true;
}
}
if (tween.runner$stopped) {
hasStoppedTweens = true;
if (hasRunningTweens) {
this.onTick();
}
}
if (hasRunningTweens) {
this.onTick();
}
// Prune list if needed
// TODO perhaps batch this up so it happens less often
if (hasStoppedTweens) {
this.tweens = tweens.filter(isTweenNotStopped);
// Prune list if needed
// TODO perhaps batch this up so it happens less often
if (hasStoppedTweens) {
this.tweens = tweens.filter(isTweenNotStopped);
// remove runner from running runners if it has no tweens left
if (!this.tweens.length) {
stopRunner(this);
if (this.onDone) {
this.onDone();
// remove runner from running runners if it has no tweens left
if (!this.tweens.length) {
stopRunner(this);
if (this.onDone) {
this.onDone();
}
}
}
}
};
/**
* Override to specify a function that will be called at the end of every frame, after all
* tweens have been updated.
*/
Runner.prototype.onTick = function onTick () {
// abstract
};
/**
* Override to specify a function that will be called at the end of every frame, after all
* tweens have been updated.
*/
onTick() {
// abstract
}
/**
* Override to specify a function that will be called after all running tweens have completed.
*/
Runner.prototype.onDone = function onDone () {
// abstract
};
/**
* Override to specify a function that will be called after all running tweens have completed.
*/
onDone() {
// abstract
}
}
export { Easings, Interpolators, MultiTween, Runner, Tween, setAnimationScheduler };
{
"name": "troika-animation",
"version": "0.16.0",
"version": "0.17.0",
"description": "Troika Animation Utilities",

@@ -17,3 +17,3 @@ "author": "Jason Johnston <jason.johnston@protectwise.com>",

"module:es2015": "src/index.js",
"gitHead": "b17e3967b2166f102cabc6cd4bf46f5a725a8910"
"gitHead": "31909f4beed23f5913aa380db1dd3c1802798b39"
}

@@ -1,11 +0,101 @@

# `troika-animation`
# Troika Animation
> TODO: description
This package provides a small library for "tweening" values over time, heavily optimized for performance. It is used by the Troika framework behind the scenes for its declarative `transition` and `animation` features, but can also be used as a standalone library.
## Installation
If you're using the Troika framework, you don't need to install this directly. If you want to use it standalone, you can get it from [NPM](https://www.npmjs.com/package/troika-animation):
```sh
npm install troika-animation
```
## Usage
To animate a value, you basically need to:
1. Create a `Tween` describing the start and end values, how the value should change over time, and a callback to invoke on each frame
2. Create a `Runner`
3. Start the tween in the runner
### Tween
> See the JSDoc comments in [Tween.js](./src/Tween.js) for more details about each parameter.
```js
import { Tween } from 'troika-animation'
function onTweenFrame(tweenedValue) {
// ...do something with the tweenedValue
}
const tween = new Tween(
onTweenFrame, // callback
-100, // fromValue
100, // toValue
5000, // duration in ms
0, // delay
'easeOutExpo', // easing
1, // iterations
'forward', // direction
'number' // interpolation
)
```
import troikaAnimation from 'troika-animation';
// TODO: DEMONSTRATE API
### MultiTween
This is a specialized `Tween` that, instead of managing a value, manages a list of other `Tween`s. It essentially creates a sub-timeline, whose playback is controlled as a whole. For example you can apply an `easing` to the entire set of tweens as a whole, stretch out their duration, repeat them, etc.
```js
import { MultiTween, Tween } from 'troika-animation'
const tween1 = new Tween(/*...*/)
const tween2 = new Tween(/*...*/)
const multiTween = new MultiTween(
[tween1, tween2], // list of tweens
5000, // duration
0, // delay
'easeInOutExpo', // easing
10, // iterations
'alternate' // direction
)
```
### Runner
> Also see the JSDoc comments in [Runner.js](./src/Runner.js)
```js
import { Tween, Runner } from 'troika-animation'
const tween = new Tween(/*...*/)
const runner = new Runner()
runner.start(tween)
```
### Easings
When constructing a Tween, the `easing` parameter controls the rate of change over time. You can either specify a string, referring to the name of one of the built-in easing functions, or you can provide a custom easing function.
#### Built-in named easings
The built-in named easings can be found in [Easings.js](./src/Easings.js). These may be familiar, as they mostly match the ones provided by the popular [jQuery Easing Plugin](https://github.com/danro/jquery-easing/blob/master/jquery.easing.js) and [easings.net](https://easings.net).
There is also an online [demo of troika-animation easings](https://troika-examples.netlify.com/#easings) that shows the curve for each.
#### Custom easing functions
An easing function takes a single parameter `t`, which refers to the fraction of time passed in the tween's duration from 0 to 1. It must return a number specifying the progress between the start and end values at `t`; 0 corresponds to the start value and 1 corresponds to the end value. Most easings stay in the range from 0 to 1 but some may exceed it.
### Interpolation
The tween `interpolation` parameter controls how the fractional value returned from the `easing` is applied to the start and end values to calculate the in-between value. In most cases you're probably tweening two numbers, which is handled as the default interpolation. But if you have a different type of value, you may need to change the interpolator.
Two built-in interpolation types are provided, which can be referred to by their string names (see [Interpolators.js](./src/Interpolators.js))
- `"number"` - simple linear interpolation between two numeric values (the default).
- `"color"` - interprets the start/end values as RGB colors, and interpolates each color channel independently.
If you need a different interpolation, you can provide a custom function. It takes three parameters: the start value, the end value, and the progress between them (the output of the easing function.) It must return an in-between value of the appropriate type.

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

import Tween from './Tween'
import Tween from './Tween.js'

@@ -3,0 +3,0 @@

@@ -1,3 +0,3 @@

import * as Easings from './Easings'
import * as Interpolators from './Interpolators'
import * as Easings from './Easings.js'
import * as Interpolators from './Interpolators.js'

@@ -4,0 +4,0 @@ const linear = v => v

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