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

wisp-server-node

Package Overview
Dependencies
Maintainers
0
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

wisp-server-node - npm Package Compare versions

Comparing version 1.1.4 to 1.1.7

dist/utils/Error.d.ts

4

dist/ConnectionHandler.d.ts

@@ -1,5 +0,5 @@

import { WispOptions } from "./Types";
import { IncomingMessage } from "node:http";
import WebSocket from "ws";
import { Socket } from "node:net";
import { IncomingMessage } from "node:http";
import { WispOptions } from "./Types.js";
export declare function routeRequest(wsOrIncomingMessage: WebSocket | IncomingMessage, socket?: Socket, head?: Buffer, options?: WispOptions): Promise<void>;

@@ -6,0 +6,0 @@ declare const _default: {

@@ -25,2 +25,11 @@ "use strict";

};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {

@@ -31,160 +40,163 @@ return (mod && mod.__esModule) ? mod : { "default": mod };

exports.routeRequest = routeRequest;
const Types_1 = require("./Types");
const Logger_1 = require("./Logger");
const ws_1 = __importDefault(require("ws"));
const ws_1 = __importStar(require("ws"));
const node_net_1 = __importDefault(require("node:net"));
const promises_1 = __importDefault(require("node:dns/promises"));
const node_dgram_1 = __importDefault(require("node:dgram"));
const Packets_1 = __importStar(require("./Packets"));
const wsproxy_1 = require("./wsproxy");
const promises_1 = __importDefault(require("node:dns/promises"));
const Utils_1 = require("./Utils");
const wss = new ws_1.default.Server({ noServer: true });
const defaultOptions = { logLevel: Types_1.LOG_LEVEL.INFO };
// Accepts either routeRequest(ws) or routeRequest(request, socket, head) like bare
async function routeRequest(wsOrIncomingMessage, socket, head, options = defaultOptions) {
options = Object.assign({}, defaultOptions, options);
if (!(wsOrIncomingMessage instanceof ws_1.default) && socket && head) {
// Wsproxy is handled here because if we're just passed the websocket then we don't even know it's URL
// Compatibility with bare like "handle upgrade" syntax
wss.handleUpgrade(wsOrIncomingMessage, socket, head, (ws) => {
if (!wsOrIncomingMessage.url?.endsWith("/")) {
// if a URL ends with / then its not a wsproxy connection, its wisp
(0, wsproxy_1.handleWsProxy)(ws, wsOrIncomingMessage.url);
return;
}
routeRequest(ws, undefined, undefined, options);
});
return;
}
if (!(wsOrIncomingMessage instanceof ws_1.default))
return; // something went wrong, abort
const ws = wsOrIncomingMessage; // now that we are SURE we have a Websocket object, continue...
const connections = new Map();
const logger = new Logger_1.Logger(options.logLevel);
ws.on("message", async (data, isBinary) => {
try {
// Ensure that the incoming data is a valid WebSocket message
if (!Buffer.isBuffer(data) && !(data instanceof ArrayBuffer)) {
logger.error("Invalid WebSocket message data");
return;
}
const wispFrame = Packets_1.default.wispFrameParser(Buffer.from(data));
// Routing
if (wispFrame.type === Types_1.CONNECT_TYPE.CONNECT) {
// CONNECT frame data
const connectFrame = Packets_1.default.connectPacketParser(wispFrame.payload);
if (connectFrame.streamType === Types_1.STREAM_TYPE.TCP) {
// Initialize and register Socket that will handle this stream
const client = new node_net_1.default.Socket();
client.connect(connectFrame.port, connectFrame.hostname);
connections.set(wispFrame.streamID, {
client: client,
buffer: 127,
});
// Send Socket's data back to client
client.on("data", function (data) {
ws.send(Packets_1.default.dataPacketMaker(wispFrame, data));
});
// Close stream if there is some network error
client.on("error", function (err) {
logger.error(`An error occured in the connection to ${connectFrame.hostname} (${wispFrame.streamID}) with the message ${err.message}`);
ws.send(Packets_1.default.closePacketMaker(wispFrame, (0, Utils_1.checkErrorCode)(err)));
connections.delete(wispFrame.streamID);
});
client.on("close", function () {
ws.send(Packets_1.default.closePacketMaker(wispFrame, 0x02));
connections.delete(wispFrame.streamID);
});
const Packets_js_1 = __importDefault(require("./Packets.js"));
const Types_js_1 = require("./Types.js");
const Logger_js_1 = require("./utils/Logger.js");
const wsproxy_js_1 = require("./wsproxy.js");
const Error_js_1 = require("./utils/Error.js");
const wss = new ws_1.WebSocketServer({ noServer: true });
const defaultOptions = { logLevel: Types_js_1.LOG_LEVEL.INFO, pingInterval: 30 };
function routeRequest(wsOrIncomingMessage_1, socket_1, head_1) {
return __awaiter(this, arguments, void 0, function* (wsOrIncomingMessage, socket, head, options = defaultOptions) {
options = Object.assign({}, defaultOptions, options);
if (!(wsOrIncomingMessage instanceof ws_1.default) && socket && head) {
wss.handleUpgrade(wsOrIncomingMessage, socket, head, (ws) => {
var _a;
if (!((_a = wsOrIncomingMessage.url) === null || _a === void 0 ? void 0 : _a.endsWith("/"))) {
(0, wsproxy_js_1.handleWsProxy)(ws, wsOrIncomingMessage.url);
return;
}
else if (connectFrame.streamType === Types_1.STREAM_TYPE.UDP) {
let iplevel = node_net_1.default.isIP(connectFrame.hostname); // Can be 0: DNS NAME, 4: IPv4, 6: IPv6
let host = connectFrame.hostname;
if (iplevel === 0) {
// is DNS
try {
host = (await promises_1.default.resolve(connectFrame.hostname))[0];
iplevel = node_net_1.default.isIP(host); // can't be 0 now
routeRequest(ws, undefined, undefined, options);
});
return;
}
if (!(wsOrIncomingMessage instanceof ws_1.default))
return;
const ws = wsOrIncomingMessage;
const connections = new Map();
const logger = new Logger_js_1.Logger(options.logLevel);
const pingInterval = setInterval(() => {
logger.debug(`sending websocket ping`);
ws.ping();
}, options.pingInterval * 1000);
ws.on("message", (data) => __awaiter(this, void 0, void 0, function* () {
try {
if (!Buffer.isBuffer(data) && !(data instanceof ArrayBuffer)) {
logger.error("Invalid WebSocket message data");
return;
}
const wispFrame = Packets_js_1.default.wispFrameParser(Buffer.from(data));
if (wispFrame.type === Types_js_1.PACKET_TYPE.CONNECT) {
const connectFrame = Packets_js_1.default.connectPacketParser(wispFrame.payload);
if (connectFrame.streamType === Types_js_1.STREAM_TYPE.TCP) {
const client = new node_net_1.default.Socket();
client.connect(connectFrame.port, connectFrame.hostname);
connections.set(wispFrame.streamID, {
client: client,
buffer: 127,
});
client.on("data", function (data) {
ws.send(Packets_js_1.default.dataPacketMaker(wispFrame, data));
});
client.on("error", function (err) {
logger.error(`An error occured in the connection to ${connectFrame.hostname} (${wispFrame.streamID}) with the message ${err.message}`);
ws.send(Packets_js_1.default.closePacketMaker(wispFrame, (0, Error_js_1.checkErrorCode)(err)));
connections.delete(wispFrame.streamID);
});
client.on("close", function () {
if (connections.get(wispFrame.streamID)) {
ws.send(Packets_js_1.default.closePacketMaker(wispFrame, 0x02));
connections.delete(wispFrame.streamID);
}
});
}
else if (connectFrame.streamType === Types_js_1.STREAM_TYPE.UDP) {
let iplevel = node_net_1.default.isIP(connectFrame.hostname);
let host = connectFrame.hostname;
if (iplevel === 0) {
try {
host = (yield promises_1.default.resolve(connectFrame.hostname))[0];
iplevel = node_net_1.default.isIP(host);
}
catch (e) {
logger.error("Failure while trying to resolve hostname " +
connectFrame.hostname +
" with error: " +
e);
ws.send(Packets_js_1.default.closePacketMaker(wispFrame, 0x42));
return;
}
}
catch (e) {
logger.error("Failure while trying to resolve hostname " +
connectFrame.hostname +
" with error: " +
e);
ws.send(Packets_1.default.closePacketMaker(wispFrame, 0x42));
return; // we're done here, ignore doing anything to this message now.
if (iplevel !== 4 && iplevel !== 6) {
return;
}
const client = node_dgram_1.default.createSocket(iplevel === 6 ? "udp6" : "udp4");
client.connect(connectFrame.port, host);
client.connected = false;
client.on("connect", () => {
client.connected = true;
});
client.on("message", (data, rinfo) => {
ws.send(Packets_js_1.default.dataPacketMaker(wispFrame, data));
});
client.on("error", (err) => {
logger.error(`An error occured in the connection to ${connectFrame.hostname} (${wispFrame.streamID}) with the message ${err.message}`);
ws.send(Packets_js_1.default.closePacketMaker(wispFrame, (0, Error_js_1.checkErrorCode)(err)));
connections.delete(wispFrame.streamID);
client.close();
});
client.on("close", function () {
if (connections.get(wispFrame.streamID)) {
ws.send(Packets_js_1.default.closePacketMaker(wispFrame, 0x02));
connections.delete(wispFrame.streamID);
}
});
connections.set(wispFrame.streamID, {
client,
});
}
// iplevel is now guaranteed to be 6 or 4, fingers crossed, so we can define the UDP type now
if (iplevel != 4 && iplevel != 6) {
return; // something went wrong.. neither ipv4 nor ipv6
}
if (wispFrame.type === Types_js_1.PACKET_TYPE.DATA) {
const stream = connections.get(wispFrame.streamID);
if (stream && stream.client instanceof node_net_1.default.Socket) {
stream.client.write(wispFrame.payload);
stream.buffer--;
if (stream.buffer === 0) {
stream.buffer = 127;
ws.send(Packets_js_1.default.continuePacketMaker(wispFrame, stream.buffer));
}
}
// Create a new UDP socket
const client = node_dgram_1.default.createSocket(iplevel === 6 ? "udp6" : "udp4");
client.connect(connectFrame.port, host);
//@ts-expect-error stupid workaround
client.connected = false;
client.on("connect", () => {
//@ts-expect-error really dumb workaround
client.connected = true;
});
// Handle incoming UDP data
client.on("message", (data, rinfo) => {
ws.send(Packets_1.default.dataPacketMaker(wispFrame, data));
});
// Handle errors
client.on("error", (err) => {
logger.error(`An error occured in the connection to ${connectFrame.hostname} (${wispFrame.streamID}) with the message ${err.message}`);
ws.send(Packets_1.default.closePacketMaker(wispFrame, (0, Utils_1.checkErrorCode)(err)));
connections.delete(wispFrame.streamID);
client.close();
});
client.on("close", function () {
ws.send(Packets_1.default.closePacketMaker(wispFrame, 0x02));
connections.delete(wispFrame.streamID);
});
// Store the UDP socket and connectFrame in the connections map
connections.set(wispFrame.streamID, {
client,
});
else if (stream && stream.client instanceof node_dgram_1.default.Socket) {
stream.client.send(wispFrame.payload, undefined, undefined, (err) => {
if (err) {
ws.send(Packets_js_1.default.closePacketMaker(wispFrame, (0, Error_js_1.checkErrorCode)(err)));
if (stream.client.connected) {
stream.client.close();
}
connections.delete(wispFrame.streamID);
}
});
}
}
}
if (wispFrame.type === Types_1.CONNECT_TYPE.DATA) {
const stream = connections.get(wispFrame.streamID);
if (stream && stream.client instanceof node_net_1.default.Socket) {
stream.client.write(wispFrame.payload);
stream.buffer--;
if (stream.buffer === 0) {
stream.buffer = 127;
ws.send((0, Packets_1.continuePacketMaker)(wispFrame, stream.buffer));
if (wispFrame.type === Types_js_1.PACKET_TYPE.CLOSE) {
logger.log("Client decided to terminate with reason " + new DataView(wispFrame.payload.buffer).getUint8(0));
const stream = connections.get(wispFrame.streamID);
if (stream && stream.client instanceof node_net_1.default.Socket) {
stream.client.destroy();
}
else if (stream && stream.client instanceof node_dgram_1.default.Socket) {
stream.client.close();
}
connections.delete(wispFrame.streamID);
}
else if (stream && stream.client instanceof node_dgram_1.default.Socket) {
stream.client.send(wispFrame.payload, undefined, undefined, (err) => {
if (err) {
ws.send(Packets_1.default.closePacketMaker(wispFrame, 0x03));
if (stream.client.connected) {
stream.client.close();
}
connections.delete(wispFrame.streamID);
}
});
}
}
if (wispFrame.type === Types_1.CONNECT_TYPE.CLOSE) {
// its joever
logger.log("Client decided to terminate with reason " + new DataView(wispFrame.payload.buffer).getUint8(0));
const stream = connections.get(wispFrame.streamID);
if (stream && stream.client instanceof node_net_1.default.Socket) {
stream.client.destroy();
catch (e) {
ws.close();
logger.error(`WISP incoming message handler error: `, e);
for (const { client } of connections.values()) {
if (client instanceof node_net_1.default.Socket) {
client.destroy();
}
else if (client instanceof node_dgram_1.default.Socket) {
client.close();
}
}
else if (stream && stream.client instanceof node_dgram_1.default.Socket) {
stream.client.close();
}
connections.delete(wispFrame.streamID);
connections.clear();
}
}
catch (e) {
ws.close(); // something went SUPER wrong, like its probably not even a wisp connection
logger.error(`WISP incoming message handler error: `, e);
// cleanup
}));
ws.on("close", (code, reason) => {
logger.debug(`WebSocket connection closed with code ${code} and reason: ${reason}`);
for (const { client } of connections.values()) {

@@ -199,19 +211,6 @@ if (client instanceof node_net_1.default.Socket) {

connections.clear();
}
clearTimeout(pingInterval);
});
ws.send(Packets_js_1.default.continuePacketMaker({ streamID: 0 }, 127));
});
// Close all open sockets when the WebSocket connection is closed
ws.on("close", (code, reason) => {
logger.debug(`WebSocket connection closed with code ${code} and reason: ${reason}`);
for (const { client } of connections.values()) {
if (client instanceof node_net_1.default.Socket) {
client.destroy();
}
else if (client instanceof node_dgram_1.default.Socket) {
client.close();
}
}
connections.clear();
});
// SEND the initial continue packet with streamID 0 and 127 queue limit
ws.send(Packets_1.default.continuePacketMaker({ streamID: 0 }, 127));
}

@@ -218,0 +217,0 @@ exports.default = {

@@ -6,11 +6,12 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
const ConnectionHandler_1 = __importDefault(require("./ConnectionHandler"));
const ConnectionHandler_js_1 = __importDefault(require("./ConnectionHandler.js"));
const node_http_1 = __importDefault(require("node:http"));
const Types_1 = require("./Types");
const Types_js_1 = require("./Types.js");
const httpServer = node_http_1.default.createServer().listen(process.env.PORT || 3000);
httpServer.on("upgrade", (req, socket, head) => {
ConnectionHandler_1.default.routeRequest(req, socket, head, {
logLevel: Types_1.LOG_LEVEL.DEBUG
ConnectionHandler_js_1.default.routeRequest(req, socket, head, {
logLevel: Types_js_1.LOG_LEVEL.DEBUG,
pingInterval: 30
});
});
//# sourceMappingURL=createServer.js.map

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

import { WispFrame } from "./Types";
import { WispFrame } from "./Types.js";
export declare function wispFrameParser(data: Buffer): WispFrame;

@@ -11,3 +11,3 @@ export declare function connectPacketParser(payload: Uint8Array): {

export declare function closePacketMaker(wispFrame: WispFrame, reason: number): ArrayBuffer;
export declare function dataPacketMaker(wispFrame: WispFrame, data: Buffer): Buffer;
export declare function dataPacketMaker(wispFrame: WispFrame, data: any): Buffer;
declare const _default: {

@@ -14,0 +14,0 @@ wispFrameParser: typeof wispFrameParser;

@@ -8,3 +8,3 @@ "use strict";

exports.dataPacketMaker = dataPacketMaker;
const Types_1 = require("./Types");
const Types_js_1 = require("./Types.js");
function wispFrameParser(data) {

@@ -24,3 +24,3 @@ const uint8arrayView = new Uint8Array(data);

const dataview = new DataView(payload.buffer);
const streamType = dataview.getUint8(0); // for future use, makes it easier to retrofit UDP support
const streamType = dataview.getUint8(0);
const port = dataview.getUint16(1, true);

@@ -37,3 +37,3 @@ const hostname = new TextDecoder("utf8").decode(dataview.buffer.slice(3, dataview.buffer.byteLength));

const initialPacket = new DataView(new Uint8Array(9).buffer);
initialPacket.setUint8(0, Types_1.CONNECT_TYPE.CONTINUE);
initialPacket.setUint8(0, Types_js_1.PACKET_TYPE.CONTINUE);
initialPacket.setUint32(1, wispFrame.streamID, true);

@@ -45,3 +45,3 @@ initialPacket.setUint32(5, queue, true);

const closePacket = new DataView(new Uint8Array(9).buffer);
closePacket.setUint8(0, Types_1.CONNECT_TYPE.CLOSE);
closePacket.setUint8(0, Types_js_1.PACKET_TYPE.CLOSE);
closePacket.setUint32(1, wispFrame.streamID, true);

@@ -52,8 +52,5 @@ closePacket.setUint8(5, reason);

function dataPacketMaker(wispFrame, data) {
// Only function here that returns a node buffer instead ArrayBufferLike
// Packet header creation
const dataPacketHeader = new DataView(new Uint8Array(5).buffer);
dataPacketHeader.setUint8(0, Types_1.CONNECT_TYPE.DATA);
dataPacketHeader.setUint32(1, wispFrame.streamID, true); // Technically should be uint32 little endian, but libcurl bug
// Combine the data and the packet header and send to client
dataPacketHeader.setUint8(0, Types_js_1.PACKET_TYPE.DATA);
dataPacketHeader.setUint32(1, wispFrame.streamID, true);
return Buffer.concat([Buffer.from(dataPacketHeader.buffer), data]);

@@ -60,0 +57,0 @@ }

export type WispFrame = {
type: CONNECT_TYPE;
type: PACKET_TYPE;
streamID: number;
payload: Uint8Array;
};
export declare enum CONNECT_TYPE {
export declare enum PACKET_TYPE {
CONNECT = 1,

@@ -25,2 +25,3 @@ DATA = 2,

logLevel: LOG_LEVEL;
pingInterval: number;
};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LOG_LEVEL = exports.STREAM_TYPE = exports.CONNECT_TYPE = void 0;
var CONNECT_TYPE;
(function (CONNECT_TYPE) {
CONNECT_TYPE[CONNECT_TYPE["CONNECT"] = 1] = "CONNECT";
CONNECT_TYPE[CONNECT_TYPE["DATA"] = 2] = "DATA";
CONNECT_TYPE[CONNECT_TYPE["CONTINUE"] = 3] = "CONTINUE";
CONNECT_TYPE[CONNECT_TYPE["CLOSE"] = 4] = "CLOSE";
})(CONNECT_TYPE || (exports.CONNECT_TYPE = CONNECT_TYPE = {}));
exports.LOG_LEVEL = exports.STREAM_TYPE = exports.PACKET_TYPE = void 0;
var PACKET_TYPE;
(function (PACKET_TYPE) {
PACKET_TYPE[PACKET_TYPE["CONNECT"] = 1] = "CONNECT";
PACKET_TYPE[PACKET_TYPE["DATA"] = 2] = "DATA";
PACKET_TYPE[PACKET_TYPE["CONTINUE"] = 3] = "CONTINUE";
PACKET_TYPE[PACKET_TYPE["CLOSE"] = 4] = "CLOSE";
})(PACKET_TYPE || (exports.PACKET_TYPE = PACKET_TYPE = {}));
var STREAM_TYPE;

@@ -12,0 +12,0 @@ (function (STREAM_TYPE) {

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.handleWsProxy = handleWsProxy;
const node_net_1 = require("node:net");
async function handleWsProxy(ws, url) {
const client = new node_net_1.Socket();
try {
const destination = url.split("/").pop().split(":");
const host = destination[0];
const port = parseInt(destination[1]);
client.connect(port, host);
client.on("data", (data) => {
ws.send(data);
});
ws.onmessage = (event) => {
client.write(event.data);
};
ws.onclose = () => {
function handleWsProxy(ws, url) {
return __awaiter(this, void 0, void 0, function* () {
const client = new node_net_1.Socket();
try {
const destination = url.split("/").pop().split(":");
const host = destination[0];
const port = parseInt(destination[1]);
client.connect(port, host);
client.on("data", (data) => {
ws.send(data);
});
ws.onmessage = (event) => {
client.write(event.data);
};
ws.onclose = () => {
client.destroy();
};
client.on("close", () => {
ws.close();
});
}
catch (e) {
ws.close();
client.destroy();
};
client.on("close", () => {
ws.close();
});
}
catch (e) {
ws.close();
client.destroy();
}
}
});
}
//# sourceMappingURL=wsproxy.js.map
{
"name": "wisp-server-node",
"version": "1.1.4",
"type": "commonjs",
"description": "",
"main": "dist/ConnectionHandler.js",
"types": "dist/ConnectionHandler.d.ts",
"files": [
"dist",
"bin.js"
],
"keywords": [],
"author": "",
"repository": {
"type": "git",
"url": "git+https://github.com/MercuryWorkshop/wisp-server-node.git"
},
"homepage": "https://github.com/MercuryWorkshop/wisp-server-node#readme",
"license": "AGPL-3.0-only",
"devDependencies": {
"@types/ws": "^8.5.11",
"typescript": "^5.3.3"
},
"dependencies": {
"bufferutil": "^4.0.8",
"utf-8-validate": "^6.0.4",
"ws": "^8.18.0"
},
"scripts": {
"start": "node dist/createServer.js",
"build": "tsc",
"dev": "tsc --watch",
"pretty": "npx prettier -w *"
}
}
"name": "wisp-server-node",
"version": "1.1.7",
"type": "commonjs",
"description": "",
"scripts": {
"start": "node dist/createServer.js",
"build": "tsc",
"dev": "tsc --watch",
"pretty": "npx prettier -w *",
"prepare": "npm run build"
},
"main": "dist/ConnectionHandler.js",
"types": "dist/ConnectionHandler.d.ts",
"files": [
"dist",
"bin.js"
],
"keywords": [],
"author": "",
"repository": {
"type": "git",
"url": "git+https://github.com/MercuryWorkshop/wisp-server-node.git"
},
"homepage": "https://github.com/MercuryWorkshop/wisp-server-node#readme",
"license": "AGPL-3.0-only",
"devDependencies": {
"@types/ws": "^8.5.12",
"typescript": "^5.6.2"
},
"dependencies": {
"bufferutil": "^4.0.8",
"utf-8-validate": "^6.0.4",
"ws": "^8.18.0"
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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