Socket
Socket
Sign inDemoInstall

@ckeditor/ckeditor5-utils

Package Overview
Dependencies
Maintainers
1
Versions
613
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ckeditor/ckeditor5-utils - npm Package Compare versions

Comparing version 29.2.0 to 30.0.0

10

package.json
{
"name": "@ckeditor/ckeditor5-utils",
"version": "29.2.0",
"version": "30.0.0",
"description": "Miscellaneous utilities used by CKEditor 5.",

@@ -17,6 +17,6 @@ "keywords": [

"devDependencies": {
"@ckeditor/ckeditor5-build-classic": "^29.2.0",
"@ckeditor/ckeditor5-editor-classic": "^29.2.0",
"@ckeditor/ckeditor5-core": "^29.2.0",
"@ckeditor/ckeditor5-engine": "^29.2.0",
"@ckeditor/ckeditor5-build-classic": "^30.0.0",
"@ckeditor/ckeditor5-editor-classic": "^30.0.0",
"@ckeditor/ckeditor5-core": "^30.0.0",
"@ckeditor/ckeditor5-engine": "^30.0.0",
"assertion-error": "^1.1.0",

@@ -23,0 +23,0 @@ "js-beautify": "^1.11.0"

@@ -88,2 +88,3 @@ /**

* Checks if the error is of the `CKEditorError` type.
* @returns {Boolean}
*/

@@ -146,3 +147,2 @@ is( type ) {

* @param {Object} [data] Additional data to be logged.
* @returns {String}
*/

@@ -172,3 +172,2 @@ export function logWarning( errorName, data ) {

* @param {Object} [data] Additional data to be logged.
* @returns {String}
*/

@@ -175,0 +174,0 @@ export function logError( errorName, data ) {

@@ -59,3 +59,3 @@ /**

*
* @param {Iterable.<Object>|Object} initialItemsOrOptions The initial items of the collection or
* @param {Iterable.<Object>|Object} [initialItemsOrOptions] The initial items of the collection or
* the options object.

@@ -62,0 +62,0 @@ * @param {Object} [options={}] The options object, when the first argument is an array of initial items.

@@ -16,2 +16,4 @@ /**

// @if CK_DEBUG_POSITION // import { RectDrawer } from '@ckeditor/ckeditor5-minimap/src/utils';
/**

@@ -78,6 +80,6 @@ * Calculates the `position: absolute` coordinates of a given element so it can be positioned with respect to the

*
* @param {module:utils/dom/position~Options} options Positioning options object.
* @param {module:utils/dom/position~Options} options The input data and configuration of the helper.
* @returns {module:utils/dom/position~Position}
*/
export function getOptimalPosition( { element, target, positions, limiter, fitInViewport } ) {
export function getOptimalPosition( { element, target, positions, limiter, fitInViewport, viewportOffsetConfig } ) {
// If the {@link module:utils/dom/position~Options#target} is a function, use what it returns.

@@ -99,48 +101,50 @@ // https://github.com/ckeditor/ckeditor5-utils/issues/157

let bestPositionRect;
let bestPositionName;
let bestPosition;
// @if CK_DEBUG_POSITION // RectDrawer.clear();
// @if CK_DEBUG_POSITION // RectDrawer.draw( targetRect, { outlineWidth: '5px' }, 'Target' );
const positionOptions = { targetRect, elementRect, positionedElementAncestor };
// If there are no limits, just grab the very first position and be done with that drama.
if ( !limiter && !fitInViewport ) {
[ bestPositionName, bestPositionRect ] = getPositionNameAndRect( positions[ 0 ], targetRect, elementRect );
bestPosition = new Position( positions[ 0 ], positionOptions );
} else {
const limiterRect = limiter && new Rect( limiter ).getVisible();
const viewportRect = fitInViewport && new Rect( global.window );
const bestPosition = getBestPositionNameAndRect( positions, { targetRect, elementRect, limiterRect, viewportRect } );
const viewportRect = fitInViewport && getConstrainedViewportRect( viewportOffsetConfig );
// @if CK_DEBUG_POSITION // if ( viewportRect ) {
// @if CK_DEBUG_POSITION // RectDrawer.draw( viewportRect, { outlineWidth: '5px' }, 'Viewport' );
// @if CK_DEBUG_POSITION // }
// @if CK_DEBUG_POSITION // if ( limiter ) {
// @if CK_DEBUG_POSITION // RectDrawer.draw( limiterRect, { outlineWidth: '5px', outlineColor: 'green' }, 'Visible limiter' );
// @if CK_DEBUG_POSITION // }
Object.assign( positionOptions, { limiterRect, viewportRect } );
// If there's no best position found, i.e. when all intersections have no area because
// rects have no width or height, then just use the first available position.
[ bestPositionName, bestPositionRect ] = bestPosition || getPositionNameAndRect( positions[ 0 ], targetRect, elementRect );
bestPosition = getBestPosition( positions, positionOptions ) || new Position( positions[ 0 ], positionOptions );
}
let absoluteRectCoordinates = getAbsoluteRectCoordinates( bestPositionRect );
if ( positionedElementAncestor ) {
absoluteRectCoordinates = shiftRectCoordinatesDueToPositionedAncestor( absoluteRectCoordinates, positionedElementAncestor );
}
return {
left: absoluteRectCoordinates.left,
top: absoluteRectCoordinates.top,
name: bestPositionName
};
return bestPosition;
}
// For given position function, returns a corresponding `Rect` instance.
// Returns a viewport `Rect` shrunk by the viewport offset config from all sides.
//
// @private
// @param {Function} position A function returning {@link module:utils/dom/position~Position}.
// @param {utils/dom/rect~Rect} targetRect A rect of the target.
// @param {utils/dom/rect~Rect} elementRect A rect of positioned element.
// @returns {Array|null} An array containing position name and its Rect (or null if position should be ignored).
function getPositionNameAndRect( position, targetRect, elementRect ) {
const positionData = position( targetRect, elementRect );
// @param {Object} An object containing viewportOffset config.
// @returns {utils/dom/rect~Rect} A shrunken rect of the viewport.
function getConstrainedViewportRect( viewportOffsetConfig ) {
viewportOffsetConfig = Object.assign( { top: 0, bottom: 0, left: 0, right: 0 }, viewportOffsetConfig );
if ( !positionData ) {
return null;
}
const viewportRect = new Rect( global.window );
const { left, top, name } = positionData;
viewportRect.top += viewportOffsetConfig.top;
viewportRect.height -= viewportOffsetConfig.top;
viewportRect.bottom -= viewportOffsetConfig.bottom;
viewportRect.height -= viewportOffsetConfig.bottom;
return [ name, elementRect.clone().moveTo( left, top ) ];
return viewportRect;
}

@@ -154,13 +158,14 @@

// @param {Object} options
// @param {module:utils/dom/position~Options#positions} positions Functions returning {@link module:utils/dom/position~Position}
// to be checked, in the order of preference.
// @param {module:utils/dom/position~Options#positions} positions Functions returning
// {@link module:utils/dom/position~Position}to be checked, in the order of preference.
// @param {Object} options
// @param {utils/dom/rect~Rect} options.targetRect A rect of the {@link module:utils/dom/position~Options#target}.
// @param {utils/dom/rect~Rect} options.elementRect A rect of positioned {@link module:utils/dom/position~Options#element}.
// @param {utils/dom/rect~Rect} options.elementRect A rect of positioned
// {@link module:utils/dom/position~Options#element}.
// @param {utils/dom/rect~Rect} options.limiterRect A rect of the {@link module:utils/dom/position~Options#limiter}.
// @param {utils/dom/rect~Rect} options.viewportRect A rect of the viewport.
// @param {utils/dom/rect~Rect} options.viewportRect A rect of the {@link module:utils/dom/position~Options#viewport}.
//
// @returns {Array} An array containing the name of the position and it's rect.
function getBestPositionNameAndRect( positions, options ) {
const { elementRect, viewportRect } = options;
function getBestPosition( positions, options ) {
const { elementRect } = options;

@@ -170,138 +175,30 @@ // This is when element is fully visible.

// Let's calculate intersection areas for positions. It will end early if best match is found.
const processedPositions = processPositionsToAreas( positions, options );
const positionInstances = positions
.map( positioningFunction => new Position( positioningFunction, options ) )
// Some positioning functions may return `null` if they don't want to participate.
.filter( position => !!position.name );
// First let's check all positions that fully fit in the viewport.
if ( viewportRect ) {
const processedPositionsInViewport = processedPositions.filter( ( { viewportIntersectArea } ) => {
return viewportIntersectArea === elementRectArea;
} );
let maxFitFactor = 0;
let bestPosition = null;
// Try to find best position from those which fit completely in viewport.
const bestPositionData = getBestOfProcessedPositions( processedPositionsInViewport, elementRectArea );
for ( const position of positionInstances ) {
const { _limiterIntersectionArea, _viewportIntersectionArea } = position;
if ( bestPositionData ) {
return bestPositionData;
}
}
// Either there is no viewportRect or there is no position that fits completely in the viewport.
return getBestOfProcessedPositions( processedPositions, elementRectArea );
}
// For a given array of positioning functions, calculates intersection areas for them.
//
// Note: If some position fully fits into the `limiterRect`, it will be returned early, without further consideration
// of other positions.
//
// @private
//
// @param {module:utils/dom/position~Options#positions} positions Functions returning {@link module:utils/dom/position~Position}
// to be checked, in the order of preference.
// @param {Object} options
// @param {utils/dom/rect~Rect} options.targetRect A rect of the {@link module:utils/dom/position~Options#target}.
// @param {utils/dom/rect~Rect} options.elementRect A rect of positioned {@link module:utils/dom/position~Options#element}.
// @param {utils/dom/rect~Rect} options.limiterRect A rect of the {@link module:utils/dom/position~Options#limiter}.
// @param {utils/dom/rect~Rect} options.viewportRect A rect of the viewport.
//
// @returns {Array.<Object>} Array of positions with calculated intersection areas. Each item is an object containing:
// * {String} positionName Name of position.
// * {utils/dom/rect~Rect} positionRect Rect of position.
// * {Number} limiterIntersectArea Area of intersection of the position with limiter part that is in the viewport.
// * {Number} viewportIntersectArea Area of intersection of the position with viewport.
function processPositionsToAreas( positions, { targetRect, elementRect, limiterRect, viewportRect } ) {
const processedPositions = [];
// This is when element is fully visible.
const elementRectArea = elementRect.getArea();
for ( const position of positions ) {
const positionData = getPositionNameAndRect( position, targetRect, elementRect );
if ( !positionData ) {
continue;
}
const [ positionName, positionRect ] = positionData;
let limiterIntersectArea = 0;
let viewportIntersectArea = 0;
if ( limiterRect ) {
if ( viewportRect ) {
// Consider only the part of the limiter which is visible in the viewport. So the limiter is getting limited.
const limiterViewportIntersectRect = limiterRect.getIntersection( viewportRect );
if ( limiterViewportIntersectRect ) {
// If the limiter is within the viewport, then check the intersection between that part of the
// limiter and actual position.
limiterIntersectArea = limiterViewportIntersectRect.getIntersectionArea( positionRect );
}
} else {
limiterIntersectArea = limiterRect.getIntersectionArea( positionRect );
}
}
if ( viewportRect ) {
viewportIntersectArea = viewportRect.getIntersectionArea( positionRect );
}
const processedPosition = {
positionName,
positionRect,
limiterIntersectArea,
viewportIntersectArea
};
// If a such position is found that element is fully contained by the limiter then, obviously,
// there will be no better one, so finishing.
if ( limiterIntersectArea === elementRectArea ) {
return [ processedPosition ];
if ( _limiterIntersectionArea === elementRectArea ) {
return position;
}
processedPositions.push( processedPosition );
}
// To maximize both viewport and limiter intersection areas we use distance on _viewportIntersectionArea
// and _limiterIntersectionArea plane (without sqrt because we are looking for max value).
const fitFactor = _viewportIntersectionArea ** 2 + _limiterIntersectionArea ** 2;
return processedPositions;
}
// For a given array of processed position data (with calculated Rects for positions and intersection areas)
// returns such that provides the best fit of the `elementRect` into the `limiterRect` and `viewportRect` at the same time.
//
// **Note**: It will return early if some position fully fits into the `limiterRect`.
//
// @private
// @param {Array.<Object>} Array of positions with calculated intersection areas (in order of preference).
// Each item is an object containing:
//
// * {String} positionName Name of position.
// * {utils/dom/rect~Rect} positionRect Rect of position.
// * {Number} limiterIntersectArea Area of intersection of the position with limiter part that is in the viewport.
// * {Number} viewportIntersectArea Area of intersection of the position with viewport.
//
// @param {Number} elementRectArea Area of positioned {@link module:utils/dom/position~Options#element}.
// @returns {Array|null} An array containing the name of the position and it's rect, or null if not found.
function getBestOfProcessedPositions( processedPositions, elementRectArea ) {
let maxFitFactor = 0;
let bestPositionRect;
let bestPositionName;
for ( const { positionName, positionRect, limiterIntersectArea, viewportIntersectArea } of processedPositions ) {
// If a such position is found that element is fully container by the limiter then, obviously,
// there will be no better one, so finishing.
if ( limiterIntersectArea === elementRectArea ) {
return [ positionName, positionRect ];
}
// To maximize both viewport and limiter intersection areas we use distance on viewportIntersectArea
// and limiterIntersectArea plane (without sqrt because we are looking for max value).
const fitFactor = viewportIntersectArea ** 2 + limiterIntersectArea ** 2;
if ( fitFactor > maxFitFactor ) {
maxFitFactor = fitFactor;
bestPositionRect = positionRect;
bestPositionName = positionName;
bestPosition = position;
}
}
return bestPositionRect ? [ bestPositionName, bestPositionRect ] : null;
return bestPosition;
}

@@ -318,13 +215,16 @@

//
// @param {Object} absoluteRectCoordinates An object with absolute rect coordinates.
// @param {Object} absoluteRectCoordinates.top
// @param {Object} absoluteRectCoordinates.left
// @param {utils/dom/rect~Rect} rect A rect with absolute rect coordinates.
// @param {Number} rect.top
// @param {Number} rect.left
// @param {HTMLElement} positionedElementAncestor An ancestor element that should be considered.
//
// @returns {Object} An object corresponding to `absoluteRectCoordinates` input but with values shifted
// @returns {utils/dom/rect~Rect} A rect corresponding to `absoluteRect` input but with values shifted
// to make up for the positioned element ancestor.
function shiftRectCoordinatesDueToPositionedAncestor( { left, top }, positionedElementAncestor ) {
const ancestorPosition = getAbsoluteRectCoordinates( new Rect( positionedElementAncestor ) );
function shiftRectToCompensatePositionedAncestor( rect, positionedElementAncestor ) {
const ancestorPosition = getRectForAbsolutePositioning( new Rect( positionedElementAncestor ) );
const ancestorBorderWidths = getBorderWidths( positionedElementAncestor );
let moveX = 0;
let moveY = 0;
// (https://github.com/ckeditor/ckeditor5-ui-default/issues/126)

@@ -334,4 +234,4 @@ // If there's some positioned ancestor of the panel, then its `Rect` must be taken into

// with respect to that positioned ancestor.
left -= ancestorPosition.left;
top -= ancestorPosition.top;
moveX -= ancestorPosition.left;
moveY -= ancestorPosition.top;

@@ -343,4 +243,4 @@ // (https://github.com/ckeditor/ckeditor5-utils/issues/139)

// must compensate that scrolling.
left += positionedElementAncestor.scrollLeft;
top += positionedElementAncestor.scrollTop;
moveX += positionedElementAncestor.scrollLeft;
moveY += positionedElementAncestor.scrollTop;

@@ -352,6 +252,6 @@ // (https://github.com/ckeditor/ckeditor5-utils/issues/139)

// not upper-left corner of its border.
left -= ancestorBorderWidths.left;
top -= ancestorBorderWidths.top;
moveX -= ancestorBorderWidths.left;
moveY -= ancestorBorderWidths.top;
return { left, top };
rect.moveBy( moveX, moveY );
}

@@ -365,12 +265,171 @@

// @returns {Object} Object containing `left` and `top` properties, in absolute coordinates.
function getAbsoluteRectCoordinates( { left, top } ) {
function getRectForAbsolutePositioning( rect ) {
const { scrollX, scrollY } = global.window;
return {
left: left + scrollX,
top: top + scrollY
};
return rect.clone().moveBy( scrollX, scrollY );
}
/**
* A position class which instances are created and used by the {@link module:utils/dom/position~getOptimalPosition} helper.
*
* {@link module:utils/dom/position~Position#top} and {@link module:utils/dom/position~Position#left} properties of the position instance
* translate directly to the `top` and `left` properties in CSS "`position: absolute` coordinate system". If set on the positioned element
* in DOM, they will make it display it in the right place in the viewport.
*/
export class Position {
/**
* Creates an instance of the {@link module:utils/dom/position~Position} class.
*
* @param {module:utils/dom/position~positioningFunction} [positioningFunction] function The function that defines the expected
* coordinates the positioned element should move to.
* @param {Object} [options] options object.
* @param {module:utils/dom/rect~Rect} options.elementRect The positioned element rect.
* @param {module:utils/dom/rect~Rect} options.targetRect The target element rect.
* @param {module:utils/dom/rect~Rect} options.viewportRect The viewport rect.
* @param {HTMLElement|null} [options.positionedElementAncestor] Nearest element ancestor element which CSS position is not "static".
*/
constructor( positioningFunction, options ) {
const positioningFunctionOutput = positioningFunction( options.targetRect, options.elementRect, options.viewportRect );
// Nameless position for a function that didn't participate.
if ( !positioningFunctionOutput ) {
return;
}
const { left, top, name, config } = positioningFunctionOutput;
Object.assign( this, { name, config } );
this._positioningFunctionCorrdinates = { left, top };
this._options = options;
/**
* Position name.
*
* @readonly
* @member {String} #name
*/
/**
* Additional position configuration, as passed from the {@link module:utils/dom/position~positioningFunction positioning function}.
*
* This object can be use, for instance, to pass through presentation options used by the consumer of the
* {@link module:utils/dom/position~getOptimalPosition} helper.
*
* @readonly
* @member {Object} #config
*/
}
/**
* The left value in pixels in the CSS `position: absolute` coordinate system.
* Set it on the positioned element in DOM to move it to the position.
*
* @readonly
* @type {Number}
*/
get left() {
return this._absoluteRect.left;
}
/**
* The top value in pixels in the CSS `position: absolute` coordinate system.
* Set it on the positioned element in DOM to move it to the position.
*
* @readonly
* @type {Number}
*/
get top() {
return this._absoluteRect.top;
}
/**
* An intersection area between positioned element and limiter within viewport constraints.
*
* @readonly
* @private
* @type {Number}
*/
get _limiterIntersectionArea() {
const limiterRect = this._options.limiterRect;
if ( limiterRect ) {
const viewportRect = this._options.viewportRect;
if ( viewportRect ) {
// Consider only the part of the limiter which is visible in the viewport. So the limiter is getting limited.
const limiterViewportIntersectRect = limiterRect.getIntersection( viewportRect );
if ( limiterViewportIntersectRect ) {
// If the limiter is within the viewport, then check the intersection between that part of the
// limiter and actual position.
return limiterViewportIntersectRect.getIntersectionArea( this._rect );
}
} else {
return limiterRect.getIntersectionArea( this._rect );
}
}
return 0;
}
/**
* An intersection area between positioned element and viewport.
*
* @readonly
* @private
* @type {Number}
*/
get _viewportIntersectionArea() {
const viewportRect = this._options.viewportRect;
if ( viewportRect ) {
return viewportRect.getIntersectionArea( this._rect );
}
return 0;
}
/**
* An already positioned element rect. A clone of the element rect passed to the constructor
* but placed in the viewport according to the positioning function.
*
* @private
* @type {module:utils/dom/rect~Rect}
*/
get _rect() {
if ( this._cachedRect ) {
return this._cachedRect;
}
this._cachedRect = this._options.elementRect.clone().moveTo(
this._positioningFunctionCorrdinates.left,
this._positioningFunctionCorrdinates.top
);
return this._cachedRect;
}
/**
* An already absolutely positioned element rect. See ({@link #_rect}).
*
* @private
* @type {module:utils/dom/rect~Rect}
*/
get _absoluteRect() {
if ( this._cachedAbsoluteRect ) {
return this._cachedAbsoluteRect;
}
this._cachedAbsoluteRect = getRectForAbsolutePositioning( this._rect );
if ( this._options.positionedElementAncestor ) {
shiftRectToCompensatePositionedAncestor( this._cachedAbsoluteRect, this._options.positionedElementAncestor );
}
return this._cachedAbsoluteRect;
}
}
/**
* The `getOptimalPosition()` helper options.

@@ -394,8 +453,11 @@ *

/**
* An array of functions which return {@link module:utils/dom/position~Position} relative
* to the `target`, in the order of preference.
* An array of positioning functions.
*
* **Note**: If a function returns `null`, it is ignored by the `getOptimalPosition()`.
* **Note**: Positioning functions are processed in the order of preference. The first function that works
* in the current environment (e.g. offers the complete fit in the viewport geometry) will be picked by
* `getOptimalPosition()`.
*
* @member {Array.<Function>} #positions
* **Note**: Any positioning function returning `null` is ignored.
*
* @member {Array.<module:utils/dom/position~positioningFunction>} #positions
*/

@@ -418,10 +480,51 @@

/**
* An object describing a position in `position: absolute` coordinate
* system, along with position name.
* Viewport offset config object. It restricts the visible viewport available to the `getOptimalPosition()` from each side.
*
* @typedef {Object} module:utils/dom/position~Position
* {
* top: 50,
* right: 50,
* bottom: 50,
* left: 50
* }
*
* @property {Number} top Top position offset.
* @property {Number} left Left position offset.
* @property {String} name Name of the position.
* @member {Object} #viewportOffsetConfig
*/
/**
* A positioning function which, based on positioned element and target {@link module:utils/dom/rect~Rect Rects}, returns rect coordinates
* representing the geometrical relation between them. Used by the {@link module:utils/dom/position~getOptimalPosition} helper.
*
* // This simple position will place the element directly under the target, in the middle:
* //
* // [ Target ]
* // +-----------------+
* // | Element |
* // +-----------------+
* //
* const position = ( targetRect, elementRect, [ viewportRect ] ) => ( {
* top: targetRect.bottom,
* left: targetRect.left + targetRect.width / 2 - elementRect.width / 2,
* name: 'bottomMiddle',
*
* // Note: The config is optional.
* config: {
* zIndex: '999'
* }
* } );
*
* @callback module:utils/dom/position~positioningFunction
* @param {module:utils/dom/rect~Rect} elementRect The rect of the element to be positioned.
* @param {module:utils/dom/rect~Rect} targetRect The rect of the target the element (its rect) is relatively positioned to.
* @param {module:utils/dom/rect~Rect} viewportRect The rect of the visual browser viewport.
* @returns {Object|null} return When the function returns `null`, it will not be considered by
* {@link module:utils/dom/position~getOptimalPosition}.
* @returns {Number} return.top The `top` value of the element rect that would represent the position.
* @returns {Number} return.left The `left` value of the element rect that would represent the position.
* @returns {Number} return.name The name of the position. It helps the user of the {@link module:utils/dom/position~getOptimalPosition}
* helper to recognize different positioning function results. It will pass through to the {@link module:utils/dom/position~Position}
* returned by the helper.
* @returns {Number} [return.config] An optional configuration that will pass-through the
* {@link module:utils/dom/position~getOptimalPosition} helper to the {@link module:utils/dom/position~Position} returned by this helper.
* This configuration may, for instance, let the user of {@link module:utils/dom/position~getOptimalPosition} know that this particular
* position comes with a certain presentation.
*/

@@ -36,2 +36,3 @@ /**

* * `f1-f12`,
* * `` ` ``, `-`, `=`, `[`, `]`, `;`, `'`, `,`, `.`, `/`, `\`,
* * `arrow(left|up|right|bottom)`,

@@ -255,2 +256,7 @@ * * `backspace`, `delete`, `enter`, `esc`, `tab`,

// other characters
for ( const char of '`-=[];\',./\\' ) {
keyCodes[ char ] = char.charCodeAt( 0 );
}
return keyCodes;

@@ -257,0 +263,0 @@ }

@@ -134,3 +134,3 @@ /**

* @param {String} language Target language.
* @param {module:utils/translation-service~Message|String} message A message that will be translated.
* @param {module:utils/translation-service~Message} message A message that will be translated.
* @param {Number} [quantity] The number of elements for which a plural form should be picked from the target language dictionary.

@@ -137,0 +137,0 @@ * @returns {String} Translated sentence.

@@ -14,3 +14,3 @@ /**

const version = '29.2.0';
const version = '30.0.0';

@@ -17,0 +17,0 @@ export default version;

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