Socket
Socket
Sign inDemoInstall

ink

Package Overview
Dependencies
Maintainers
2
Versions
76
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ink - npm Package Compare versions

Comparing version 0.5.1 to 2.0.0-0

build/apply-styles.js

217

package.json
{
"name": "ink",
"version": "0.5.1",
"description": "React for CLI",
"license": "MIT",
"repository": "vadimdemedes/ink",
"author": {
"name": "vdemedes",
"email": "vdemedes@gmail.com",
"url": "github.com/vadimdemedes"
},
"engines": {
"node": ">=6"
},
"scripts": {
"test": "xo && ava",
"cast": "svg-term --command 'node media/demo.js' --out media/demo.svg --from=100 --window --width=50 --height=8 --term=iterm2 --profile=Snazzy"
},
"files": [
"lib",
"index.js"
],
"keywords": [
"react",
"cli",
"jsx",
"stdout",
"components",
"command-line",
"preact",
"redux",
"print",
"render",
"colors",
"text"
],
"dependencies": {
"arrify": "^1.0.1",
"chalk": "^2.0.1",
"indent-string": "^3.1.0",
"is-equal-shallow": "^0.1.3",
"lodash.flattendeep": "^4.4.0",
"log-update": "^2.1.0",
"prop-types": "^15.5.10"
},
"devDependencies": {
"@babel/core": "^7.0.0-beta.44",
"@babel/plugin-transform-react-jsx": "^7.0.0-beta.44",
"@babel/register": "^7.0.0-beta.44",
"ansi-styles": "^3.1.0",
"ava": "^1.0.0-beta.3",
"babel-eslint": "^8.2.2",
"eslint-config-xo-react": "^0.13.0",
"eslint-plugin-react": "^7.1.0",
"sinon": "^2.3.4",
"strip-ansi": "^4.0.0",
"svg-term-cli": "^2.1.1",
"xo": "^0.18.2"
},
"ava": {
"require": [
"@babel/register"
],
"babel": {
"testOptions": {
"presets": [
"@ava/stage-4"
],
"plugins": [
[
"@babel/plugin-transform-react-jsx",
{
"pragma": "h",
"pragmaFrag": "h.Fragment"
}
]
]
}
}
},
"xo": {
"extends": [
"xo-react"
],
"settings": {
"react": {
"pragma": "h",
"pragmaFrag": "h.Fragment"
}
},
"parser": "babel-eslint",
"rules": {
"react/no-deprecated": 0
},
"overrides": [
{
"files": "test/*.js",
"rules": {
"react/prop-types": 0,
"quotes": 0
}
}
]
}
"name": "ink",
"version": "2.0.0-0",
"description": "React for CLI",
"license": "MIT",
"repository": "vadimdemedes/ink",
"author": {
"name": "vdemedes",
"email": "vdemedes@gmail.com",
"url": "github.com/vadimdemedes"
},
"engines": {
"node": ">=8"
},
"scripts": {
"build": "babel src --out-dir build",
"prepublish": "npm run build",
"test": "xo && ava",
"pretest": "npm run build",
"cast": "svg-term --command 'node media/demo.js' --out media/demo.svg --from=100 --window --width=50 --height=8 --term=iterm2 --profile=Snazzy"
},
"main": "build",
"files": [
"build"
],
"keywords": [
"react",
"cli",
"jsx",
"stdout",
"components",
"command-line",
"preact",
"redux",
"print",
"render",
"colors",
"text"
],
"dependencies": {
"arrify": "^1.0.1",
"chalk": "^2.4.1",
"cli-cursor": "^2.1.0",
"log-update": "^2.3.0",
"prop-types": "^15.6.2",
"react": "^16.4.2",
"react-reconciler": "^0.12.0",
"slice-ansi": "^1.0.0",
"string-length": "^2.0.0",
"undom": "^0.4.0",
"widest-line": "^2.0.0",
"yoga-layout-prebuilt": "^1.9.3"
},
"devDependencies": {
"@babel/cli": "^7.1.2",
"@babel/core": "^7.1.2",
"@babel/plugin-proposal-class-properties": "^7.1.0",
"@babel/plugin-proposal-object-rest-spread": "^7.0.0",
"@babel/preset-react": "^7.0.0",
"ava": "1.0.0-beta.8",
"babel-eslint": "^10.0.1",
"eslint-config-xo-react": "^0.17.0",
"eslint-plugin-react": "^7.11.1",
"strip-ansi": "^4.0.0",
"svg-term-cli": "^2.1.1",
"xo": "^0.23.0"
},
"babel": {
"plugins": [
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-object-rest-spread",
"@babel/plugin-transform-modules-commonjs"
],
"presets": [
"@babel/preset-react"
]
},
"ava": {
"babel": {
"testOptions": {
"plugins": [
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-object-rest-spread",
"@babel/plugin-transform-modules-commonjs"
],
"presets": [
"@babel/preset-react"
]
}
}
},
"xo": {
"parser": "babel-eslint",
"extends": [
"xo-react"
],
"plugins": [
"react"
],
"overrides": [
{
"files": "src/components/*.js",
"rules": {
"unicorn/filename-case": 0,
"react/require-default-props": 1
}
},
{
"files": "test/*.js",
"rules": {
"import/default": 0
}
}
]
}
}
<h1 align="center">
<br>
<img width="192" alt="Ink" src="media/logo.png">
<br>
<img width="300" alt="Ink" src="media/logo.png">
<br>
<br>
<br>
</h1>

@@ -11,3 +12,3 @@

[![Build Status](https://travis-ci.org/vadimdemedes/ink.svg?branch=master)](https://travis-ci.org/vadimdemedes/ink)
[![Build Status](https://travis-ci.org/vadimdemedes/ink.svg?branch=next)](https://travis-ci.org/vadimdemedes/ink)

@@ -18,3 +19,3 @@

```
$ npm install ink
$ npm install ink@next
```

@@ -26,3 +27,4 @@

```jsx
const {h, render, Component, Color } = require('ink');
import React, {Component} from 'react';
import {render, Color} from 'ink';

@@ -62,6 +64,5 @@ class Counter extends Component {

<p align="center">
<img src="media/demo.svg" width="600">
</p>
<img src="media/demo.svg" width="600">
## Useful Components

@@ -92,3 +93,5 @@

- [ink-big-text](https://github.com/sindresorhus/ink-big-text) - Awesome text component.
- [ink-divider](https://github.com/JureSotosek/ink-divider) - A divider component.
## Built with Ink

@@ -99,22 +102,18 @@

## Guide
- [Getting Started](#getting-started)
- [Core API](#core-api)
- [Components](#components)
- [Props](#props)
- [Lifecycle Methods](#lifecycle-methods)
- [State](#state)
- [Refs](#refs)
- [Context](#context)
- [Stateless Function Components](#stateless-function-components)
- [API](#api)
- [Building Layouts](#building-layouts)
- [Built-in Components](#built-in-components)
Ink's goal is to provide the same component-based UI building experience that React provides, but for command-line apps. That's why it tries to implement the minimum required functionality of React. If you are already familiar with React (or Preact, since Ink borrows a few ideas from it), you already know Ink.
Ink's goal is to provide the same component-based UI building experience that React provides, but for command-line apps. It uses [yoga-layout](https://github.com/facebook/yoga) to allow Flexbox layouts in the terminal. If you are already familiar with React, you already know Ink.
The key difference you have to remember is that the rendering result isn't a DOM, but a string, which Ink writes to the output.
### Getting Started
To ensure all examples work and you can begin your adventure with Ink, make sure to set up a JSX transpiler and set JSX pragma to `h`. You can use [`babel-plugin-transform-react-jsx`](https://babeljs.io/docs/plugins/transform-react-jsx/) to do this. For example, in `package.json`:
To ensure all examples work and you can begin your adventure with Ink, make sure to set up Babel with a React preset. After [installing Babel](https://babeljs.io/docs/en/usage), configure it in `package.json`:

@@ -124,9 +123,4 @@ ```json

"babel": {
"plugins": [
[
"transform-react-jsx",
{
"pragma": "h"
}
]
"presets": [
"@babel/preset-react"
]

@@ -137,8 +131,9 @@ }

Don't forget to import `h` into every file that contains JSX:
Don't forget to import `React` into every file that contains JSX:
```jsx
const {h} = require('ink');
import React from 'react';
import {Box} from 'ink';
const Demo = () => <div/>;
const Demo = () => <Box/>;
```

@@ -149,22 +144,42 @@

### Core API
### API
#### render(tree, stream)
Since Ink is a React renderer, it means that all of React is supported.
Head over to [React](https://reactjs.org/) website for documentation on how to use it.
In this readme only Ink's methods will be documented.
Mount a component, listen for updates and update the output.
This method is used for interactive UIs, where you need state, user input or lifecycle methods.
#### render(tree, options)
It automatically enables `keypress` events on `process.stdin`. Since it requires [raw mode](https://davidwalsh.name/node-raw-mode) to be enabled, Ink handles default behavior for you, like exiting with <kbd>Ctrl</kbd>+<kbd>C</kbd>.
Mount a component and render the output.
##### tree
Type: `VNode`
Type: `ReactElement`
##### stream
##### options
###### stdout
Type: `Stream`<br>
Default: `process.stdout`
Output stream where app will be rendered.
###### stdin
Type: `Stream`<br>
Default: `process.stdin`
Input stream where app will listen for input.
###### debug
Type: `Boolean`<br>
Default: `false`
If `true`, each update will be rendered as a separate output, without replacing the previous one.
```jsx
const {h, render, Component} = require('ink');
import React, {Component} from 'react';
import {render, Box} from 'ink';

@@ -180,4 +195,8 @@ class Counter extends Component {

render(props, state) {
return `Iteration #${state.i}`;
render() {
return (
<Box>
Iteration #${this.state.i}
</Box>
);
}

@@ -206,411 +225,395 @@

#### renderToString(tree, [prevTree])
There's also a shortcut to avoid passing `options` object:
Render a component to a string and return it.
Useful if you don't intend to use state or lifecycle methods and just want to render the UI once and exit.
```jsx
const {h, renderToString} = require('ink');
render(<Counter>, process.stdout);
```
const Hello = () => 'Hello World';
process.stdout.write(renderToString(<Hello/>));
```
### Building Layouts
### Components
Ink uses [Yoga](https://github.com/facebook/yoga) - a Flexbox layout engine to build great user interfaces for your CLIs.
It's important to remember that each element is a Flexbox container.
Think of it as if each `<div>` in the browser had `display: flex`.
See `<Box>` built-in component below for documentation on how to use Flexbox layouts in Ink.
Similarly to React, there are two kinds of components: Stateful components (next, "component") and stateless function components. You can create a component by extending `Component` class. Unlike stateless function components, they have access to state, context, lifecycle methods and they can be accessed via refs.
```js
class Demo extends Component {
render(props, state, context) {
// props === this.props
// state === this.state
// context === this.context
### Built-in Components
return 'Hello World';
}
}
```
#### <Box>
If you need to extend the constructor to set the initial state or for other purposes, make sure to call `super()` with `props` and `context`:
`<Box>` it's an essential Ink component to build your layout. It's like a `<div>` in a browser.
Import:
```js
constructor(props, context) {
super(props, context);
import {Box} from 'ink';
```
this.state = {
i: 0
};
##### Padding
// Other initialization
}
```
###### paddingTop
#### Props
Type: `number`<br>
Default: `0`
Props are basically arguments for components.
Every parent component can pass props to their children.
###### paddingBottom
```jsx
class Child extends Component {
render(props) {
// props === this.props
Type: `number`<br>
Default: `0`
return `Hello, ${props.name}`;
}
}
###### paddingLeft
class Parent extends Component {
render() {
return <Child name="Joe"/>;
}
}
```
Type: `number`<br>
Default: `0`
To set default props on specific component, use `defaultProps`:
###### paddingRight
```js
const Test = ({first, second}) => `${first} ${second}`;
Type: `number`<br>
Default: `0`
Test.defaultProps = {
first: 'Hello',
second: 'World'
};
###### paddingX
// <Test/> => "Hello World"
```
Type: `number`<br>
Default: `0`
##### Prop Types
###### paddingY
Ink supports prop types out-of-the-box. All you have to do is set them in the same way you would in React:
Type: `number`<br>
Default: `0`
```js
const PropTypes = require('prop-types');
###### padding
Test.propTypes = {
first: PropTypes.string.isRequired,
second: PropTypes.string
};
Type: `number`<br>
Default: `0`
```jsx
<Box paddingTop={2}>Top</Box>
<Box paddingBottom={2}>Bottom</Box>
<Box paddingLeft={2}>Left</Box>
<Box paddingRight={2}>Right</Box>
<Box paddingX={2}>Left and right</Box>
<Box paddingY={2}>Top and bottom</Box>
<Box padding={2}>Top, bottom, left and right</Box>
```
**Note**: Prop types are only checked when `NODE_ENV` isn't `'production'`.
##### Margin
#### Lifecycle Methods
###### marginTop
Lifecycle methods are component methods that are called whenever a certain event happens related to that specific component. All lifecycle methods are called from top to down, meaning that components on top receive those events earlier than their children.
Type: `number`<br>
Default: `0`
##### componentWillMount()
###### marginBottom
Component is initialized and is about to be rendered and written to the output.
Type: `number`<br>
Default: `0`
##### componentDidMount()
###### marginLeft
Component is rendered and written to the output.
Type: `number`<br>
Default: `0`
##### componentWillUnmount()
###### marginRight
Component is about to be unmounted and component instance is going to be destroyed.
This is the place to clean up timers, cancel HTTP requests, etc.
Type: `number`<br>
Default: `0`
##### componentWillReceiveProps(nextProps, nextState)
###### marginX
Component is going to receive new props or state.
At this point `this.props` and `this.state` contain previous props and state.
Type: `number`<br>
Default: `0`
##### shouldComponentUpdate(nextProps, nextState)
###### marginY
Determines whether to rerender component for the next props and state.
Return `false` to skip rerendering of component's children.
By default, returns `true`, so component is always rerendered on update.
Type: `number`<br>
Default: `0`
##### componentWillUpdate(nextProps, nextState)
###### margin
Component is about to rerender.
Type: `number`<br>
Default: `0`
##### componentDidUpdate()
```jsx
<Box marginTop={2}>Top</Box>
<Box marginBottom={2}>Bottom</Box>
<Box marginLeft={2}>Left</Box>
<Box marginRight={2}>Right</Box>
<Box marginX={2}>Left and right</Box>
<Box marginY={2}>Top and bottom</Box>
<Box margin={2}>Top, bottom, left and right</Box>
```
Component was rerendered and was written to the output.
##### Flex
#### State
###### flexGrow
Each component can have its local state accessible via `this.state`.
Whenever a state updates, the component is rerendered.
Type: `number`
To set the initial state, extend the constructor and assign an object to `this.state`.
The state is accessible via `this.state` anywhere in the component, and it's also passed to `render()` as a second argument.
See [flex-grow](https://css-tricks.com/almanac/properties/f/flex-grow/).
```js
class Demo extends Component {
constructor(props, context) {
super(props, context);
```jsx
<Box>
Label:
<Box flexGrow={1}>
Fills all remaining space
</Box>
</Box>
```
this.state = {
i: 0
}
}
###### flexShrink
render(props, state) {
return `Iteration ${state.i}`;
}
}
```
Type: `number`
##### setState(nextState)
See [flex-shrink](https://css-tricks.com/almanac/properties/f/flex-shrink/).
###### nextState
```jsx
<Box width={20}>
<Box flexShrink={2} width={10}>
Will be 1/4
</Box>
<Box width={10}>
Will be 3/4
</Box>
</Box>
```
Type: `Object` `Function`
Default: `{}`
###### flexDirection
Set a new state and update the output.
Type: `string`<br>
Allowed values: `row`, `row-reverse`, `column` and `column-reverse`
**Note**: `setState()` works by **extending** the state via `Object.assign()`, not replacing it with a new object. Therefore you can pass only changed values.
See [flex-direction](https://css-tricks.com/almanac/properties/f/flex-direction/).
```js
class Demo extends Component {
constructor(props, context) {
super(props, context);
```jsx
<Box>
<Box marginRight={1}>X</Box>
<Box>Y</Box>
</Box>
// X Y
this.state = {
i: 0
}
}
<Box flexDirection="row-reverse">
<Box>X</Box>
<Box marginRight={1}>Y</Box>
</Box>
// Y X
render(props, state) {
return `Iteration ${state.i}`;
}
<Box flexDirection="column">
<Box>X</Box>
<Box>Y</Box>
</Box>
// X
// Y
componentDidMount() {
this.setState({
i: this.state.i + 1
});
}
}
<Box flexDirection="column-reverse">
<Box>X</Box>
<Box>Y</Box>
</Box>
// Y
// X
```
The above example will increment the `i` state property and render `Iteration 1` as a result.
###### alignItems
`setState()` also accepts a function, which receives the current state as an argument.
The same effect of incrementing `i` could be achieved in a following way:
Type: `string`<br>
Allowed values: `flex-start`, `center` and `flex-end`
```js
this.setState(state => {
return {
i: state.i + 1
}
});
```
See [align-items](https://css-tricks.com/almanac/properties/f/align-items/).
This is useful when `setState()` calls are batched to ensure that you update the state in a stable way.
```jsx
<Box alignItems="flex-start">
<Box marginRight={1}>X</Box>
<Box>{`A\nB\nC`}</Box>
</Box>
// X A
// B
// C
#### Refs
<Box alignItems="center">
<Box marginRight={1}>X</Box>
<Box>{`A\nB\nC`}</Box>
</Box>
// A
// X B
// C
Refs can be used to get a direct reference to a component instance.
This is useful, if you want to access its methods, for example.
<Box alignItems="flex-end">
<Box marginRight={1}>X</Box>
<Box>{`A\nB\nC`}</Box>
</Box>
// A
// B
// X C
```
Refs work by setting a special `ref` prop on a component.
Prop's value must be a function, which receives a reference to a component as an argument or `null` when the wanted component is unmounted.
###### justifyContent
**Note**: You can't get refs to stateless function components.
Type: `string`<br>
Allowed values: `flex-start`, `center`, `flex-end`, `space-between` and `space-around`.
See [justify-content](https://css-tricks.com/almanac/properties/f/justify-content/).
```jsx
class Child extends Component {
render() {
return null;
}
<Box justifyContent="flex-start">
<Box>X</Box>
</Box>
// [X ]
hello() {
return 'Hello World';
}
}
<Box justifyContent="center">
<Box>X</Box>
</Box>
// [ X ]
class Parent extends Component {
constructor(props, context) {
super(props, context);
<Box justifyContent="flex-end">
<Box>X</Box>
</Box>
// [ X]
this.state = {
message: 'Ink is awesome'
};
}
<Box justifyContent="space-between">
<Box>X</Box>
<Box>Y</Box>
</Box>
// [X Y]
render(props, state) {
const setChildRef = ref => {
this.childRef = ref;
};
<Box justifyContent="space-around">
<Box>X</Box>
<Box>Y</Box>
</Box>
// [ X Y ]
```
return (
<div>
{message}
#### <Color>
<Child ref={setChildRef}/>
</div>
)
}
The `<Color>` compoment is a simple wrapper around [the `chalk` API](https://github.com/chalk/chalk#api).
It supports all of the chalk's methods as `props`.
componentDidMount() {
this.setState({
message: this.childRef.hello()
});
}
}
```
Import:
#### Context
Context is like a global state for all components.
Every component can access context either via `this.context` or inside `render()`:
```js
render(props, state, context) {
// context === this.context
}
import {Color} from 'ink';
```
To add new entries to context, add `getChildContext()` method to your component:
Usage:
```js
class Child extends Component {
render() {
return this.context.message;
}
}
```jsx
<Color rgb={[255, 255, 255]} bgKeyword="magenta">
Hello!
</Color>
class Parent extends Component {
getChildContext() {
return {
message: 'Hello World'
};
}
<Color hex="#000000" bgHex="#FFFFFF">
Hey there
</Color>
render() {
return <Child/>;
}
}
<Color blue>
I'm blue
</Color>
```
#### Stateless Function Components
#### <Text>
If you don't need state, lifecycle methods, context and refs, it's best to use stateless function components for their small amount of code and readability.
This component can change the style of the text, make it bold, underline, italic or strikethrough.
Using stateful components:
Import:
```js
class Demo extends Component {
render(props, state, context) {
return 'Hello World';
}
}
import {Text} from 'ink';
```
Using stateless function components:
##### bold
```js
const Demo = (props, context) => 'Hello World';
```
Type: `boolean`<br>
Default: `false`
As you may have noticed, stateless function components still get access to props and context.
##### italic
#### Built-in Components
Type: `boolean`<br>
Default: `false`
Surprise, surprise, our favorite `<div>` and `<span>` can be used in Ink components!
They are useful for grouping elements
The only difference between `<div>` and `<span>` is that `<div>` inserts a newline after children.
##### underline
```jsx
const Demo = (
<div>
<A/>
<B/>
<C/>
</div>
);
```
Type: `boolean`<br>
Default: `false`
There's also `<br/>`, which serves the same purpose as on the web - a newline.
##### strikethrough
Type: `boolean`<br>
Default: `false`
Usage:
```jsx
const Demo = (
<div>
Line 1
<br/>
Line 2
</div>
);
<Text bold>I am bold</Text>
<Text italic>I am italic</Text>
<Text underline>I am underline</Text>
<Text strikethrough>I am strikethrough</Text>
```
Ink also supports Fragments for returning multiple children from a component's render method.
#### <StdinContext>
```jsx
const {h, Fragment} = require('ink');
`<StdinContext>` is a [React context](https://reactjs.org/docs/context.html#reactcreatecontext), which exposes several props.
render(
<Fragment>
<A/>
<B/>
<C/>
</Fragment>
);
Import:
```js
import {StdinContext} from 'ink';
```
Or using the shorthand syntax:
##### stdin
```jsx
const {h} = require('ink');
Type: `Stream`<br>
Default: `process.stdin`
render(
<>
<A/>
<B/>
<C/>
</>
);
```
Stdin stream passed to `render()` in `options.stdin` or `process.stdin` by default.
Useful if your app needs to handle user input.
To use the Fragments make sure you have `pragmaFrag` in your configuration:
Usage:
```json
{
"babel": {
"plugins": [
[
"@babel/plugin-transform-react-jsx",
{
"pragma": "h",
"pragmaFrag": "h.Fragment"
}
]
]
}
}
```jsx
<StdinContext.Consumer>
{({ stdin }) => (
<MyComponent stdin={stdin}/>
)}
</StdinContext.Consumer>
```
You will also need [Babel v7.0.0-beta.31](https://github.com/babel/babel/releases/tag/v7.0.0-beta.31) or above, which means you will also need to upgrade any other tools that use Babel to their compatible versions, like [@babel/plugin-transform-react-jsx](https://www.npmjs.com/package/@babel/plugin-transform-react-jsx) and [@babel/core](https://www.npmjs.com/package/@babel/core).
##### setRawMode
The `<Color>` compoment is a simple wrapper around [the `chalk` API](https://github.com/chalk/chalk#api) it supports all of the chalk methods as `props`.
Type: `function`<br>
See [setRawMode](https://nodejs.org/api/tty.html#tty_readstream_setrawmode_mode).
Ink exposes this function via own `<StdinContext>` to be able to handle <kbd>Ctrl</kbd>+<kbd>C</kbd>, that's why you should use Ink's `setRawMode` instead of `process.stdin.setRawMode`.
Usage:
```jsx
import {Color} from 'ink';
<StdinContext.Consumer>
{({ setRawMode }) => (
<MyComponent setRawMode={setRawMode}/>
)}
</StdinContext.Consumer>
```
<Color rgb={[255, 255, 255]} bgKeyword="magenta">
Hello!
</Color>
#### <StdoutContext>
<Color hex="#000000" bgHex="#FFFFFF">
Hey there
</Color>
`<StdoutContext>` is a [React context](https://reactjs.org/docs/context.html#reactcreatecontext), which exposes stdout stream, where Ink renders your app.
Import:
```js
import {StdoutContext} from 'ink';
```
The `<Bold>` and `<Underline>` components render their children bolded and underlined respectively.
##### stdout
```jsx
import {Bold, Underline} from 'ink';
Type: `Stream`<br>
Default: `process.stdout`
<Bold>
I am bold
</Bold>
Usage:
<Underline>
I am underlined
</Underline>
```jsx
<StdoutContext.Consumer>
{({ stdout }) => (
<MyComponent stdout={stdout}/>
)}
</StdoutContext.Consumer>
```

@@ -617,0 +620,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