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

@jupyterlab/coreutils

Package Overview
Dependencies
Maintainers
7
Versions
355
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@jupyterlab/coreutils - npm Package Compare versions

Comparing version 0.12.0 to 0.13.0

lib/dataconnector.d.ts

3

lib/activitymonitor.js

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

*/
var ActivityMonitor = (function () {
var ActivityMonitor = /** @class */ (function () {
/**

@@ -86,2 +86,1 @@ * Construct a new activity monitor.

exports.ActivityMonitor = ActivityMonitor;
//# sourceMappingURL=activitymonitor.js.map
export * from './activitymonitor';
export * from './dataconnector';
export * from './interfaces';
export * from './markdowncodeblocks';
export * from './modeldb';
export * from './nbformat';
export * from './observablejson';
export * from './observablelist';
export * from './observablemap';
export * from './observablestring';
export * from './pageconfig';

@@ -16,4 +12,3 @@ export * from './path';

export * from './time';
export * from './undoablelist';
export * from './url';
export * from './uuid';

@@ -9,9 +9,5 @@ "use strict";

__export(require("./activitymonitor"));
__export(require("./dataconnector"));
__export(require("./markdowncodeblocks"));
__export(require("./modeldb"));
__export(require("./nbformat"));
__export(require("./observablejson"));
__export(require("./observablelist"));
__export(require("./observablemap"));
__export(require("./observablestring"));
__export(require("./pageconfig"));

@@ -23,5 +19,3 @@ __export(require("./path"));

__export(require("./time"));
__export(require("./undoablelist"));
__export(require("./url"));
__export(require("./uuid"));
//# sourceMappingURL=index.js.map

@@ -21,7 +21,7 @@ /**

*/
export interface IDataConnector<T, U = T> {
export interface IDataConnector<T, U = T, V = string> {
/**
* Retrieve a saved bundle from the data connector.
* Retrieve an item from the data connector.
*
* @param id - The identifier used to retrieve a data bundle.
* @param id - The identifier used to retrieve an item.
*

@@ -31,9 +31,8 @@ * @returns A promise that bears a data payload if available.

* #### Notes
* The promise returned by this method may be rejected if an error
* occurs in retrieving the data. Non-existence of an `id` will
* succeed with `undefined`.
* The promise returned by this method may be rejected if an error occurs in
* retrieving the data. Nonexistence of an `id` will succeed with `undefined`.
*/
fetch(id: string): Promise<T | undefined>;
fetch(id: V): Promise<T | undefined>;
/**
* Remove a value from the data connector.
* Remove a value using the data connector.
*

@@ -44,5 +43,5 @@ * @param id - The identifier for the data being removed.

*/
remove(id: string): Promise<void>;
remove(id: V): Promise<void>;
/**
* Save a value in the data connector.
* Save a value using the data connector.
*

@@ -55,3 +54,3 @@ * @param id - The identifier for the data being saved.

*/
save(id: string, value: U): Promise<void>;
save(id: V, value: U): Promise<void>;
}

@@ -5,2 +5,1 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=interfaces.js.map

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

];
var MarkdownCodeBlock = (function () {
var MarkdownCodeBlock = /** @class */ (function () {
function MarkdownCodeBlock(startLine) {

@@ -99,2 +99,1 @@ this.startLine = startLine;

})(MarkdownCodeBlocks = exports.MarkdownCodeBlocks || (exports.MarkdownCodeBlocks = {}));
//# sourceMappingURL=markdowncodeblocks.js.map

@@ -121,2 +121,1 @@ "use strict";

})(nbformat = exports.nbformat || (exports.nbformat = {}));
//# sourceMappingURL=nbformat.js.map

@@ -123,2 +123,1 @@ "use strict";

})(PageConfig = exports.PageConfig || (exports.PageConfig = {}));
//# sourceMappingURL=pageconfig.js.map

@@ -148,2 +148,1 @@ "use strict";

})(PathExt = exports.PathExt || (exports.PathExt = {}));
//# sourceMappingURL=path.js.map

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

import { JSONObject, JSONValue, Token } from '@phosphor/coreutils';
import { JSONObject, JSONValue, ReadonlyJSONObject, Token } from '@phosphor/coreutils';
import { IDisposable } from '@phosphor/disposable';

@@ -18,16 +18,2 @@ import { ISignal } from '@phosphor/signaling';

/**
* Add a schema to the validator.
*
* @param plugin - The plugin ID.
*
* @param schema - The schema being added.
*
* @return A list of errors if the schema fails to validate or `null` if there
* are no errors.
*
* #### Notes
* It is safe to call this function multiple times with the same plugin name.
*/
addSchema(plugin: string, schema: ISettingRegistry.ISchema): ISchemaValidator.IError[] | null;
/**
* Validate a plugin's schema and user data; populate the `composite` data.

@@ -38,6 +24,9 @@ *

*
* @param populate - Whether plugin data should be populated, defaults to
* `true`.
*
* @return A list of errors if either the schema or data fail to validate or
* `null` if there are no errors.
*/
validateData(plugin: ISettingRegistry.IPlugin): ISchemaValidator.IError[] | null;
validateData(plugin: ISettingRegistry.IPlugin, populate?: boolean): ISchemaValidator.IError[] | null;
}

@@ -65,2 +54,6 @@ /**

/**
* Optional parameter metadata that might be included in an error.
*/
params?: ReadonlyJSONObject;
/**
* The path in the schema where the error occurred.

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

/**
* The raw user settings data as a string containing JSON with comments.
*/
raw: string;
/**
* The JSON schema for the plugin.

@@ -178,2 +175,6 @@ */

/**
* The plugin settings raw text value.
*/
readonly raw: string;
/**
* Get the plugin settings schema.

@@ -223,3 +224,3 @@ */

*/
save(user: JSONObject): Promise<void>;
save(raw: string): Promise<void>;
/**

@@ -238,2 +239,10 @@ * Set a single setting.

set(key: string, value: JSONValue): Promise<void>;
/**
* Validates raw settings with comments.
*
* @param raw - The JSON with comments string being validated.
*
* @returns A list of errors or `null` if valid.
*/
validate(raw: string): ISchemaValidator.IError[] | null;
}

@@ -255,2 +264,15 @@ }

/**
* Validate a plugin's schema and user data; populate the `composite` data.
*
* @param plugin - The plugin being validated. Its `composite` data will be
* populated by reference.
*
* @param populate - Whether plugin data should be populated, defaults to
* `true`.
*
* @return A list of errors if either the schema or data fail to validate or
* `null` if there are no errors.
*/
validateData(plugin: ISettingRegistry.IPlugin, populate?: boolean): ISchemaValidator.IError[] | null;
/**
* Add a schema to the validator.

@@ -268,13 +290,3 @@ *

*/
addSchema(plugin: string, schema: ISettingRegistry.ISchema): ISchemaValidator.IError[] | null;
/**
* Validate a plugin's schema and user data; populate the `composite` data.
*
* @param plugin - The plugin being validated. Its `composite` data will be
* populated by reference.
*
* @return A list of errors if either the schema or data fail to validate or
* `null` if there are no errors.
*/
validateData(plugin: ISettingRegistry.IPlugin): ISchemaValidator.IError[] | null;
private _addSchema(plugin, schema);
private _composer;

@@ -296,2 +308,6 @@ private _validator;

/**
* The schema validator used by the setting registry.
*/
readonly validator: ISchemaValidator;
/**
* A signal that emits the name of a plugin when its settings change.

@@ -361,10 +377,9 @@ */

*
* @param plugin - The name of the plugin whose settings are being set.
*
* @param raw - The raw plugin settings being uploaded.
*
* @returns A promise that resolves when the settings have been saved.
*
* #### Notes
* Only the `user` data will be saved.
*/
upload(raw: ISettingRegistry.IPlugin): Promise<void>;
upload(plugin: string, raw: string): Promise<void>;
/**

@@ -381,3 +396,2 @@ * Save a plugin in the registry.

private _plugins;
private _validator;
}

@@ -409,2 +423,6 @@ /**

/**
* Get the plugin settings raw text value.
*/
readonly raw: string;
/**
* Get the user settings.

@@ -463,3 +481,3 @@ */

*/
save(user: JSONObject): Promise<void>;
save(raw: string): Promise<void>;
/**

@@ -479,2 +497,10 @@ * Set a single setting.

/**
* Validates raw settings with comments.
*
* @param raw - The JSON with comments string being validated.
*
* @returns A list of errors or `null` if valid.
*/
validate(raw: string): ISchemaValidator.IError[] | null;
/**
* Handle plugin changes in the setting registry.

@@ -486,2 +512,3 @@ */

private _isDisposed;
private _raw;
private _schema;

@@ -501,3 +528,3 @@ private _user;

*/
connector: IDataConnector<ISettingRegistry.IPlugin, JSONObject>;
connector: IDataConnector<ISettingRegistry.IPlugin, string>;
/**

@@ -504,0 +531,0 @@ * The validator used to enforce the settings JSON schema.

"use strict";
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
var Ajv = require("ajv");
var json = require("comment-json");
var algorithm_1 = require("@phosphor/algorithm");

@@ -29,3 +38,3 @@ var coreutils_1 = require("@phosphor/coreutils");

*/
var DefaultSchemaValidator = (function () {
var DefaultSchemaValidator = /** @class */ (function () {
/**

@@ -41,2 +50,59 @@ * Instantiate a schema validator.

/**
* Validate a plugin's schema and user data; populate the `composite` data.
*
* @param plugin - The plugin being validated. Its `composite` data will be
* populated by reference.
*
* @param populate - Whether plugin data should be populated, defaults to
* `true`.
*
* @return A list of errors if either the schema or data fail to validate or
* `null` if there are no errors.
*/
DefaultSchemaValidator.prototype.validateData = function (plugin, populate) {
if (populate === void 0) { populate = true; }
var validate = this._validator.getSchema(plugin.id);
var compose = this._composer.getSchema(plugin.id);
// If the schemas do not exist, add them to the validator and continue.
if (!validate || !compose) {
var errors = this._addSchema(plugin.id, plugin.schema);
if (errors) {
return errors;
}
return this.validateData(plugin);
}
// Parse the raw commented JSON into a user map.
var user;
try {
var strip = true;
user = json.parse(plugin.raw, null, strip);
}
catch (error) {
if (error instanceof SyntaxError) {
return [{
dataPath: '', keyword: 'syntax', schemaPath: '',
message: error.message
}];
}
var column = error.column, description = error.description;
var line = error.lineNumber;
return [{
dataPath: '', keyword: 'parse', schemaPath: '',
message: description + " (line " + line + " column " + column + ")"
}];
}
if (!validate(user)) {
return validate.errors;
}
// Copy the user data before merging defaults into composite map.
var composite = copy(user);
if (!compose(composite)) {
return compose.errors;
}
if (populate) {
plugin.data = { composite: composite, user: user };
}
return null;
};
/**
* Add a schema to the validator.

@@ -54,3 +120,3 @@ *

*/
DefaultSchemaValidator.prototype.addSchema = function (plugin, schema) {
DefaultSchemaValidator.prototype._addSchema = function (plugin, schema) {
var composer = this._composer;

@@ -75,30 +141,2 @@ var validator = this._validator;

};
/**
* Validate a plugin's schema and user data; populate the `composite` data.
*
* @param plugin - The plugin being validated. Its `composite` data will be
* populated by reference.
*
* @return A list of errors if either the schema or data fail to validate or
* `null` if there are no errors.
*/
DefaultSchemaValidator.prototype.validateData = function (plugin) {
var validate = this._validator.getSchema(plugin.id);
var compose = this._composer.getSchema(plugin.id);
if (!validate || !compose) {
var errors = this.addSchema(plugin.id, plugin.schema);
if (errors) {
return errors;
}
}
if (!validate(plugin.data.user)) {
return validate.errors;
}
// Copy the user data before validating (and merging defaults).
plugin.data.composite = copy(plugin.data.user);
if (!compose(plugin.data.composite)) {
return compose.errors;
}
return null;
};
return DefaultSchemaValidator;

@@ -110,3 +148,3 @@ }());

*/
var SettingRegistry = (function () {
var SettingRegistry = /** @class */ (function () {
/**

@@ -123,3 +161,3 @@ * Create a new setting registry.

this._connector = options.connector;
this._validator = options.validator || new DefaultSchemaValidator();
this.validator = options.validator || new DefaultSchemaValidator();
}

@@ -163,4 +201,4 @@ Object.defineProperty(SettingRegistry.prototype, "pluginChanged", {

var result = {
composite: key in composite ? copy(composite[key]) : void 0,
user: key in user ? copy(user[key]) : void 0
composite: key in composite ? copy(composite[key]) : undefined,
user: key in user ? copy(user[key]) : undefined
};

@@ -202,2 +240,3 @@ return Promise.resolve(result);

var plugins = this._plugins;
var registry = this;
// If the plugin needs to be loaded from the connector, fetch.

@@ -221,6 +260,3 @@ return connector.fetch(plugin).then(function (data) {

_this._pluginChanged.emit(plugin);
return new Settings({
plugin: copy(plugins[plugin]),
registry: _this
});
return new Settings({ plugin: plugins[plugin], registry: registry });
});

@@ -240,5 +276,9 @@ };

if (!(plugin in plugins)) {
return Promise.resolve(void 0);
return Promise.resolve(undefined);
}
delete plugins[plugin].data.user[key];
var raw = json.parse(plugins[plugin].raw);
// Delete both the value and any associated comment.
delete raw[key];
delete raw["// " + key];
plugins[plugin].raw = json.stringify(raw);
return this._save(plugin);

@@ -264,4 +304,6 @@ };

}
plugins[plugin].data.user[key] = value;
var raw = json.parse(plugins[plugin].raw);
plugins[plugin].raw = json.stringify(__assign({}, raw, (_a = {}, _a[key] = value, _a)));
return this._save(plugin);
var _a;
};

@@ -271,22 +313,16 @@ /**

*
* @param plugin - The name of the plugin whose settings are being set.
*
* @param raw - The raw plugin settings being uploaded.
*
* @returns A promise that resolves when the settings have been saved.
*
* #### Notes
* Only the `user` data will be saved.
*/
SettingRegistry.prototype.upload = function (raw) {
SettingRegistry.prototype.upload = function (plugin, raw) {
var _this = this;
var plugins = this._plugins;
var plugin = raw.id;
var errors = null;
// Validate the user data and create the composite data.
raw.data.user = raw.data.user || {};
delete raw.data.composite;
errors = this._validator.validateData(raw);
if (errors) {
return Promise.reject(errors);
if (!(plugin in plugins)) {
return this.load(plugin).then(function () { return _this.upload(plugin, raw); });
}
// Set the local copy.
plugins[plugin] = raw;
plugins[plugin].raw = raw;
return this._save(plugin);

@@ -301,6 +337,14 @@ };

if (!(plugin in plugins)) {
return Promise.reject(plugin + " does not exist in setting registry.");
var message = plugin + " does not exist in setting registry.";
return Promise.reject(new Error(message));
}
this._validate(plugins[plugin]);
return this._connector.save(plugin, plugins[plugin].data.user)
try {
this._validate(plugins[plugin]);
}
catch (errors) {
var message = plugin + " failed to validate; check console for errors.";
console.warn(plugin + " validation errors:", errors);
return Promise.reject(new Error(message));
}
return this._connector.save(plugin, plugins[plugin].raw)
.then(function () { _this._pluginChanged.emit(plugin); });

@@ -312,12 +356,4 @@ };

SettingRegistry.prototype._validate = function (plugin) {
var errors = null;
// Add the schema to the registry.
errors = this._validator.addSchema(plugin.id, plugin.schema);
if (errors) {
throw errors;
}
// Validate the user data and create the composite data.
plugin.data.user = plugin.data.user || {};
delete plugin.data.composite;
errors = this._validator.validateData(plugin);
var errors = this.validator.validateData(plugin);
if (errors) {

@@ -335,3 +371,3 @@ throw errors;

*/
var Settings = (function () {
var Settings = /** @class */ (function () {
/**

@@ -344,2 +380,3 @@ * Instantiate a new plugin settings manager.

this._isDisposed = false;
this._raw = '{ }';
this._schema = Object.create(null);

@@ -351,2 +388,3 @@ this._user = Object.create(null);

this._composite = plugin.data.composite || {};
this._raw = plugin.raw || '{ }';
this._schema = plugin.schema || { type: 'object' };

@@ -396,2 +434,12 @@ this._user = plugin.data.user || {};

});
Object.defineProperty(Settings.prototype, "raw", {
/**
* Get the plugin settings raw text value.
*/
get: function () {
return this._raw;
},
enumerable: true,
configurable: true
});
Object.defineProperty(Settings.prototype, "user", {

@@ -447,4 +495,4 @@ /**

return {
composite: key in composite ? copy(composite[key]) : void 0,
user: key in user ? copy(user[key]) : void 0
composite: key in composite ? copy(composite[key]) : undefined,
user: key in user ? copy(user[key]) : undefined
};

@@ -468,8 +516,4 @@ };

*/
Settings.prototype.save = function (user) {
return this.registry.upload({
id: this.plugin,
data: { composite: this._composite, user: user },
schema: this._schema
});
Settings.prototype.save = function (raw) {
return this.registry.upload(this.plugin, raw);
};

@@ -492,2 +536,16 @@ /**

/**
* Validates raw settings with comments.
*
* @param raw - The JSON with comments string being validated.
*
* @returns A list of errors or `null` if valid.
*/
Settings.prototype.validate = function (raw) {
var data = { composite: {}, user: {} };
var id = this.plugin;
var schema = this._schema;
var validator = this.registry.validator;
return validator.validateData({ data: data, id: id, raw: raw, schema: schema }, false);
};
/**
* Handle plugin changes in the setting registry.

@@ -502,7 +560,8 @@ */

var _a = found.data, composite = _a.composite, user = _a.user;
var schema = found.schema;
var raw = found.raw, schema = found.schema;
this._composite = composite || {};
this._raw = raw;
this._schema = schema || { type: 'object' };
this._user = user || {};
this._changed.emit(void 0);
this._changed.emit(undefined);
}

@@ -535,2 +594,6 @@ };

/**
* The default indentation level, uses spaces instead of tabs.
*/
var indent = ' ';
/**
* Replacement text for schema properties missing a `description` field.

@@ -553,2 +616,3 @@ */

var keys = Object.keys(properties).sort(function (a, b) { return a.localeCompare(b); });
var length = Math.max((description || nondescript).length, plugin.length);
return [

@@ -559,3 +623,3 @@ '{',

prefix(description || nondescript),
prefix(line((description || nondescript).length)),
prefix(line(length)),
'',

@@ -574,3 +638,3 @@ keys.map(function (key) { return docstring(schema, key); }).join('\n\n'),

var defaults = reified === undefined ? prefix("\"" + key + "\": " + undefaulted)
: prefix("\"" + key + "\": " + JSON.stringify(reified, null, 2), ' ');
: prefix("\"" + key + "\": " + JSON.stringify(reified, null, 2), indent);
return [

@@ -593,3 +657,3 @@ prefix("" + (title || untitled)),

function prefix(source, pre) {
if (pre === void 0) { pre = ' \/\/ '; }
if (pre === void 0) { pre = indent + "// "; }
return pre + source.split('\n').join("\n" + pre);

@@ -618,2 +682,1 @@ }

})(Private = exports.Private || (exports.Private = {}));
//# sourceMappingURL=settingregistry.js.map

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

import { ReadonlyJSONObject, Token } from '@phosphor/coreutils';
import { IDataConnector } from '.';
import { ReadonlyJSONValue, Token } from '@phosphor/coreutils';
import { IDataConnector } from './interfaces';
/**

@@ -18,3 +18,3 @@ * The default state database token.

*/
value: ReadonlyJSONObject;
value: ReadonlyJSONValue;
}

@@ -24,3 +24,3 @@ /**

*/
export interface IStateDB extends IDataConnector<ReadonlyJSONObject> {
export interface IStateDB extends IDataConnector<ReadonlyJSONValue> {
/**

@@ -101,3 +101,3 @@ * The maximum allowed length of the data after it has been serialized.

*/
fetch(id: string): Promise<ReadonlyJSONObject | undefined>;
fetch(id: string): Promise<ReadonlyJSONValue | undefined>;
/**

@@ -144,3 +144,3 @@ * Retrieve all the saved bundles for a namespace.

*/
save(id: string, value: ReadonlyJSONObject): Promise<void>;
save(id: string, value: ReadonlyJSONValue): Promise<void>;
}

@@ -147,0 +147,0 @@ /**

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

*/
var StateDB = (function () {
var StateDB = /** @class */ (function () {
/**

@@ -40,3 +40,3 @@ * Create a new state database.

}
return Promise.resolve(void 0);
return Promise.resolve(undefined);
};

@@ -67,3 +67,4 @@ /**

try {
return Promise.resolve(JSON.parse(value));
var envelope = JSON.parse(value);
return Promise.resolve(envelope.v);
}

@@ -100,5 +101,6 @@ catch (error) {

try {
var envelope = JSON.parse(value);
items.push({
id: key.replace(regex, ''),
value: value ? JSON.parse(value) : undefined
value: envelope ? envelope.v : undefined
});

@@ -123,3 +125,3 @@ }

window.localStorage.removeItem(this.namespace + ":" + id);
return Promise.resolve(void 0);
return Promise.resolve(undefined);
};

@@ -145,3 +147,4 @@ /**

var key = this.namespace + ":" + id;
var serialized = JSON.stringify(value);
var envelope = { v: value };
var serialized = JSON.stringify(envelope);
var length_1 = serialized.length;

@@ -153,3 +156,3 @@ var max = this.maxLength;

window.localStorage.setItem(key, serialized);
return Promise.resolve(void 0);
return Promise.resolve(undefined);
}

@@ -163,2 +166,1 @@ catch (error) {

exports.StateDB = StateDB;
//# sourceMappingURL=statedb.js.map

@@ -75,2 +75,1 @@ "use strict";

})(Text = exports.Text || (exports.Text = {}));
//# sourceMappingURL=text.js.map

@@ -39,2 +39,1 @@ "use strict";

})(Time = exports.Time || (exports.Time = {}));
//# sourceMappingURL=time.js.map

@@ -99,2 +99,1 @@ "use strict";

})(URLExt = exports.URLExt || (exports.URLExt = {}));
//# sourceMappingURL=url.js.map

@@ -21,2 +21,1 @@ "use strict";

exports.uuid = uuid;
//# sourceMappingURL=uuid.js.map
{
"name": "@jupyterlab/coreutils",
"version": "0.12.0",
"version": "0.13.0",
"description": "JupyterLab - Core Utilities",

@@ -28,2 +28,3 @@ "homepage": "https://github.com/jupyterlab/jupyterlab",

"clean": "rimraf lib",
"prepublishOnly": "npm run build",
"watch": "tsc -w"

@@ -35,5 +36,5 @@ },

"@phosphor/disposable": "^1.1.2",
"@phosphor/messaging": "^1.2.2",
"@phosphor/signaling": "^1.2.2",
"ajv": "~5.1.6",
"comment-json": "^1.1.3",
"minimist": "~1.2.0",

@@ -45,6 +46,7 @@ "moment": "~2.17.1",

"devDependencies": {
"@types/comment-json": "^1.1.0",
"@types/minimist": "~1.2.0",
"rimraf": "~2.6.2",
"typescript": "~2.4.2"
"typescript": "~2.6.2"
}
}
# @jupyterlab/coreutils
A JupyterLab package which provides utility functions and data structures that are widely used across many
of the `@jupyterlab` packages. This includes (among other things) functions for manipulating paths, urls, strings, lists, and maps.
A JupyterLab package which provides utility functions that are widely used across many
of the `@jupyterlab` packages. This includes (among other things) functions for manipulating paths, urls, and the notebook format.
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