Socket
Socket
Sign inDemoInstall

aerogel

Package Overview
Dependencies
15
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.0.2 to 0.0.3

lib/parameters.js

87

examples/telemetry.js

@@ -1,61 +0,28 @@

var
Aerogel = require('../index')
;
var Aerogel = require('../index');
var driver = new Aerogel.CrazyDriver();
var copter = new Aerogel.Copter(driver);
process.on('SIGINT', copter.land.bind(copter));
var params;
process.on('SIGINT', bail);
console.log('telemetry logging...');
console.log('just connecting & sitting to log some telemetry info...');
function shutItDown()
function bail()
{
console.log('shutting down');
copter.shutdown()
.then(function(response)
console.log('entered bail()');
return copter.shutdown()
.then(function()
{
console.log('shutting down:', response);
process.exit(0);
return process.exit(0);
})
.fail(function(err)
{
console.log('error: ', err);
copter.shutdown()
.then(function(response)
{
process.exit(1);
});
})
.done();
}
function flyAndLog()
{
copter.takeoff()
.then(function() { return copter.land(); })
.then(function() { return copter.shutdown(); })
.then(function(response)
{
console.log(response);
process.exit(0);
})
.fail(function(err)
{
console.log(err);
copter.shutdown()
.then(function(response)
{
console.log(response);
process.exit(1);
});
copter.shutdown();
return process.exit(0);
})
.done();
}
copter.on('ready', function()
{
setTimeout(shutItDown, 20000);
});
setTimeout(bail, 30000);

@@ -79,4 +46,30 @@ driver.findCopters()

})
.then(function()
{
console.log('got all telemetry & parameters');
params = copter.driver.parameters.all();
console.log(params);
return copter.driver.parameters.get('pid_attitude.yaw_kd');
})
.then(function(value)
{
console.log('pid_attitude.yaw_kd:', value);
return copter.shutdown();
})
.then(function(response)
{
console.log('Shutdown complete.');
process.exit(0);
})
.fail(function(err)
{
console.log(err);
copter.shutdown()
.then(function(response)
{
console.log(response);
process.exit(1);
});
})
.done();

@@ -45,12 +45,15 @@ var

{
var self = this;
var self = this,
deferred = P.defer();
self.copterStates.connect();
return self.driver.connect(uri)
self.driver.connect(uri)
.then(function()
{
self.driver.onStabilizerTelemetry(self.handleStabilizerTelemetry.bind(self));
self.driver.onMotorTelemetry(self.handleMotorTelemetry.bind(self));
self.driver.telemetry.subscribe('motor', self.handleMotorTelemetry.bind(self));
self.driver.telemetry.subscribe('stabilizer', self.handleStabilizerTelemetry.bind(self));
self.driver.telemetry.subscribe('accelerometer', self.handleAccTelemetry.bind(self));
self.copterStates.ready();
self.emit('ready');
deferred.resolve('ready');
})

@@ -61,4 +64,7 @@ .fail(function(err)

self.emit('error', err);
deferred.reject(err);
})
.done();
return deferred.promise;
};

@@ -72,4 +78,2 @@

console.log('takeoff()');
this.copterStates.takeoff();

@@ -220,3 +224,3 @@ this.pulseTimer = setInterval(this.pulse.bind(this), 100);

{
console.log('entering', current, 'from', previous);
console.log('STATE CHANGE:', previous, '-->', current);
};

@@ -303,3 +307,2 @@ };

case 'flying':
console.log(data.thrust, this.currentSetpoint.thrust);
/*

@@ -365,2 +368,7 @@ var diff = data.yaw - this.goal.yaw;

Copter.prototype.handleAccTelemetry = function(data)
{
// console.log('acc:', data);
};
Copter.prototype.shutdown = function()

@@ -367,0 +375,0 @@ {

// Crazy Real Time Protocol Driver
// This module knows how to format messages for the crazy radio and the copter.
// There's some repetition because the emphasis is on provding a clear, readable
// API to higher levels.

@@ -12,6 +14,8 @@ var

Crazypacket = require('./crazypacket'),
Parameters = require('./parameters'),
Protocol = require('./protocol'),
Telemetry = require('./telemetry')
;
function CrazyDriver(name)
var CrazyDriver = module.exports = function CrazyDriver(name)
{

@@ -23,5 +27,5 @@ events.EventEmitter.call(this);

this.datarate = 2;
this.queue = [];
this.telemetry = new Telemetry(this);
}
this.parameters = new Parameters(this);
};
util.inherits(CrazyDriver, events.EventEmitter);

@@ -37,3 +41,3 @@

return self.radio.setupRadio()
.then(self.radio.setAckRetryCount(1))
.then(function() { return self.radio.setAckRetryCount(1); })
.then(function() { return self.scanAtRate(0); })

@@ -94,5 +98,3 @@ .then(function(res1)

for (var i = 0; i < result.length; i++)
{
copters.push(util.format('radio://1/%d/%s', result[i], CrazyDriver.DATARATE[datarate]));
}

@@ -131,2 +133,5 @@ return copters;

this.radio.addListener('logging', this.telemetry.handlePacket.bind(this.telemetry));
this.radio.addListener('param', this.parameters.handlePacket.bind(this.parameters));
this.channel = parseInt(pieces[1], 10);

@@ -136,3 +141,7 @@ return self.radio.setupRadio(null, self.channel, self.datarate)

{
return self.startTelemetry();
return self.startTelemetry(); // completion required for flight
})
.then(function()
{
return self.fetchParameters();
});

@@ -163,5 +172,4 @@ };

var packet = new Crazypacket();
packet.port = Crazypacket.Ports.COMMANDER;
packet.port = Protocol.Ports.COMMANDER;
// first byte is for the header data
packet.writeFloat(roll)

@@ -176,3 +184,2 @@ .writeFloat(-pitch)

{
// console.log(item);
return item;

@@ -188,58 +195,104 @@ })

// parameter functions: get list, set, get
// telemetry aka logging functions
CrazyDriver.prototype.startTelemetry = function()
CrazyDriver.prototype.fetchParameters = function()
{
this.telemetryDeferred = P.defer();
this.radio.addListener('logging', this.telemetry.handlePacket.bind(this.telemetry));
this.requestTOC();
return this.telemetryDeferred.promise;
var self = this;
this.parametersDeferred = P.defer();
this.requestTOC(Protocol.Ports.PARAM);
return this.parametersDeferred.promise;
};
CrazyDriver.prototype.telemetryReady = function()
CrazyDriver.prototype.parametersDone = function()
{
this.telemetryDeferred.resolve('OK');
if (!this.parametersDeferred) return;
this.parametersDeferred.resolve('OK');
this.parametersDeferred = undefined;
};
CrazyDriver.prototype.onStabilizerTelemetry = function(subfunc)
CrazyDriver.prototype.getParameter = function(param)
{
this.telemetry.addSubscriber(subfunc, 'stabilizer');
var packet = new Crazypacket();
packet.port = Protocol.Ports.PARAM;
packet.channel = Protocol.Channels.PARAM_READ;
packet.writeByte(param);
packet.endPacket();
return this.radio.sendPacket(packet);
};
CrazyDriver.prototype.onMotorTelemetry = function(subfunc)
CrazyDriver.prototype.setParameter = function(param, value)
{
this.telemetry.addSubscriber(subfunc, 'motor');
var packet = new Crazypacket();
packet.port = Protocol.Ports.PARAM;
packet.channel = Protocol.Channels.PARAM_WRITE;
packet.writeByte(param.id)
.writeType(param.type, value)
.endPacket();
return this.radio.sendPacket(packet);
};
CrazyDriver.prototype.requestTOC = function()
// telemetry, which the Crazy protocol calls "logging"
CrazyDriver.prototype.startTelemetry = function()
{
console.log('starting telemetry');
var self = this;
this.telemetryDeferred = P.defer();
var packet = new Crazypacket();
packet.port = Crazypacket.Ports.LOGGING;
packet.channel = Crazypacket.Channels.SETTINGS;
packet.writeByte(Crazypacket.Commands.RESET_LOGGING);
packet.port = Protocol.Ports.LOGGING;
packet.channel = Protocol.Channels.SETTINGS;
packet.writeByte(Protocol.Commands.RESET_LOGGING);
packet.endPacket();
return self.radio.sendPacket(packet)
this.radio.sendPacket(packet)
.then(function()
{
packet = new Crazypacket();
packet.port = Crazypacket.Ports.LOGGING;
packet.channel = Crazypacket.Channels.TOC;
packet.writeByte(Crazypacket.Commands.GET_INFO);
packet.endPacket();
self.requestTOC(Protocol.Ports.LOGGING);
});
return self.radio.sendPacket(packet);
});
return this.telemetryDeferred.promise;
};
CrazyDriver.prototype.telemetryReady = function()
{
if (!this.telemetryDeferred) return;
this.telemetryDeferred.resolve('OK');
this.telemetryDeferred = undefined;
};
// ---------------------
// now the heavy lifting
CrazyDriver.prototype.requestTOC = function(which)
{
var packet = new Crazypacket();
packet.port = which;
packet.channel = Protocol.Channels.TOC;
packet.writeByte(Protocol.Commands.GET_INFO);
packet.endPacket();
return this.radio.sendPacket(packet);
};
// request details about a specific parameter or telemetry item
CrazyDriver.prototype.requestTelemetryElement = function(id)
{
return this.requestTOCItem(Protocol.Ports.LOGGING, id);
};
CrazyDriver.prototype.requestParameter = function(id)
{
return this.requestTOCItem(Protocol.Ports.PARAM, id);
};
CrazyDriver.prototype.requestTOCItem = function(port, id)
{
var packet = new Crazypacket();
packet.port = Crazypacket.Ports.LOGGING;
packet.channel = Crazypacket.Channels.TOC;
packet.writeByte(Crazypacket.Commands.GET_ELEMENT);
packet.port = port;
packet.channel = Protocol.Channels.TOC;
packet.writeByte(Protocol.Commands.GET_ELEMENT);
if (id)

@@ -252,8 +305,11 @@ packet.writeByte(id);

// Create a telemetry block, aka a group of sensor readings that
// get emitted by the copter periodically.
CrazyDriver.prototype.createTelemetryBlock = function(block)
{
var packet = new Crazypacket();
packet.port = Crazypacket.Ports.LOGGING;
packet.channel = Crazypacket.Channels.SETTINGS;
packet.writeByte(Crazypacket.Commands.CREATE_BLOCK)
packet.port = Protocol.Ports.LOGGING;
packet.channel = Protocol.Channels.SETTINGS;
packet.writeByte(Protocol.Commands.CREATE_BLOCK)
.writeByte(block.id);

@@ -275,5 +331,5 @@

var packet = new Crazypacket();
packet.port = Crazypacket.Ports.LOGGING;
packet.channel = Crazypacket.Channels.SETTINGS;
packet.writeByte(Crazypacket.Commands.START_LOGGING)
packet.port = Protocol.Ports.LOGGING;
packet.channel = Protocol.Channels.SETTINGS;
packet.writeByte(Protocol.Commands.START_LOGGING)
.writeByte(block)

@@ -288,7 +344,5 @@ .writeByte(10) // period

{
// TODO record ack stats
// TODO record ack stats-- dropped packets etc
var ack = new Crazypacket.RadioAck(buf);
return P(ack);
};
module.exports = CrazyDriver;

@@ -24,38 +24,88 @@ // Crazyradio should offer a method to take data in, format it properly

// --------------------------------------------
// chainable write methods
// This is sugar so you never have to resize your buffer & to track how many
// bytes we need to write over the radio.
Crazypacket.Ports =
Crazypacket.readType = function(buffer, type, offset)
{
CONSOLE : 0x00,
PARAM : 0x02,
COMMANDER : 0x03,
LOGGING : 0x05,
DEBUGDRIVER : 0x0E,
LINKCTRL : 0x0F,
ALL : 0xFF,
switch(type)
{
case 'uint8_t':
return buffer.readUInt8(offset);
case 'uint16_t':
return buffer.readUInt16(offset);
case 'uint32_t':
return buffer.readUInt32(offset);
case 'uint64_t':
return buffer.readUInt64(offset);
case 'int8_t':
return buffer.readInt8(offset);
case 'int16_t':
return buffer.readInt16(offset);
case 'int32_t':
return buffer.readInt32(offset);
case 'int64_t':
return buffer.readInt64(offset);
case 'float':
return buffer.readFloatLE(offset);
case 'double':
return buffer.readDoubleLE(offset);
default:
// log?
return 0;
}
};
Crazypacket.Channels =
Crazypacket.prototype.writeType = function(type, value)
{
TOC: 0,
SETTINGS: 1,
LOGDATA: 2
};
switch(type)
{
case 'uint8_t':
return this.writeByte(value);
Crazypacket.Commands =
{
CREATE_BLOCK: 0,
APPEND_BLOCK: 1,
DELETE_BLOCK: 2,
START_LOGGING: 3,
STOP_LOGGING: 4,
RESET_LOGGING: 5,
GET_ELEMENT: 0,
GET_INFO: 1
case 'uint16_t':
return this.writeUnsignedShort(value);
case 'uint32_t':
return this.writeUnsignedLong(value);
case 'uint64_t':
return this.writeUnsignedLongLong(value);
case 'int8_t':
return this.writeInt(value);
case 'int16_t':
return this.writeShort(value);
case 'int32_t':
return this.writeLong(value);
case 'int64_t':
return this.writeLongLong(value);
case 'float':
return this.writeFloat(value);
case 'double':
return this.writeDouble(value);
default:
// log?
return this;
}
};
// --------------------------------------------
// chainable write methods
Crazypacket.prototype.resizeBuffer = function()

@@ -81,2 +131,27 @@ {

Crazypacket.prototype.writeDouble = function(value)
{
if (!this._writable)
return;
if (this.pointer + 8 >= this.data.length)
this.resizeBuffer();
this.data.writeDoubleLE(value, this.pointer);
this.pointer += 8;
return this;
};
Crazypacket.prototype.writeByte = function(value)
{
if (!this._writable)
return;
if (this.pointer + 1 >= this.data.length)
this.resizeBuffer();
this.data.writeUInt8(value, this.pointer);
this.pointer++;
return this;
};
Crazypacket.prototype.writeUnsignedShort = function(value)

@@ -94,10 +169,36 @@ {

Crazypacket.prototype.writeByte = function(value)
Crazypacket.prototype.writeUnsignedLong = function(value)
{
if (!this._writable)
return;
if (this.pointer + 4 >= this.data.length)
this.resizeBuffer();
this.data.writeUInt32LE(value, this.pointer);
this.pointer += 4;
return this;
};
Crazypacket.prototype.writeUnsignedLongLong = function(value)
{
if (!this._writable)
return;
if (this.pointer + 8 >= this.data.length)
this.resizeBuffer();
this.data.writeUInt64LE(value, this.pointer);
this.pointer += 8;
return this;
};
//
Crazypacket.prototype.writeInt = function(value)
{
if (!this._writable)
return;
if (this.pointer + 1 >= this.data.length)
this.resizeBuffer();
this.data.writeUInt8(value, this.pointer);
this.data.writeInt8(value, this.pointer);
this.pointer++;

@@ -107,2 +208,39 @@ return this;

Crazypacket.prototype.writeShort = function(value)
{
if (!this._writable)
return;
if (this.pointer + 2 >= this.data.length)
this.resizeBuffer();
this.data.writeInt16LE(value, this.pointer);
this.pointer += 2;
return this;
};
Crazypacket.prototype.writeLong = function(value)
{
if (!this._writable)
return;
if (this.pointer + 4 >= this.data.length)
this.resizeBuffer();
this.data.writeInt32LE(value, this.pointer);
this.pointer += 4;
return this;
};
Crazypacket.prototype.writeLongLong = function(value)
{
if (!this._writable)
return;
if (this.pointer + 8 >= this.data.length)
this.resizeBuffer();
this.data.writeInt64LE(value, this.pointer);
this.pointer += 8;
return this;
};
// ready to write over the radio...
Crazypacket.prototype.endPacket = function()

@@ -195,3 +333,3 @@ {

module.exports = Crazypacket;
module.exports = Crazypacket;
Crazypacket.Ack = RadioAck;

@@ -10,2 +10,3 @@ var

Crazypacket = require('./crazypacket'),
Protocol = require('./protocol'),
usbstreams = require('./usbstreams'),

@@ -37,5 +38,2 @@ WritableUSBStream = usbstreams.WritableUSBStream,

// ----- The radio driver
function findCrazyradios()

@@ -51,3 +49,3 @@ {

function Crazyradio()
var Crazyradio = module.exports = function Crazyradio()
{

@@ -68,3 +66,3 @@ events.EventEmitter.call(this);

this.pingTimer = null;
}
};
util.inherits(Crazyradio, events.EventEmitter);

@@ -126,3 +124,2 @@

input.addListener('readable', this.onReadable.bind(this));
input.addListener('end', this.onInputEnd.bind(this));
input.addListener('error', this.onInputError.bind(this));

@@ -325,8 +322,2 @@

/*
We inspect the packet to determinewhich channel it's addressed
to. We then handed off to be parsed further & sent along to any subscribers
to that kind of event.
*/
// console.log('got packet for port ' + ack.packet.port, 'length:', ack.packet.data.length);

@@ -336,19 +327,19 @@

{
case Crazypacket.Ports.CONSOLE:
case Protocol.Ports.CONSOLE:
this.emit('console', ack.packet);
break;
case Crazypacket.Ports.PARAM:
case Protocol.Ports.PARAM:
this.emit('param', ack.packet);
break;
case Crazypacket.Ports.COMMANDER:
case Protocol.Ports.COMMANDER:
this.emit('commander', ack.packet);
break;
case Crazypacket.Ports.LOGGING:
case Protocol.Ports.LOGGING:
this.emit('logging', ack.packet);
break;
case Crazypacket.Ports.LINKCTRL:
case Protocol.Ports.LINKCTRL:
this.emit('linkcontrol', ack);

@@ -370,2 +361,8 @@ break;

console.log('usb stream input error:', err);
this.close()
.then(function()
{
console.log('shutting down following usb error.');
process.exit(0);
});
};

@@ -379,3 +376,2 @@

var d = domain.create();
d.on('error', function(err)

@@ -411,6 +407,2 @@ {

// exports
module.exports = Crazyradio;

@@ -9,3 +9,3 @@ // See the logging section here:

P = require('p-promise'),
Crazypacket = require('./crazypacket')
Protocol = require('./protocol')
;

@@ -35,2 +35,3 @@

this.stabilizerblock = null;
this.accblock = null;
this.nextBlockID = 16;

@@ -45,4 +46,4 @@ this.blocks = {};

{
case Crazypacket.Channels.TOC:
if (packet.payload[0] === Crazypacket.Commands.GET_ELEMENT)
case Protocol.Channels.TOC:
if (packet.payload[0] === Protocol.Commands.GET_ELEMENT)
this.handleTOCElement(packet.payload);

@@ -53,7 +54,7 @@ else

case Crazypacket.Channels.SETTINGS:
case Protocol.Channels.SETTINGS:
this.handleSettings(packet.payload);
break;
case Crazypacket.Channels.LOGDATA:
case Protocol.Channels.LOGDATA:
this.handleBlock(packet.payload);

@@ -73,20 +74,6 @@ break;

var ptr = 1;
// var next = payload[1];
var item = new TelemetryDatum();
item.id = payload[ptr++];
item.type = payload[ptr++];
item.read(payload);
var start = ptr;
while (payload[ptr] !== 0x00)
ptr++;
item.group = payload.slice(start, ptr).toString();
start = ++ptr;
while (payload[ptr] !== 0x00)
ptr++;
item.name = payload.slice(start, ptr).toString();
item.fullname = item.group + '.' + item.name;
// console.log('telemetry variable: ' + item.fullname, item.id, item.type);
console.log('telemetry: ' + item.fullname, item.id, item.type);
this.variables[item.fullname] = item;

@@ -102,4 +89,4 @@

{
this.total = payload[1];
this.CRC = payload.slice(2);
this.total = payload[1] - 1;
this.CRC = payload.readUInt16LE(2);
this.driver.requestTelemetryElement(0);

@@ -112,23 +99,23 @@ };

{
case Crazypacket.Commands.CREATE_BLOCK:
case Protocol.Commands.CREATE_BLOCK:
//console.log('telemetry block ' + payload[1] + ' created: ' + (payload[2] === 0));
break;
case Crazypacket.Commands.APPEND_BLOCK:
case Protocol.Commands.APPEND_BLOCK:
console.log('telemetry block ' + payload[1] + ' appended to: ' + (payload[2] === 0));
break;
case Crazypacket.Commands.DELETE_BLOCK:
case Protocol.Commands.DELETE_BLOCK:
console.log('telemetry block ' + payload[1] + ' deleted: ' + (payload[2] === 0));
break;
case Crazypacket.Commands.START_LOGGING:
case Protocol.Commands.START_LOGGING:
// console.log('telemetry block ' + payload[1] + ' enabled: ' + (payload[2] === 0));
break;
case Crazypacket.Commands.STOP_LOGGING:
case Protocol.Commands.STOP_LOGGING:
console.log('telemetry block ' + payload[1] + ' stopped: ' + (payload[2] === 0));
break;
case Crazypacket.Commands.RESET_LOGGING:
case Protocol.Commands.RESET_LOGGING:
// console.log('telemetry reset: ' + payload.slice(1));

@@ -144,9 +131,13 @@ break;

case this.motorblock:
this.handleMotorTelemetry(payload);
this.handleMotor(payload);
break;
case this.stabilizerblock:
this.handleStabilizerTelemetry(payload);
this.handleStabilizer(payload);
break;
case this.accblock:
this.handleAccelerometer(payload);
break;
default:

@@ -158,3 +149,3 @@ console.log('got telemetry but not ready for it yet; id=', payload[0]);

Telemetry.prototype.addSubscriber = function(subfunc, group)
Telemetry.prototype.subscribe = function(group, subfunc)
{

@@ -173,2 +164,13 @@ switch (group)

case 'accelerometer':
if (!this.variables['acc.x'])
{
console.log('** no accelerometer telemetry available');
return;
}
this.startAccelerometer();
this.addListener('accelerometer', subfunc);
break;
default:

@@ -231,4 +233,29 @@ console.error('warning: cannot subscribe to non-existent telemetry group ' + group);

Telemetry.prototype.handleMotorTelemetry = function(payload)
Telemetry.prototype.startAccelerometer = function()
{
var self = this;
if (this.accblock)
return;
var block =
{
id: this.nextBlockID++,
variables:
[
{ fetchAs: 7, type: this.variables['acc.x'].type, id: this.variables['acc.x'].id },
{ fetchAs: 7, type: this.variables['acc.y'].type, id: this.variables['acc.y'].id },
{ fetchAs: 7, type: this.variables['acc.z'].type, id: this.variables['acc.z'].id },
],
};
this.driver.createTelemetryBlock(block)
.then(function()
{
self.accblock = block.id;
self.driver.enableTelemetryBlock(block.id);
}).done();
};
Telemetry.prototype.handleMotor = function(payload)
{
var update =

@@ -244,9 +271,9 @@ {

Telemetry.prototype.handleStabilizerTelemetry = function(payload)
Telemetry.prototype.handleStabilizer = function(payload)
{
var update =
{
roll: payload.readFloatLE(4),
roll: payload.readFloatLE(4),
pitch: payload.readFloatLE(8),
yaw: payload.readFloatLE(12)
yaw: payload.readFloatLE(12)
};

@@ -256,2 +283,13 @@ this.emit('stabilizer', update);

Telemetry.prototype.handleAccelerometer = function(payload)
{
var update =
{
x: payload.readFloatLE(4),
y: payload.readFloatLE(8),
z: payload.readFloatLE(12)
};
this.emit('accelerometer', update);
};
function TelemetryDatum()

@@ -266,2 +304,21 @@ {

TelemetryDatum.prototype.read = function(payload)
{
var ptr = 1;
this.id = payload[ptr++];
this.type = payload[ptr++];
var start = ptr;
while (payload[ptr] !== 0x00)
ptr++;
this.group = payload.slice(start, ptr).toString();
start = ++ptr;
while (payload[ptr] !== 0x00)
ptr++;
this.name = payload.slice(start, ptr).toString();
this.fullname = this.group + '.' + this.name;
};
module.exports = Telemetry;

@@ -47,3 +47,2 @@ var

console.log(error);
this.endpoint.stopStream();
};

@@ -55,3 +54,2 @@

console.log('readable stream end');
this.endpoint.stopStream();
};

@@ -58,0 +56,0 @@

{
"name": "aerogel",
"version": "0.0.2",
"version": "0.0.3",
"description": "CrazyFlie control software",

@@ -5,0 +5,0 @@ "author": "C J Silverio <ceejceej@gmail.com>",

@@ -8,2 +8,3 @@ aerogel

[![NPM](https://nodei.co/npm/aerogel.png)](https://nodei.co/npm/aerogel/)

@@ -10,0 +11,0 @@ ## Installation

SocketSocket SOC 2 Logo

Product

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc