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

@augment-vir/common

Package Overview
Dependencies
Maintainers
1
Versions
222
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@augment-vir/common - npm Package Compare versions

Comparing version 6.4.0 to 7.0.0

dist/cjs/augments/truncate-number.d.ts

26

dist/cjs/augments/common-number.d.ts

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

export declare function addCommasToNumber(input: number): string;
export declare const NaNString: string;
export declare function addCommasToNumber(input: number | string): string;
export declare function clamp(

@@ -12,23 +13,4 @@ /**

}): number;
/**
* This truncates a number such that is will at a max have 6 characters including suffix, decimal
* point, or comma.
*
* Default suffixes are:
*
* '', // no suffix, numbers below 1000
* 'k', // thousand
* 'M', // million
* 'B', // billion
* 'T', // trillion
* 'P', // peta-, quadrillion
* 'E', // exa- quintillion
* 'Z', // zetta- sextillion
* 'Y', // yotta- septillion
*/
export declare function truncateNumber(originalValue: unknown, { customSuffixes, suppressErrorLogging, customErrorLogCallback, }?: {
customSuffixes?: ReadonlyArray<string>;
suppressErrorLogging?: boolean;
customErrorLogCallback?: (...args: any) => void;
}): string;
export declare function convertIntoNumber(input: unknown): number;
export declare function doesRequireScientificNotation(input: number): boolean;
//# sourceMappingURL=common-number.d.ts.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.truncateNumber = exports.clamp = exports.addCommasToNumber = void 0;
exports.doesRequireScientificNotation = exports.convertIntoNumber = exports.clamp = exports.addCommasToNumber = exports.NaNString = void 0;
const common_string_1 = require("./common-string");
const regexp_1 = require("./regexp");
exports.NaNString = String(NaN);
function addCommasToNumber(input) {
if (typeof input === 'string' && isNaN(Number(input))) {
return exports.NaNString;
}
const stringValue = String(input);

@@ -26,87 +30,17 @@ const [digits, decimalValues,] = stringValue.split('.');

exports.clamp = clamp;
const defaultTruncationSuffixes = [
'',
'k',
'M',
'B',
'T',
'P',
'E',
'Z',
'Y', // yotta- septillion
];
function recursiveTruncation(value, recursionDepth = 0, decimalValues = '') {
var _a;
if (value.includes('e+')) {
throw new Error(`Number is too large, it cannot be truncated: ${value}`);
function convertIntoNumber(input) {
if (typeof input === 'number') {
return input;
}
else if (value.includes('e-')) {
throw new Error(`Number is too small, it cannot be truncated: ${value}`);
else if (typeof input === 'string') {
return Number((0, common_string_1.removeCommasFromNumberString)(input));
}
const split = (0, common_string_1.typedSplit)(value, '.');
decimalValues = (_a = split[1]) !== null && _a !== void 0 ? _a : decimalValues;
const amount = split[0];
if (amount.length > 3) {
decimalValues = amount.slice(-3);
return recursiveTruncation(amount.slice(0, -3), recursionDepth + 1, decimalValues);
else {
return Number(input);
}
return {
value: amount,
decimalValues,
recursionDepth,
};
}
const maxDecimals = 4;
/**
* This truncates a number such that is will at a max have 6 characters including suffix, decimal
* point, or comma.
*
* Default suffixes are:
*
* '', // no suffix, numbers below 1000
* 'k', // thousand
* 'M', // million
* 'B', // billion
* 'T', // trillion
* 'P', // peta-, quadrillion
* 'E', // exa- quintillion
* 'Z', // zetta- sextillion
* 'Y', // yotta- septillion
*/
function truncateNumber(originalValue, { customSuffixes, suppressErrorLogging, customErrorLogCallback, } = {}) {
try {
const value = typeof originalValue === 'number'
? originalValue
: typeof originalValue === 'string'
? Number((0, common_string_1.removeCommasFromNumberString)(originalValue))
: Number(originalValue);
if (isNaN(value)) {
throw new Error(`${originalValue} could not be converted into a number.`);
}
const stringValue = String(value);
const results = recursiveTruncation(stringValue);
const suffixes = customSuffixes !== null && customSuffixes !== void 0 ? customSuffixes : defaultTruncationSuffixes;
const suffix = suffixes[results.recursionDepth];
if (suffix === undefined) {
throw new Error(`Number is too large, could not truncate: ${value}`);
}
const decimalPlaces = maxDecimals - (results.value.length - 1) - suffix.length;
const decimalValues = results.decimalValues.replace(/0+$/, '').slice(0, decimalPlaces);
const withDecimal = decimalValues.length ? `.${decimalValues}` : '';
const combined = `${results.value}${withDecimal}${suffix}`;
if (combined.length > stringValue.length + 1) {
return addCommasToNumber(value);
}
else {
return combined;
}
}
catch (error) {
const errorCallback = customErrorLogCallback ? customErrorLogCallback : console.error;
if (!suppressErrorLogging) {
errorCallback(error);
}
return String(originalValue);
}
exports.convertIntoNumber = convertIntoNumber;
function doesRequireScientificNotation(input) {
return String(input).includes('e');
}
exports.truncateNumber = truncateNumber;
exports.doesRequireScientificNotation = doesRequireScientificNotation;

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

import { NoInputsFunction } from './function';
import { AtLeastTuple } from './tuple';
import { UnPromise } from './type';
export declare function combineErrors(errors: AtLeastTuple<Error, 1>): Error;

@@ -9,2 +11,4 @@ export declare function combineErrors(errors: ReadonlyArray<never>): undefined;

export declare function ensureError(input: unknown): Error;
export declare function executeAndReturnError<CallbackGeneric extends NoInputsFunction<PromiseLike<any>>>(callback: CallbackGeneric): Promise<Error | UnPromise<ReturnType<CallbackGeneric>>>;
export declare function executeAndReturnError<CallbackGeneric extends NoInputsFunction>(callback: CallbackGeneric): Error | ReturnType<CallbackGeneric>;
//# sourceMappingURL=error.d.ts.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ensureError = exports.extractErrorMessage = exports.combineErrorMessages = exports.combineErrors = void 0;
exports.executeAndReturnError = exports.ensureError = exports.extractErrorMessage = exports.combineErrorMessages = exports.combineErrors = void 0;
const function_1 = require("./function");
const promise_1 = require("./promise");
function combineErrors(errors) {

@@ -44,1 +45,27 @@ if (!errors || errors.length === 0) {

exports.ensureError = ensureError;
function executeAndReturnError(callback) {
let caughtError;
try {
const result = callback();
if ((0, promise_1.isPromiseLike)(result)) {
return new Promise(async (resolve) => {
try {
const output = await result;
return resolve(output);
}
catch (error) {
caughtError = ensureError(error);
}
return resolve(caughtError);
});
}
else {
return result;
}
}
catch (error) {
caughtError = ensureError(error);
}
return caughtError;
}
exports.executeAndReturnError = executeAndReturnError;

@@ -1,3 +0,4 @@

export type AnyFunction = (...args: any[]) => any;
export type AnyFunction<ReturnGeneric = any> = (...args: any[]) => ReturnGeneric;
export type NoInputsFunction<ReturnGeneric = any> = () => ReturnGeneric;
export declare function isTruthy<T>(input: T): input is NonNullable<T>;
//# sourceMappingURL=function.d.ts.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getValueFromNestedKeys = void 0;
const error_1 = require("./error");
const object_1 = require("./object");

@@ -13,19 +12,13 @@ function getValueFromNestedKeys(inputObject, nestedKeys) {

const keyToAccess = nestedKeys[0];
try {
if (!(0, object_1.typedHasProperty)(inputObject, keyToAccess)) {
return undefined;
}
const currentValue = inputObject[keyToAccess];
if (nestedKeys.length > 1) {
return getValueFromNestedKeys(currentValue, nestedKeys.slice(1));
}
else {
return currentValue;
}
if (!(0, object_1.typedHasProperty)(inputObject, keyToAccess)) {
return undefined;
}
catch (error) {
console.error({ inputObject, nestedKeys });
throw new Error(`Failed to traverse into inputObject using key "${String(keyToAccess)}": ${(0, error_1.extractErrorMessage)(error)}`);
const currentValue = inputObject[keyToAccess];
if (nestedKeys.length > 1) {
return getValueFromNestedKeys(currentValue, nestedKeys.slice(1));
}
else {
return currentValue;
}
}
exports.getValueFromNestedKeys = getValueFromNestedKeys;

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

const deferredPromiseWrapper = createDeferredPromiseWrapper();
if (delayMs === Infinity || delayMs < 0) {
return deferredPromiseWrapper.promise;
if (delayMs !== Infinity) {
setTimeout(() => {
deferredPromiseWrapper.resolve();
}, delayMs <= 0 ? 0 : delayMs);
}
setTimeout(() => {
deferredPromiseWrapper.resolve();
}, delayMs);
return deferredPromiseWrapper.promise;

@@ -61,2 +60,4 @@ }

});
// no way to test this edge case
// istanbul ignore next
if (!resolve || !reject) {

@@ -63,0 +64,0 @@ throw new Error(`Reject and resolve callbacks were not set by the promise constructor for ${createDeferredPromiseWrapper.name}.`);

@@ -5,6 +5,6 @@ export type Tuple<ArrayElementGeneric, LengthGeneric extends number> = LengthGeneric extends LengthGeneric ? number extends LengthGeneric ? ArrayElementGeneric[] : _TupleOf<ArrayElementGeneric, LengthGeneric, []> : never;

...Tuple<ArrayElementGeneric, LengthGeneric>,
...ArrayElementGeneric[]
...(ArrayElementGeneric | undefined)[]
];
export declare function isLengthAtLeast<ArrayElementGeneric, LengthGeneric extends number>(array: ReadonlyArray<ArrayElementGeneric>, length: LengthGeneric): array is AtLeastTuple<ArrayElementGeneric, LengthGeneric>;
export declare function isLengthAtLeast<ArrayElementGeneric, LengthGeneric extends number>(array: ReadonlyArray<ArrayElementGeneric | undefined>, length: LengthGeneric): array is AtLeastTuple<ArrayElementGeneric, LengthGeneric>;
export {};
//# sourceMappingURL=tuple.d.ts.map

@@ -15,2 +15,3 @@ export * from './augments/ansi';

export * from './augments/regexp';
export * from './augments/truncate-number';
export * from './augments/tuple';

@@ -17,0 +18,0 @@ export * from './augments/type';

@@ -31,4 +31,5 @@ "use strict";

__exportStar(require("./augments/regexp"), exports);
__exportStar(require("./augments/truncate-number"), exports);
__exportStar(require("./augments/tuple"), exports);
__exportStar(require("./augments/type"), exports);
__exportStar(require("./augments/type-of"), exports);

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

export declare function addCommasToNumber(input: number): string;
export declare const NaNString: string;
export declare function addCommasToNumber(input: number | string): string;
export declare function clamp(

@@ -12,23 +13,4 @@ /**

}): number;
/**
* This truncates a number such that is will at a max have 6 characters including suffix, decimal
* point, or comma.
*
* Default suffixes are:
*
* '', // no suffix, numbers below 1000
* 'k', // thousand
* 'M', // million
* 'B', // billion
* 'T', // trillion
* 'P', // peta-, quadrillion
* 'E', // exa- quintillion
* 'Z', // zetta- sextillion
* 'Y', // yotta- septillion
*/
export declare function truncateNumber(originalValue: unknown, { customSuffixes, suppressErrorLogging, customErrorLogCallback, }?: {
customSuffixes?: ReadonlyArray<string>;
suppressErrorLogging?: boolean;
customErrorLogCallback?: (...args: any) => void;
}): string;
export declare function convertIntoNumber(input: unknown): number;
export declare function doesRequireScientificNotation(input: number): boolean;
//# sourceMappingURL=common-number.d.ts.map

@@ -1,4 +0,8 @@

import { removeCommasFromNumberString, typedSplit } from './common-string';
import { removeCommasFromNumberString } from './common-string';
import { safeMatch } from './regexp';
export const NaNString = String(NaN);
export function addCommasToNumber(input) {
if (typeof input === 'string' && isNaN(Number(input))) {
return NaNString;
}
const stringValue = String(input);

@@ -21,86 +25,15 @@ const [digits, decimalValues,] = stringValue.split('.');

}
const defaultTruncationSuffixes = [
'',
'k',
'M',
'B',
'T',
'P',
'E',
'Z',
'Y', // yotta- septillion
];
function recursiveTruncation(value, recursionDepth = 0, decimalValues = '') {
var _a;
if (value.includes('e+')) {
throw new Error(`Number is too large, it cannot be truncated: ${value}`);
export function convertIntoNumber(input) {
if (typeof input === 'number') {
return input;
}
else if (value.includes('e-')) {
throw new Error(`Number is too small, it cannot be truncated: ${value}`);
else if (typeof input === 'string') {
return Number(removeCommasFromNumberString(input));
}
const split = typedSplit(value, '.');
decimalValues = (_a = split[1]) !== null && _a !== void 0 ? _a : decimalValues;
const amount = split[0];
if (amount.length > 3) {
decimalValues = amount.slice(-3);
return recursiveTruncation(amount.slice(0, -3), recursionDepth + 1, decimalValues);
else {
return Number(input);
}
return {
value: amount,
decimalValues,
recursionDepth,
};
}
const maxDecimals = 4;
/**
* This truncates a number such that is will at a max have 6 characters including suffix, decimal
* point, or comma.
*
* Default suffixes are:
*
* '', // no suffix, numbers below 1000
* 'k', // thousand
* 'M', // million
* 'B', // billion
* 'T', // trillion
* 'P', // peta-, quadrillion
* 'E', // exa- quintillion
* 'Z', // zetta- sextillion
* 'Y', // yotta- septillion
*/
export function truncateNumber(originalValue, { customSuffixes, suppressErrorLogging, customErrorLogCallback, } = {}) {
try {
const value = typeof originalValue === 'number'
? originalValue
: typeof originalValue === 'string'
? Number(removeCommasFromNumberString(originalValue))
: Number(originalValue);
if (isNaN(value)) {
throw new Error(`${originalValue} could not be converted into a number.`);
}
const stringValue = String(value);
const results = recursiveTruncation(stringValue);
const suffixes = customSuffixes !== null && customSuffixes !== void 0 ? customSuffixes : defaultTruncationSuffixes;
const suffix = suffixes[results.recursionDepth];
if (suffix === undefined) {
throw new Error(`Number is too large, could not truncate: ${value}`);
}
const decimalPlaces = maxDecimals - (results.value.length - 1) - suffix.length;
const decimalValues = results.decimalValues.replace(/0+$/, '').slice(0, decimalPlaces);
const withDecimal = decimalValues.length ? `.${decimalValues}` : '';
const combined = `${results.value}${withDecimal}${suffix}`;
if (combined.length > stringValue.length + 1) {
return addCommasToNumber(value);
}
else {
return combined;
}
}
catch (error) {
const errorCallback = customErrorLogCallback ? customErrorLogCallback : console.error;
if (!suppressErrorLogging) {
errorCallback(error);
}
return String(originalValue);
}
export function doesRequireScientificNotation(input) {
return String(input).includes('e');
}

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

import { NoInputsFunction } from './function';
import { AtLeastTuple } from './tuple';
import { UnPromise } from './type';
export declare function combineErrors(errors: AtLeastTuple<Error, 1>): Error;

@@ -9,2 +11,4 @@ export declare function combineErrors(errors: ReadonlyArray<never>): undefined;

export declare function ensureError(input: unknown): Error;
export declare function executeAndReturnError<CallbackGeneric extends NoInputsFunction<PromiseLike<any>>>(callback: CallbackGeneric): Promise<Error | UnPromise<ReturnType<CallbackGeneric>>>;
export declare function executeAndReturnError<CallbackGeneric extends NoInputsFunction>(callback: CallbackGeneric): Error | ReturnType<CallbackGeneric>;
//# sourceMappingURL=error.d.ts.map
import { isTruthy } from './function';
import { isPromiseLike } from './promise';
export function combineErrors(errors) {

@@ -37,1 +38,26 @@ if (!errors || errors.length === 0) {

}
export function executeAndReturnError(callback) {
let caughtError;
try {
const result = callback();
if (isPromiseLike(result)) {
return new Promise(async (resolve) => {
try {
const output = await result;
return resolve(output);
}
catch (error) {
caughtError = ensureError(error);
}
return resolve(caughtError);
});
}
else {
return result;
}
}
catch (error) {
caughtError = ensureError(error);
}
return caughtError;
}

@@ -1,3 +0,4 @@

export type AnyFunction = (...args: any[]) => any;
export type AnyFunction<ReturnGeneric = any> = (...args: any[]) => ReturnGeneric;
export type NoInputsFunction<ReturnGeneric = any> = () => ReturnGeneric;
export declare function isTruthy<T>(input: T): input is NonNullable<T>;
//# sourceMappingURL=function.d.ts.map

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

import { extractErrorMessage } from './error';
import { typedHasProperty } from './object';

@@ -10,18 +9,12 @@ export function getValueFromNestedKeys(inputObject, nestedKeys) {

const keyToAccess = nestedKeys[0];
try {
if (!typedHasProperty(inputObject, keyToAccess)) {
return undefined;
}
const currentValue = inputObject[keyToAccess];
if (nestedKeys.length > 1) {
return getValueFromNestedKeys(currentValue, nestedKeys.slice(1));
}
else {
return currentValue;
}
if (!typedHasProperty(inputObject, keyToAccess)) {
return undefined;
}
catch (error) {
console.error({ inputObject, nestedKeys });
throw new Error(`Failed to traverse into inputObject using key "${String(keyToAccess)}": ${extractErrorMessage(error)}`);
const currentValue = inputObject[keyToAccess];
if (nestedKeys.length > 1) {
return getValueFromNestedKeys(currentValue, nestedKeys.slice(1));
}
else {
return currentValue;
}
}

@@ -5,8 +5,7 @@ import { extractErrorMessage } from './error';

const deferredPromiseWrapper = createDeferredPromiseWrapper();
if (delayMs === Infinity || delayMs < 0) {
return deferredPromiseWrapper.promise;
if (delayMs !== Infinity) {
setTimeout(() => {
deferredPromiseWrapper.resolve();
}, delayMs <= 0 ? 0 : delayMs);
}
setTimeout(() => {
deferredPromiseWrapper.resolve();
}, delayMs);
return deferredPromiseWrapper.promise;

@@ -54,2 +53,4 @@ }

});
// no way to test this edge case
// istanbul ignore next
if (!resolve || !reject) {

@@ -56,0 +57,0 @@ throw new Error(`Reject and resolve callbacks were not set by the promise constructor for ${createDeferredPromiseWrapper.name}.`);

@@ -5,6 +5,6 @@ export type Tuple<ArrayElementGeneric, LengthGeneric extends number> = LengthGeneric extends LengthGeneric ? number extends LengthGeneric ? ArrayElementGeneric[] : _TupleOf<ArrayElementGeneric, LengthGeneric, []> : never;

...Tuple<ArrayElementGeneric, LengthGeneric>,
...ArrayElementGeneric[]
...(ArrayElementGeneric | undefined)[]
];
export declare function isLengthAtLeast<ArrayElementGeneric, LengthGeneric extends number>(array: ReadonlyArray<ArrayElementGeneric>, length: LengthGeneric): array is AtLeastTuple<ArrayElementGeneric, LengthGeneric>;
export declare function isLengthAtLeast<ArrayElementGeneric, LengthGeneric extends number>(array: ReadonlyArray<ArrayElementGeneric | undefined>, length: LengthGeneric): array is AtLeastTuple<ArrayElementGeneric, LengthGeneric>;
export {};
//# sourceMappingURL=tuple.d.ts.map

@@ -15,2 +15,3 @@ export * from './augments/ansi';

export * from './augments/regexp';
export * from './augments/truncate-number';
export * from './augments/tuple';

@@ -17,0 +18,0 @@ export * from './augments/type';

@@ -15,4 +15,5 @@ export * from './augments/ansi';

export * from './augments/regexp';
export * from './augments/truncate-number';
export * from './augments/tuple';
export * from './augments/type';
export * from './augments/type-of';

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

export declare function addCommasToNumber(input: number): string;
export declare const NaNString: string;
export declare function addCommasToNumber(input: number | string): string;
export declare function clamp(

@@ -12,23 +13,4 @@ /**

}): number;
/**
* This truncates a number such that is will at a max have 6 characters including suffix, decimal
* point, or comma.
*
* Default suffixes are:
*
* '', // no suffix, numbers below 1000
* 'k', // thousand
* 'M', // million
* 'B', // billion
* 'T', // trillion
* 'P', // peta-, quadrillion
* 'E', // exa- quintillion
* 'Z', // zetta- sextillion
* 'Y', // yotta- septillion
*/
export declare function truncateNumber(originalValue: unknown, { customSuffixes, suppressErrorLogging, customErrorLogCallback, }?: {
customSuffixes?: ReadonlyArray<string>;
suppressErrorLogging?: boolean;
customErrorLogCallback?: (...args: any) => void;
}): string;
export declare function convertIntoNumber(input: unknown): number;
export declare function doesRequireScientificNotation(input: number): boolean;
//# sourceMappingURL=common-number.d.ts.map

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

import { NoInputsFunction } from './function';
import { AtLeastTuple } from './tuple';
import { UnPromise } from './type';
export declare function combineErrors(errors: AtLeastTuple<Error, 1>): Error;

@@ -9,2 +11,4 @@ export declare function combineErrors(errors: ReadonlyArray<never>): undefined;

export declare function ensureError(input: unknown): Error;
export declare function executeAndReturnError<CallbackGeneric extends NoInputsFunction<PromiseLike<any>>>(callback: CallbackGeneric): Promise<Error | UnPromise<ReturnType<CallbackGeneric>>>;
export declare function executeAndReturnError<CallbackGeneric extends NoInputsFunction>(callback: CallbackGeneric): Error | ReturnType<CallbackGeneric>;
//# sourceMappingURL=error.d.ts.map

@@ -1,3 +0,4 @@

export type AnyFunction = (...args: any[]) => any;
export type AnyFunction<ReturnGeneric = any> = (...args: any[]) => ReturnGeneric;
export type NoInputsFunction<ReturnGeneric = any> = () => ReturnGeneric;
export declare function isTruthy<T>(input: T): input is NonNullable<T>;
//# sourceMappingURL=function.d.ts.map

@@ -5,6 +5,6 @@ export type Tuple<ArrayElementGeneric, LengthGeneric extends number> = LengthGeneric extends LengthGeneric ? number extends LengthGeneric ? ArrayElementGeneric[] : _TupleOf<ArrayElementGeneric, LengthGeneric, []> : never;

...Tuple<ArrayElementGeneric, LengthGeneric>,
...ArrayElementGeneric[]
...(ArrayElementGeneric | undefined)[]
];
export declare function isLengthAtLeast<ArrayElementGeneric, LengthGeneric extends number>(array: ReadonlyArray<ArrayElementGeneric>, length: LengthGeneric): array is AtLeastTuple<ArrayElementGeneric, LengthGeneric>;
export declare function isLengthAtLeast<ArrayElementGeneric, LengthGeneric extends number>(array: ReadonlyArray<ArrayElementGeneric | undefined>, length: LengthGeneric): array is AtLeastTuple<ArrayElementGeneric, LengthGeneric>;
export {};
//# sourceMappingURL=tuple.d.ts.map

@@ -15,2 +15,3 @@ export * from './augments/ansi';

export * from './augments/regexp';
export * from './augments/truncate-number';
export * from './augments/tuple';

@@ -17,0 +18,0 @@ export * from './augments/type';

{
"name": "@augment-vir/common",
"version": "6.4.0",
"version": "7.0.0",
"homepage": "https://github.com/electrovir/augment-vir/tree/main/packages/common",

@@ -26,3 +26,3 @@ "bugs": {

"dependencies": {
"type-fest": "^3.5.0"
"type-fest": "^3.5.1"
},

@@ -29,0 +29,0 @@ "devDependencies": {

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