Socket
Socket
Sign inDemoInstall

regl

Package Overview
Dependencies
Maintainers
1
Versions
42
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

regl - npm Package Compare versions

Comparing version 0.4.0 to 0.5.0

coverage/coverage.json

66

CHANGES.md

@@ -5,16 +5,51 @@ # Release notes

* Add a mechanism for requiring/selectively disabling extensions
* Upgrade vertex pointer format, allow for implicit conversion from arrays
* Improve validation of vertex attributes
* Refactor attributeState, some names are inconsistent and code is too complex
* Change buffer and texture APIs to separate data from rest of options (or maybe not?)
* Add in place update methods to buffers and textures
* Add support for polling buffers and animated GIFs (useful for web audio)
* Cubic framebuffer objects
* More unit tests, improve code coverage
* Support fixed scopes as arguments
* Support directly constructing elements and attributes from arrays
* Code generation rewrite
+ per-batch contexts
+ Allow for batch scopes
+ Stop using stacks for managing states, save state locally in command
* Error reporting
+ All error messages should link to command/resource declaration
+ Improve validation of vertex attributes
+ Improve validation of dynamic properties
* Resource API improvements
+ Add in place update methods to buffers and textures
+ Add support for polling buffers and animated GIFs (useful for web audio)
* Implement a standard method for handling context creation errors
* Add a mechanism for managing webgl extensions
+ Should be able to report errors when extensions are missing
+ Allow users to disable extensions for testing/mocking
* Cubic frame buffer objects
* WebVR support and integration (need to think how this will work)
* Documentation
+ Write "regl for react programmers"
+ Rewrite resource section, bring individual resources to the top
* Code quality and management
+ Refactor attributeState, some names are inconsistent and code is too complex
+ Update development documentation
+ Add contributing guidelines and code of conduct
* Testing
+ Instancing
+ Texture generation
+ Framebuffers
+ Element buffer rendering primitives
+ Constant attributes
+ Viewport change notifications
+ RAF/frame behavior
+ Complete coverage for all code generation pathways
+ Test weird invocation sequences
* Benchmark suite
* Optimize generated code
* Optimize bundle size, remove string constants
+ Dashboard for test cases and benchmarks
+ Create some more typical drawing examples
* Optimization
+ Save environment and this variables across batch mode invocations
+ Kill all VM bailouts on all major platforms
+ Kill all garbage collection
+ Optimize generated code
+ Optimize bundle size, remove string constants
* Support more DDS texture formats (HDR, PVRTC, etc.)
* Build a website (@freeman-lab is on it!)
* Render to glTF (maybe?), could be useful for dumping previews
* Recipe book/example set

@@ -33,2 +68,11 @@ + Minecraft example

## 0.5.0
* Context variables
* Use `this` argument effectively
* Should pass this to dynamic attributes and scope
* Make scopes and dynamic attributes take same argument
* Combine batchId with stats argument
* Pass `this` to draw commands so that they can be stored as members
## 0.4.0

@@ -35,0 +79,0 @@

52

DEVELOPING.md

@@ -5,42 +5,50 @@ # Build environment

`regl` uses [standard](https://github.com/feross/standard) style
* `regl` ahderes to the [standard](https://github.com/feross/standard) style.
* Write all test cases, benchmarks and library code using strict ES5 style.
* Write examples using ES6
## Testing
## Development set up
regl uses [tape](https://www.npmjs.com/package/tape)
* To set up the development environment for regl, you first need to install [nodejs](https://nodejs.org/en/). Any version >0.10 is supported.
* Once this is done, you can install regl's development dependencies using the following npm command:
### Running tests
```
npm install
```
#### In node
With headless-gl, you can just do:
## Testing and benchmarks
* regl uses [tape](https://www.npmjs.com/package/tape) for unit testing
* To run the test cases in node, use the following command:
```
npm run test
```
Which should run all test cases
#### In the browser
* To run the test cases in your web browser, use:
```
npm run test-browser
```
### Adding tests
### Test coverage
* To add a test case, create a new file in the `test/` folder and then add a reference to it in `test/util/index.js`
* To generate a code coverage report, you can run the following command. A report webpage will the be generated in `coverage/lcov-report/index.html`
```
npm run coverage
```
* To run benchmarks, use this command:
```
npm run bench
```
* The easiest way to add a new benchmark is to copy an existing benchmark (see for example `bench/clear.js`), modify it, and add an entry to `bench/list.js`
## Benchmarks
## Building
### Running benchmarks
* To rebuild all redistributable assets and the static website, use the command:
```
npm run bench
npm run build
```
* If you just want to modify the examples, you can do
```
npm run build-gallery
```
### Adding benchmarks
Copy an existing benchmark (see for example `bench/clear.js`) and add it to `bench/list.js`
## How to help out
Check out the [change log](CHANGES.md) for planned features and tasks. Alternatively, if you want to propose a new feature or report a bug, you should open an issue on GitHub.

@@ -43,3 +43,3 @@ var glTypes = require('./constants/dtypes.json')

left.normalized === right.normalized &&
left.type === right.type &&
left.type === (right.type || right.buffer.dtype || GL_FLOAT) &&
left.offset === right.offset &&

@@ -57,3 +57,3 @@ left.stride === right.stride &&

left.normalized = right.normalized
left.type = right.type
left.type = right.type || right.buffer.dtype || GL_FLOAT
left.offset = right.offset

@@ -95,17 +95,11 @@ left.stride = right.stride

if (!next.pointer) {
if (current.pointer) {
gl.disableVertexAttribArray(index)
}
gl.disableVertexAttribArray(index)
gl.vertexAttrib4f(index, next.x, next.y, next.z, next.w)
} else {
if (!current.pointer) {
gl.enableVertexAttribArray(index)
}
if (current.buffer !== next.buffer) {
next.buffer.bind()
}
gl.enableVertexAttribArray(index)
next.buffer.bind()
gl.vertexAttribPointer(
index,
size,
next.type,
next.type || next.buffer.dtype || GL_FLOAT,
next.normalized,

@@ -168,3 +162,3 @@ next.stride,

var normalized = false
var type = GL_FLOAT
var type = 0
if (!buffer) {

@@ -179,8 +173,6 @@ buffer = bufferState.getBuffer(data.buffer)

normalized = data.normalized || false
type = buffer.dtype
type = 0
if ('type' in data) {
type = glTypes[data.type]
}
} else {
type = buffer.dtype
}

@@ -187,0 +179,0 @@ box.pointer = true

@@ -70,3 +70,3 @@ // Array and element buffer creation

module.exports = function wrapBufferState (gl) {
module.exports = function wrapBufferState (gl, unbindBuffer) {
var bufferCount = 0

@@ -91,2 +91,3 @@ var bufferSet = {}

function refresh (buffer) {
unbindBuffer(buffer)
if (!gl.isBuffer(buffer.buffer)) {

@@ -102,2 +103,3 @@ buffer.buffer = gl.createBuffer()

check(handle, 'buffer must not be deleted already')
unbindBuffer(buffer)
if (gl.isBuffer(handle)) {

@@ -104,0 +106,0 @@ gl.deleteBuffer(handle)

@@ -50,2 +50,7 @@ var check = require('./util/check')

var DYN_FUNC = 0
var DYN_PROP = 1
var DYN_CONTEXT = 2
var DYN_STATE = 3
var blendFuncs = {

@@ -203,3 +208,3 @@ '0': 0,

drawState,
frameState,
context,
reglPoll) {

@@ -357,3 +362,3 @@ var contextState = glState.contextState

var BIND_ATTRIBUTE_RECORD = link(attributeState.bindRecord)
var FRAME_STATE = link(frameState)
var CONTEXT = link(context)
var FRAMEBUFFER_STATE = link(framebufferState)

@@ -408,8 +413,19 @@ var DRAW_STATE = {

}
if (x.func) {
result = batch.def(
link(x.data), '(', ARG, ',', BATCH_ID, ',', FRAME_STATE, ')')
} else {
result = batch.def(ARG, '.', x.data)
switch (x.type) {
case DYN_FUNC:
result = batch.def(
link(x.data), '.call(this,', ARG, ',', CONTEXT, ')')
break
case DYN_PROP:
result = batch.def(ARG, x.data)
break
case DYN_CONTEXT:
result = batch.def(CONTEXT, x.data)
break
case DYN_STATE:
result = batch.def('this', x.data)
break
}
dynamicVars[id] = result

@@ -485,3 +501,4 @@ return result

'for(', BATCH_ID, '=0;', BATCH_ID, '<', NUM_ARGS, ';++', BATCH_ID, '){',
ARG, '=', ARGS, '[', BATCH_ID, '];')
ARG, '=', ARGS, '[', BATCH_ID, '];',
CONTEXT, '.batchId=', BATCH_ID, ';')

@@ -818,11 +835,11 @@ // -------------------------------

// ===================================================
// ===================================================
// ===========================================================================
// ===========================================================================
// MAIN DRAW COMMAND
// ===================================================
// ===================================================
// ===========================================================================
// ===========================================================================
function compileCommand (
staticOptions, staticUniforms, staticAttributes,
dynamicOptions, dynamicUniforms, dynamicAttributes,
hasDynamic) {
contextVars, hasDynamic) {
// Create code generation environment

@@ -852,2 +869,3 @@ var env = createEnvironment()

var STENCIL_OPS = link(stencilOps)
var CONTEXT = link(context)

@@ -871,3 +889,46 @@ var CONTEXT_STATE = {}

var DYNARGS
if (hasDynamic) {
DYNARGS = entry.def()
}
// -------------------------------
// update context variables
// -------------------------------
// Initialize batch id
entry(CONTEXT, '.batchId=0;')
var contextEnter = block()
Object.keys(contextVars.static).forEach(function (contextVar) {
var PREV_VALUE = entry.def(CONTEXT, '.', contextVar)
contextEnter(CONTEXT, '.', contextVar, '=',
link(contextVars.static[contextVar]), ';')
exit(CONTEXT, '.', contextVar, '=', PREV_VALUE, ';')
})
Object.keys(contextVars.dynamic).forEach(function (contextVar) {
var PREV_VALUE = entry.def(CONTEXT, '.', contextVar)
var NEXT_VALUE = entry.def()
var x = contextVars.dynamic[contextVar]
contextEnter(CONTEXT, '.', contextVar, '=', NEXT_VALUE, ';')
switch (x.type) {
case DYN_FUNC:
entry(NEXT_VALUE, '=', link(x.data), '.call(this,', DYNARGS, ',', CONTEXT, ');')
break
case DYN_PROP:
entry(NEXT_VALUE, '=', DYNARGS, x.data, ';')
break
case DYN_CONTEXT:
entry(NEXT_VALUE, '=', CONTEXT, x.data, ';')
break
case DYN_STATE:
entry(NEXT_VALUE, '=', 'this', x.data, ';')
break
}
exit(CONTEXT, '.', contextVar, '=', PREV_VALUE, ';')
})
entry(contextEnter)
// -------------------------------
// update default context state variables

@@ -1227,9 +1288,2 @@ // -------------------------------

var FRAMESTATE
var DYNARGS
if (hasDynamic) {
FRAMESTATE = link(frameState)
DYNARGS = entry.def()
}
var dynamicVars = {}

@@ -1242,7 +1296,16 @@ function dyn (x) {

}
if (x.func) {
result = dynamicEntry.def(
link(x.data), '(', DYNARGS, ',0,', FRAMESTATE, ')')
} else {
result = dynamicEntry.def(DYNARGS, '.', x.data)
switch (x.type) {
case DYN_FUNC:
result = dynamicEntry.def(
link(x.data), '.call(this,', DYNARGS, ',', CONTEXT, ')')
break
case DYN_PROP:
result = dynamicEntry.def(DYNARGS, x.data)
break
case DYN_CONTEXT:
result = dynamicEntry.def(CONTEXT, x.data)
break
case DYN_STATE:
result = dynamicEntry.def('this', x.data)
break
}

@@ -1498,10 +1561,11 @@ dynamicVars[id] = result

var SCOPE_BODY = scope.arg()
if (hasDynamic) {
scope(DYNARGS, '=', SCOPE_ARGS, ';')
}
scope(entry)
if (hasDynamic) {
scope(
DYNARGS, '=', SCOPE_ARGS, ';',
dynamicEntry)
scope(dynamicEntry)
}
scope(
SCOPE_BODY, '();',
SCOPE_BODY, '(', SCOPE_ARGS, ',', CONTEXT, ');',
hasDynamic ? dynamicExit : '',

@@ -1533,7 +1597,8 @@ exit)

var draw = proc('draw')
if (hasDynamic) {
draw(DYNARGS, '=', draw.arg(), ';')
}
draw(entry, commonDraw)
if (hasDynamic) {
draw(
DYNARGS, '=', draw.arg(), ';',
dynamicEntry)
draw(dynamicEntry)
}

@@ -1543,3 +1608,3 @@ draw(

'if(', CURRENT_PROGRAM, ')',
CURRENT_PROGRAM, '.draw(', hasDynamic ? DYNARGS : '', ');',
CURRENT_PROGRAM, '.draw.call(this', hasDynamic ? ',' + DYNARGS : '', ');',
hasDynamic ? dynamicExit : '',

@@ -1552,2 +1617,7 @@ exit)

var batch = proc('batch')
var BATCH_COUNT = batch.arg()
var BATCH_ARGS = batch.arg()
if (hasDynamic) {
batch(DYNARGS, '=', BATCH_ARGS, '[0];')
}
batch(entry, commonDraw)

@@ -1561,3 +1631,3 @@ var EXEC_BATCH = link(function (program, count, args) {

}
return proc(count, args)
return proc.call(this, count, args)
})

@@ -1567,6 +1637,6 @@ batch(

GL_POLL, '();',
EXEC_BATCH, '(',
EXEC_BATCH, '.call(this,',
CURRENT_PROGRAM, ',',
batch.arg(), ',',
batch.arg(), ');')
BATCH_COUNT, ',',
BATCH_ARGS, ');')
// Set dirty on all dynamic flags

@@ -1573,0 +1643,0 @@ Object.keys(dynamicOptions).forEach(function (option) {

@@ -0,10 +1,58 @@

var check = require('./util/check')
var VARIABLE_COUNTER = 0
function DynamicVariable (isFunc, data) {
var DYN_FUNC = 0
var DYN_PENDING_FLAG = 128
function DynamicVariable (type, data) {
this.id = (VARIABLE_COUNTER++)
this.func = isFunc
this.type = type
this.data = data
}
function defineDynamic (data, path) {
function escapeStr (str) {
return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"')
}
function splitParts (str) {
if (str.length === 0) {
return []
}
var firstChar = str.charAt(0)
var lastChar = str.charAt(str.length - 1)
if (str.length > 1 &&
firstChar === lastChar &&
(firstChar === '"' || firstChar === "'")) {
return ['"' + escapeStr(str.substr(1, str.length - 2)) + '"']
}
var parts = /\[(false|true|null|\d+|'[^']*'|"[^"]*")\]/.exec(str)
if (parts) {
return (
splitParts(str.substr(0, parts.index))
.concat(splitParts(parts[1]))
.concat(splitParts(str.substr(parts.index + parts[0].length)))
)
}
var subparts = str.split('.')
if (subparts.length === 1) {
return ['"' + escapeStr(str) + '"']
}
var result = []
for (var i = 0; i < subparts.length; ++i) {
result = result.concat(splitParts(subparts[i]))
}
return result
}
function toAccessorString (str) {
return '[' + splitParts(str).join('][') + ']'
}
function defineDynamic (type, data) {
switch (typeof data) {

@@ -14,7 +62,9 @@ case 'boolean':

case 'string':
return new DynamicVariable(false, data)
case 'function':
return new DynamicVariable(true, data)
return new DynamicVariable(type, toAccessorString(data + ''))
case 'undefined':
return new DynamicVariable(type | DYN_PENDING_FLAG, null)
default:
return defineDynamic
check.raise('invalid property type')
}

@@ -30,8 +80,11 @@ }

if (x instanceof DynamicVariable) {
return x
} else if (typeof x === 'function' &&
x !== defineDynamic) {
return new DynamicVariable(true, x)
if (x.type & DYN_PENDING_FLAG) {
return new DynamicVariable(
x.type & ~DYN_PENDING_FLAG,
toAccessorString(path))
}
} else if (typeof x === 'function') {
return new DynamicVariable(DYN_FUNC, x)
}
return new DynamicVariable(false, path)
return x
}

@@ -42,3 +95,4 @@

isDynamic: isDynamic,
unbox: unbox
unbox: unbox,
accessor: toAccessorString
}

@@ -5,2 +5,3 @@ var isTypedArray = require('./is-typed-array')

return (
!!obj &&
typeof obj === 'object' &&

@@ -7,0 +8,0 @@ Array.isArray(obj.shape) &&

{
"name": "regl",
"version": "0.4.0",
"version": "0.5.0",
"description": "WebGL",

@@ -19,3 +19,3 @@ "main": "regl.js",

"canvas-orbit-camera": "^1.0.2",
"coverify": "^1.4.1",
"codacy-coverage": "^1.1.3",
"falafel": "^1.2.0",

@@ -29,2 +29,3 @@ "faucet": "0.0.1",

"indexhtmlify": "^1.2.1",
"istanbul": "^0.4.3",
"mkdirp": "^0.5.1",

@@ -34,3 +35,2 @@ "mouse-change": "^1.3.0",

"runscript": "^1.1.0",
"smokestack": "^3.4.1",
"snazzy": "^3.0.0",

@@ -44,5 +44,5 @@ "standard": "^6.0.7",

"scripts": {
"test": "standard | snazzy && tape test/*.js | faucet",
"test": "standard | snazzy && tape test/util/index.js | faucet",
"test-browser": "budo test/util/browser.js --open",
"coverage": "browserify test/util/browser.js -t coverify | smokestack | coverify",
"cover": "istanbul cover test/util/index.js",
"bench": "budo bench/index.js --open",

@@ -49,0 +49,0 @@ "build": "npm run build-script && npm run build-min && npm run build-bench && npm run build-gallery",

# regl
[![Join the chat at https://gitter.im/ark-lang/ark](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mikolalysenko/regl) [![Circle CI](https://circleci.com/gh/mikolalysenko/regl.svg?style=svg)](https://circleci.com/gh/mikolalysenko/regl) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/)
[![Join the chat at https://gitter.im/ark-lang/ark](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mikolalysenko/regl) [![Circle CI](https://circleci.com/gh/mikolalysenko/regl.svg?style=shield)](https://circleci.com/gh/mikolalysenko/regl) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/)
[![npm version](https://badge.fury.io/js/regl.svg)](https://badge.fury.io/js/regl) ![file size](https://badge-size.herokuapp.com/mikolalysenko/regl/gh-pages/dist/regl.min.js.svg?compression=gzip)

@@ -191,3 +192,3 @@ This repo is an attempt at building new functional abstractions for working with WebGL. It is still **experimental**, so expect things to change a lot in the near future! If you want to know more about why I am writing this thing and why it looks the way it does, take a look at the [rationale](RATIONALE.md).

Development supported by the [Freeman Lab](https://www.janelia.org/lab/freeman-lab) and the Howard Hughes Medical Institute (@freeman-lab on GitHub)
Development supported by the [Freeman Lab](https://www.janelia.org/lab/freeman-lab) and the Howard Hughes Medical Institute ([@freeman-lab](https://github.com/freeman-lab) on GitHub)

@@ -199,4 +200,4 @@ ### Asset licenses

* Cube maps (posx.jpeg, negx.jpeg, posy.jpeg, negy.jpeg, posz.jpeg, negz.jpeg) by [Humus](http://www.humus.name/index.php?page=Textures), used under creative commons 3 license
* Environment map of Oregon (ogd-oregon-360.jpg) due to Max Ogden (@ogd on GitHub)
* Environment map of Oregon (ogd-oregon-360.jpg) due to Max Ogden ([@maxogd](https://github.com/maxogden) on GitHub)
* DDS test images (alpine_cliff_a, alpine_cliff_a_norm, alpine_cliff_a_spec) taken from the CC0 license [0-AD texture pack by Wildfire games](http://opengameart.org/content/0-ad-textures)
* Tile set for tile mapping demo (tiles.png) from CC0 licensed [cobblestone paths pack](http://opengameart.org/content/rpg-tiles-cobble-stone-paths-town-objects)
var check = require('./lib/util/check')
var extend = require('./lib/util/extend')
var getContext = require('./lib/context')
var initWebGL = require('./lib/webgl')
var createStringStore = require('./lib/strings')

@@ -34,4 +34,8 @@ var wrapExtensions = require('./lib/extension')

var DYN_PROP = 1
var DYN_CONTEXT = 2
var DYN_STATE = 3
module.exports = function wrapREGL () {
var args = getContext(Array.prototype.slice.call(arguments))
var args = initWebGL(Array.prototype.slice.call(arguments))
var gl = args.gl

@@ -54,3 +58,3 @@ var options = args.options

var bufferState = wrapBuffers(gl)
var bufferState = wrapBuffers(gl, unbindBuffer)

@@ -104,7 +108,9 @@ var elementState = wrapElements(

var startTime = clock()
var frameState = {
count: 0,
start: clock(),
start: startTime,
dt: 0,
t: clock(),
t: startTime,
renderTime: 0,

@@ -116,2 +122,14 @@ width: gl.drawingBufferWidth,

var context = {
count: 0,
batchId: 0,
deltaTime: 0,
time: 0,
viewportWidth: frameState.width,
viewportHeight: frameState.height,
drawingBufferWidth: frameState.width,
drawingBufferHeight: frameState.height,
pixelRatio: frameState.pixelRatio
}
var glState = wrapContext(

@@ -138,5 +156,17 @@ gl,

drawState,
frameState,
context,
poll)
function unbindBuffer (buffer) {
for (var i = 0; i < attributeState.bindings.length; ++i) {
var attr = attributeState.bindings[i]
if (attr.pointer && attr.buffer === buffer) {
attr.pointer = false
attr.buffer = null
attr.x = attr.y = attr.z = attr.w = NaN
gl.disableVertexAttribArray(i)
}
}
}
var canvas = gl.canvas

@@ -149,7 +179,12 @@

frameState.count += 1
context.count = frameState.count
if (frameState.width !== gl.drawingBufferWidth ||
frameState.height !== gl.drawingBufferHeight) {
frameState.width = gl.drawingBufferWidth
frameState.height = gl.drawingBufferHeight
context.viewportWidth =
context.drawingBufferWidth =
frameState.width = gl.drawingBufferWidth
context.viewportHeight =
context.drawingBufferHeight =
frameState.height = gl.drawingBufferHeight
glState.notifyViewportChanged()

@@ -162,2 +197,5 @@ }

context.deltaTime = frameState.dt / 1000.0
context.time = (now - startTime) / 1000.0
textureState.poll()

@@ -167,3 +205,3 @@

var cb = rafCallbacks[i]
cb(frameState.count, frameState.t, frameState.dt)
cb(null, context)
}

@@ -243,2 +281,3 @@ frameState.renderTime = clock() - now

delete result.attributes
delete result.context

@@ -283,2 +322,4 @@ function merge (name) {

// Treat context variables separate from other dynamic variables
var context = separateDynamic(options.context || {})
var uniforms = separateDynamic(options.uniforms || {})

@@ -291,3 +332,3 @@ var attributes = separateDynamic(options.attributes || {})

opts.dynamic, uniforms.dynamic, attributes.dynamic,
hasDynamic)
context, hasDynamic)

@@ -310,5 +351,5 @@ var draw = compiled.draw

if (typeof args === 'function') {
return scope(null, args)
return scope.call(this, null, args)
} else if (typeof body === 'function') {
return scope(args, body)
return scope.call(this, args, body)
}

@@ -330,7 +371,7 @@

if (typeof args === 'number') {
return batch(args | 0, reserve(args | 0))
return batch.call(this, args | 0, reserve(args | 0))
} else if (Array.isArray(args)) {
return batch(args.length, args)
return batch.call(this, args.length, args)
}
return draw(args)
return draw.call(this, args)
}

@@ -396,4 +437,6 @@

// Short cut for prop binding
prop: dynamic.define,
// Short cuts for dynamic variables
prop: dynamic.define.bind(null, DYN_PROP),
context: dynamic.define.bind(null, DYN_CONTEXT),
this: dynamic.define.bind(null, DYN_STATE),

@@ -400,0 +443,0 @@ // executes an empty draw command

Sorry, the diff of this file is too big to display

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