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

koatty_logger

Package Overview
Dependencies
Maintainers
1
Versions
35
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

koatty_logger - npm Package Compare versions

Comparing version 1.3.16 to 2.0.0

8

CHANGELOG.md

@@ -5,2 +5,10 @@ # Changelog

## [2.0.0](https://github.com/thinkkoa/koatty_logger/compare/v1.3.16...v2.0.0) (2023-01-09)
### Bug Fixes
* peerDependencies ([253f017](https://github.com/thinkkoa/koatty_logger/commit/253f0172cd2116a56174175f3a50209fdd905c65))
* 日志接口 ([d29af82](https://github.com/thinkkoa/koatty_logger/commit/d29af8297b49a81cf6b38f4ad9f036d4a8b0d7f7))
### [1.3.16](https://github.com/thinkkoa/koatty_logger/compare/v1.3.15...v1.3.16) (2023-01-07)

@@ -7,0 +15,0 @@

127

dist/index.d.ts
/*!
* @Author: richen
* @Date: 2023-01-07 12:40:37
* @Date: 2023-01-09 22:45:58
* @License: BSD (3-Clause)

@@ -8,2 +8,4 @@ * @Copyright (c) - <richenlin(at)gmail.com>

*/
import { transports } from 'winston';
export declare const DefaultLogger: Logger;

@@ -19,10 +21,2 @@

/**
* getLevel
*/
getLevel(): LogLevelType;
/**
* setLevel
*/
setLevel(level: LogLevelType): void;
/**
* log Debug

@@ -62,6 +56,4 @@ *

*
* Logger.Log('name', 'color', 'msg')
* Logger.Log('name', 'msg1', 'msg2'...)
*
* Logger.Log('name', 'color', 'msg1', 'msg2'...)
*
* @param {...any[]} args

@@ -72,7 +64,7 @@ * @returns {*}

Log(...msg: any[]): void;
Log(name: string, ...msg: any[]): void;
Log(name: string, color: LogColor, ...msg: any[]): void;
Log(name: LogLevelType | string, ...msg: any[]): void;
Log(name: LogLevelType | string, color: LogColor, ...msg: any[]): void;
}
export declare type LogColor = "white" | "grey" | "black" | "blue" | "cyan" | "green" | "magenta" | "red" | "yellow";
export declare type LogColor = "white" | "blue" | "yellow" | "red";

@@ -92,2 +84,6 @@ /**

/**
* enable
*/
enable(b?: boolean): void;
/**
* getLevel

@@ -101,26 +97,2 @@ */

/**
* getLogConsole
*/
getLogConsole(): boolean;
/**
* setLogConsole
*/
setLogConsole(t: boolean): void;
/**
* getLogFile
*/
getLogFile(): boolean;
/**
* setLogFile
*/
setLogFile(t: boolean): void;
/**
* getLogFileLevel
*/
getLogFileLevel(): LogLevelType;
/**
* setLogFileLevel
*/
setLogFileLevel(level: LogLevelType): void;
/**
* getLogFilePath

@@ -130,5 +102,5 @@ */

/**
* setLogPath
* setLogFile
*/
setLogFilePath(path: string): void;
setLogFilePath(f: string): void;
/**

@@ -143,33 +115,2 @@ * getSensFields

/**
* 格式化
*
* @private
* @param {LogLevelType} level
* @param {string} name
* @param {any[]|string} args
* @returns {string}
* @memberof Logger
*/
/**
* print console
*
* @private
* @param {LogLevelType} level
* @param {string} name
* @param {string} color
* @param {any[]|string} args
* @memberof Logger
*/
/**
* write log file
*
* @private
* @param {LogLevelType} level
* @param {string} name
* @param {any[]} msgs
* @param {boolean} [formatted=false]
* @returns {*} {Promise<any>}
* @memberof Logger
*/
/**
* log Debug

@@ -209,6 +150,4 @@ *

*
* Logger.Log('name', 'color', 'msg')
* Logger.Log('name', 'msg1', 'msg2'...)
*
* Logger.Log('name', 'color', 'msg1', 'msg2'...)
*
* @param {...any[]} args

@@ -218,22 +157,31 @@ * @returns {*}

*/
Log(level: LogLevelType, ...args: any[]): void;
Log(name: LogLevelType | string, ...args: any[]): void;
/**
* alias Log
* print console
*
* @private
* @param {LogLevelType} level
* @param {string} name
* @param {any[]|string} args
* @memberof Logger
*/
Custom(...args: any[]): void;
/**
* write log file
* 格式化
*
* @param {...any[]} args
* @returns {*}
* @private
* @param {string} level
* @param {string} label
* @param {string} timestamp
* @param {any[]|string} args
* @returns {string}
* @memberof Logger
*/
Write(...args: any[]): Promise<any>;
/**
* createLogger
* @returns
*/
}
declare interface LoggerOpt {
export declare interface LoggerOpt {
logLevel?: LogLevelType;
logConsole?: boolean;
logFile?: boolean;
logFileLevel?: LogLevelType;
logFilePath?: string;

@@ -243,4 +191,9 @@ sensFields?: Set<string>;

export declare type LogLevelType = "DEBUG" | "INFO" | "WARN" | "ERROR";
export declare type LogLevelType = "debug" | "info" | "warning" | "error";
export declare interface LogTrans {
Console?: transports.ConsoleTransportInstance;
File?: transports.FileTransportInstance;
}
export { }
/*!
* @Author: richen
* @Date: 2023-01-07 12:40:23
* @Date: 2023-01-09 22:45:46
* @License: BSD (3-Clause)

@@ -10,12 +10,7 @@ * @Copyright (c) - <richenlin(at)gmail.com>

Object.defineProperty(exports, '__esModule', { value: true });
var fs = require('fs');
var util = require('util');
var helper = require('koatty_lib');
var winston = require('winston');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
function _interopNamespace(e) {
if (e && e.__esModule) return e;
function _interopNamespaceDefault(e) {
var n = Object.create(null);

@@ -33,9 +28,7 @@ if (e) {

}
n["default"] = e;
n.default = e;
return Object.freeze(n);
}
var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
var util__default = /*#__PURE__*/_interopDefaultLegacy(util);
var helper__namespace = /*#__PURE__*/_interopNamespace(helper);
var helper__namespace = /*#__PURE__*/_interopNamespaceDefault(helper);

@@ -47,3 +40,3 @@ /*

* @Date: 2021-11-04 20:31:43
* @LastEditTime: 2022-05-26 12:47:26
* @LastEditTime: 2023-01-08 14:50:16
*/

@@ -107,3 +100,3 @@ /**

}
if (splat === null)
if (!splat)
return splat;

@@ -139,39 +132,36 @@ if (Array.isArray(splat)) {

* @LastEditors: Please set LastEditors
* @LastEditTime: 2023-01-07 12:15:36
* @LastEditTime: 2023-01-09 22:37:25
* @License: BSD (3-Clause)
* @Copyright (c) - <richenlin(at)gmail.com>
*/
const fsOpen = util.promisify(fs__default["default"].open);
const fsAppend = util.promisify(fs__default["default"].appendFile);
const fsClose = util.promisify(fs__default["default"].close);
const styles = {
'bold': ['\x1B[1m', '\x1B[22m'],
'italic': ['\x1B[3m', '\x1B[23m'],
'underline': ['\x1B[4m', '\x1B[24m'],
'inverse': ['\x1B[7m', '\x1B[27m'],
'white': ['\x1B[37m', '\x1B[39m'],
'grey': ['\x1B[90m', '\x1B[39m'],
'black': ['\x1B[30m', '\x1B[39m'],
'blue': ['\x1B[34m', '\x1B[39m'],
'cyan': ['\x1B[36m', '\x1B[39m'],
'green': ['\x1B[32m', '\x1B[39m'],
'magenta': ['\x1B[35m', '\x1B[39m'],
'red': ['\x1B[31m', '\x1B[39m'],
'yellow': ['\x1B[33m', '\x1B[39m'],
'whiteBG': ['\x1B[47m', '\x1B[49m'],
'greyBG': ['\x1B[49;5;8m', '\x1B[49m'],
'blackBG': ['\x1B[40m', '\x1B[49m'],
'blueBG': ['\x1B[44m', '\x1B[49m'],
'cyanBG': ['\x1B[46m', '\x1B[49m'],
'greenBG': ['\x1B[42m', '\x1B[49m'],
'magentaBG': ['\x1B[45m', '\x1B[49m'],
'redBG': ['\x1B[41m', '\x1B[49m'],
'yellowBG': ['\x1B[43m', '\x1B[49m']
};
const DailyRotateFile = helper__namespace.safeRequire("winston-daily-rotate-file");
const { combine, timestamp, label, printf } = winston.format;
const LogLevelObj = {
"DEBUG": 0,
"INFO": 1,
"WARN": 2,
"ERROR": 3
"debug": 7,
"info": 6,
"warning": 4,
"error": 3
};
// defaultLoggerOpt
const defaultLoggerOpt = {
File: {
level: "info",
filename: "./logs/log.log",
handleExceptions: true,
json: true,
datePattern: 'YYYY-MM-DD-HH',
// zippedArchive: true,
maxSize: '20m',
// maxFiles: '7d',
colorize: false,
timestamp: true
},
Console: {
level: "debug",
handleExceptions: true,
json: true,
colorize: true,
timestamp: true
}
};
/**

@@ -189,24 +179,18 @@ * Logger

constructor(opt) {
var _a, _b, _c, _d, _e, _f;
// 控制台日志级别
this.logLevel = "INFO";
// 默认打开控制台日志
this.logConsole = true;
// 空对象
var _a, _b, _c;
// 日志级别
this.logLevel = "debug";
// 默认打开日志
this.enableLog = true;
// 日志对象
this.emptyObj = {};
// 文件日志开关
this.logFile = false;
// 文件日志级别
this.logFileLevel = "WARN";
// 文件日志路径
this.logFilePath = "./logs";
this.transports = {};
// 文件日志
this.logFilePath = "./logs/";
// 脱敏字段
this.sensFields = new Set();
if (process.env.LOGS_LEVEL && LogLevelObj[process.env.LOGS_LEVEL]) {
this.logLevel = process.env.LOGS_LEVEL;
this.logFileLevel = process.env.LOGS_LEVEL;
const level = (process.env.LOGS_LEVEL || "").toLowerCase();
if (level && LogLevelObj[level]) {
this.logLevel = level;
}
if (process.env.LOGS_WRITE) {
this.logFile = !!process.env.LOGS_WRITE;
}
if (process.env.LOGS_PATH) {

@@ -217,10 +201,14 @@ this.logFilePath = process.env.LOGS_PATH;

this.logLevel = (_a = opt.logLevel) !== null && _a !== void 0 ? _a : this.logLevel;
this.logConsole = (_b = opt.logConsole) !== null && _b !== void 0 ? _b : this.logConsole;
this.logFile = (_c = opt.logFile) !== null && _c !== void 0 ? _c : this.logFile;
this.logFileLevel = (_d = opt.logFileLevel) !== null && _d !== void 0 ? _d : this.logFileLevel;
this.logFilePath = (_e = opt.logFilePath) !== null && _e !== void 0 ? _e : this.logFilePath;
this.sensFields = (_f = opt.sensFields) !== null && _f !== void 0 ? _f : this.sensFields;
this.logFilePath = (_b = opt.logFilePath) !== null && _b !== void 0 ? _b : this.logFilePath;
this.sensFields = (_c = opt.sensFields) !== null && _c !== void 0 ? _c : this.sensFields;
}
this.logger = this.createLogger();
}
/**
* enable
*/
enable(b = true) {
this.enableLog = b;
}
/**
* getLevel

@@ -236,42 +224,12 @@ */

this.logLevel = level;
if (this.transports.Console) {
this.transports.Console.level = level;
}
if (this.transports.File) {
this.transports.File.level = level;
}
}
/**
* getLogConsole
*/
getLogConsole() {
return this.logConsole;
}
/**
* setLogConsole
*/
setLogConsole(t) {
this.logConsole = t;
}
/**
* getLogFile
*/
getLogFile() {
return this.logFile;
}
/**
* setLogFile
*/
setLogFile(t) {
this.logFile = t;
}
/**
* getLogFileLevel
*/
getLogFileLevel() {
return this.logFileLevel;
}
/**
* setLogFileLevel
*/
setLogFileLevel(level) {
this.logFileLevel = level;
}
/**
* getLogFilePath
*/
* getLogFilePath
*/
getLogFilePath() {

@@ -281,6 +239,8 @@ return this.logFilePath;

/**
* setLogPath
* setLogFile
*/
setLogFilePath(path) {
this.logFilePath = path;
setLogFilePath(f) {
this.logFilePath = f;
this.logger.close();
this.logger = this.createLogger();
}

@@ -300,98 +260,2 @@ /**

/**
* 格式化
*
* @private
* @param {LogLevelType} level
* @param {string} name
* @param {any[]|string} args
* @returns {string}
* @memberof Logger
*/
format(level, name, args) {
try {
const params = [`[${helper__namespace.dateTime('', '')}]`, `[${name}]`, ...ShieldLog(args, this.sensFields)];
if (level === "DEBUG") {
Error.captureStackTrace(this.emptyObj);
const matchResult = (this.emptyObj.stack).match(/\(.*?\)/g) || [];
params.push(matchResult[3] || "");
}
return util__default["default"].format.apply(null, params);
}
catch (e) {
// console.error(e.stack);
return "";
}
}
/**
* print console
*
* @private
* @param {LogLevelType} level
* @param {string} name
* @param {string} color
* @param {any[]|string} args
* @memberof Logger
*/
print(level, name, color, args) {
try {
name = name !== '' ? name.toUpperCase() : level;
const logLevel = this.getLevel();
if (LogLevelObj[level] < LogLevelObj[logLevel]) {
return;
}
let formatted = false;
// print console
if (this.logConsole) {
args = this.format(level, name, args);
formatted = true;
color = color || 'grey';
const style = styles[color] || styles.grey;
console.log(`${style[0]}${args}${style[1]}`);
}
// record log files
if (this.logFile) {
this.writeLogFile(level, name, args, formatted);
}
}
catch (e) {
console.error(e);
}
}
/**
* write log file
*
* @private
* @param {LogLevelType} level
* @param {string} name
* @param {any[]} msgs
* @param {boolean} [formatted=false]
* @returns {*} {Promise<any>}
* @memberof Logger
*/
async writeLogFile(level, name, msgs, formatted = false) {
try {
name = name !== '' ? name.toUpperCase() : level;
const logFilePath = this.logFilePath;
if (!helper__namespace.isDir(logFilePath)) {
await helper__namespace.mkDir(logFilePath);
}
let params = msgs;
if (!formatted) {
params = this.format(level, name, msgs);
}
const file = `${logFilePath}${helper__namespace.sep}${name ? `${name}_` : ''}${helper__namespace.dateTime('', 'YYYY-MM-DD-hh')}.log`;
const fd = await fsOpen(file, 'a');
// tslint:disable-next-line: no-null-keyword
await fsAppend(fd, `${params}\n`, 'utf8');
await fsClose(fd);
// tslint:disable-next-line: no-null-keyword
return null;
}
catch (err) {
console.error(err);
// tslint:disable-next-line: no-null-keyword
return null;
}
}
/**
* log Debug

@@ -403,3 +267,3 @@ *

Debug(...args) {
return this.print("DEBUG", "", "blue", args);
return this.printLog("debug", "", args);
}

@@ -413,3 +277,3 @@ /**

Info(...args) {
return this.print("INFO", "", "white", args);
return this.printLog("info", "", args);
}

@@ -423,3 +287,3 @@ /**

Warn(...args) {
return this.print("WARN", "", "yellow", args);
return this.printLog("warning", "", args);
}

@@ -433,3 +297,3 @@ /**

Error(...args) {
return this.print("ERROR", "", "red", args);
return this.printLog("error", "", args);
}

@@ -443,6 +307,4 @@ /**

*
* Logger.Log('name', 'color', 'msg')
* Logger.Log('name', 'msg1', 'msg2'...)
*
* Logger.Log('name', 'color', 'msg1', 'msg2'...)
*
* @param {...any[]} args

@@ -452,67 +314,90 @@ * @returns {*}

*/
Log(level, ...args) {
Log(name, ...args) {
// tslint:disable-next-line: one-variable-per-declaration
let name = "", color = "white", msgs = [];
if (args.length > 2) {
name = args[0];
color = args[1] || color;
msgs = args.slice(2);
let level = "info";
if (LogLevelObj[name]) {
level = name;
name = "";
}
else if (args.length === 2) {
name = args[0];
msgs = args.slice(1);
}
else {
msgs = args;
}
return this.print(level, name, color, msgs);
return this.printLog(level, name, args);
}
/**
* alias Log
* print console
*
* @private
* @param {LogLevelType} level
* @param {string} name
* @param {any[]|string} args
* @memberof Logger
*/
Custom(...args) {
// tslint:disable-next-line: one-variable-per-declaration
let name = "", color = "white", msgs = [];
if (args.length > 2) {
name = args[0];
color = args[1] || color;
msgs = args.slice(2);
printLog(level, name, args) {
try {
if (!this.enableLog) {
return;
}
name = name !== '' ? name.toUpperCase() : level.toUpperCase();
// format
args.unshift(name);
this.logger[level](args);
}
else if (args.length === 2) {
name = args[0];
msgs = args.slice(1);
catch (e) {
console.error(e);
}
else {
msgs = args;
}
return this.print("INFO", name, color, msgs);
}
/**
* write log file
* 格式化
*
* @param {...any[]} args
* @returns {*}
* @private
* @param {string} level
* @param {string} label
* @param {string} timestamp
* @param {any[]|string} args
* @returns {string}
* @memberof Logger
*/
Write(...args) {
// tslint:disable-next-line: one-variable-per-declaration
let name = "", msgs = [];
if (args.length >= 2) {
name = args[0];
msgs = args.slice(1);
format(level, label, timestamp, args) {
try {
label = label ? `[${label}]` : '';
const params = [`[${timestamp}]`, label, ...ShieldLog(args, this.sensFields)];
if (level === "debug") {
Error.captureStackTrace(this.emptyObj);
const matchResult = (this.emptyObj.stack.slice(this.emptyObj.stack.lastIndexOf("koatty_logger"))).match(/\(.*?\)/g) || [];
params.push(matchResult.join(" "));
}
return util.format.apply(null, params);
}
catch (e) {
// console.error(e.stack);
return "";
}
}
/**
* createLogger
* @returns
*/
createLogger() {
const trans = [];
if (this.logFilePath != "") {
defaultLoggerOpt.File.level = this.logLevel;
defaultLoggerOpt.File.filename = `${(this.logFilePath || './logs/')}/log-%DATE%.log`;
this.transports.File = new DailyRotateFile(defaultLoggerOpt.File);
trans.push(this.transports.File);
}
else {
msgs = args;
defaultLoggerOpt.Console.level = this.logLevel;
this.transports.Console = new winston.transports.Console(defaultLoggerOpt.Console);
trans.push(this.transports.Console);
}
return this.writeLogFile("INFO", name, msgs);
return winston.createLogger({
levels: LogLevelObj,
transports: trans,
format: combine(timestamp({
format: "YYYY-MM-DD HH:mm:ss.SSS Z",
}), winston.format.json(), printf(({ level, message, label, timestamp }) => {
return this.format(level, label, timestamp, message);
})),
});
}
}
/*
* @Description:
* @Usage:
* @Author: richen
* @Date: 2021-12-18 20:03:31
* @LastEditTime: 2022-05-26 12:47:09
*/
//DefaultLogger

@@ -519,0 +404,0 @@ const DefaultLogger = new Logger();

{
"name": "koatty_logger",
"version": "1.3.16",
"version": "2.0.0",
"description": "Logger for koatty.",

@@ -8,3 +8,3 @@ "scripts": {

"build:cp": "node scripts/postBuild && copyfiles package.json LICENSE README.md dist/",
"build:js": "del-cli --force dist && npx rollup -c .rollup.config.js",
"build:js": "del-cli --force dist && npx rollup --bundleConfigAsCjs -c .rollup.config.js",
"build:doc": "del-cli --force docs/api && npx api-documenter markdown --input temp --output docs/api",

@@ -16,2 +16,4 @@ "build:dts": "del-cli --force temp && npx tsc && npx api-extractor run --local --verbose",

"release": "standard-version",
"release:major": "npm run release -- --release-as major",
"release:minor": "npm run release -- --release-as minor",
"test": "npm run eslint && jest --passWithNoTests"

@@ -62,6 +64,6 @@ },

"@microsoft/api-extractor": "^7.x.x",
"@rollup/plugin-json": "^4.x.x",
"@types/jest": "^27.x.x",
"@rollup/plugin-json": "^6.x.x",
"@types/jest": "^29.x.x",
"@types/koa": "^2.x.x",
"@types/node": "^16.x.x",
"@types/node": "^18.x.x",
"@typescript-eslint/eslint-plugin": "^5.x.x",

@@ -73,10 +75,10 @@ "@typescript-eslint/parser": "^5.x.x",

"eslint": "^8.x.x",
"eslint-plugin-jest": "^26.x.x",
"eslint-plugin-jest": "^27.x.x",
"husky": "^4.x.x",
"jest": "^28.x.x",
"jest": "^29.x.x",
"jest-html-reporters": "^3.x.x",
"rollup": "^2.x.x",
"rollup": "^3.x.x",
"rollup-plugin-typescript2": "^0.x.x",
"standard-version": "^9.x.x",
"ts-jest": "^28.x.x",
"ts-jest": "^29.x.x",
"ts-node": "^10.x.x",

@@ -86,9 +88,9 @@ "typescript": "^4.x.x"

"dependencies": {
"koatty_lib": "^1.x.x",
"winston": "^3.8.2",
"winston-daily-rotate-file": "^4.7.1"
},
"peerDependencies": {
"koatty_lib": "^1.x.x"
},
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
}
{
"name": "koatty_logger",
"version": "1.3.16",
"version": "2.0.0",
"description": "Logger for koatty.",

@@ -8,3 +8,3 @@ "scripts": {

"build:cp": "node scripts/postBuild && copyfiles package.json LICENSE README.md dist/",
"build:js": "del-cli --force dist && npx rollup -c .rollup.config.js",
"build:js": "del-cli --force dist && npx rollup --bundleConfigAsCjs -c .rollup.config.js",
"build:doc": "del-cli --force docs/api && npx api-documenter markdown --input temp --output docs/api",

@@ -16,2 +16,4 @@ "build:dts": "del-cli --force temp && npx tsc && npx api-extractor run --local --verbose",

"release": "standard-version",
"release:major": "npm run release -- --release-as major",
"release:minor": "npm run release -- --release-as minor",
"test": "npm run eslint && jest --passWithNoTests"

@@ -62,6 +64,6 @@ },

"@microsoft/api-extractor": "^7.x.x",
"@rollup/plugin-json": "^4.x.x",
"@types/jest": "^27.x.x",
"@rollup/plugin-json": "^6.x.x",
"@types/jest": "^29.x.x",
"@types/koa": "^2.x.x",
"@types/node": "^16.x.x",
"@types/node": "^18.x.x",
"@typescript-eslint/eslint-plugin": "^5.x.x",

@@ -73,10 +75,10 @@ "@typescript-eslint/parser": "^5.x.x",

"eslint": "^8.x.x",
"eslint-plugin-jest": "^26.x.x",
"eslint-plugin-jest": "^27.x.x",
"husky": "^4.x.x",
"jest": "^28.x.x",
"jest": "^29.x.x",
"jest-html-reporters": "^3.x.x",
"rollup": "^2.x.x",
"rollup": "^3.x.x",
"rollup-plugin-typescript2": "^0.x.x",
"standard-version": "^9.x.x",
"ts-jest": "^28.x.x",
"ts-jest": "^29.x.x",
"ts-node": "^10.x.x",

@@ -86,9 +88,9 @@ "typescript": "^4.x.x"

"dependencies": {
"koatty_lib": "^1.x.x",
"winston": "^3.8.2",
"winston-daily-rotate-file": "^4.7.1"
},
"peerDependencies": {
"koatty_lib": "^1.x.x"
},
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
}

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