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

@module-federation/runtime

Package Overview
Dependencies
Maintainers
8
Versions
625
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@module-federation/runtime - npm Package Compare versions

Comparing version 0.0.0-next-20241018034826 to 0.0.0-next-20241018073518

15

dist/helpers.cjs.js
'use strict';
var share = require('./share.cjs.js');
require('./polyfills.cjs.js');
require('@module-federation/sdk');
require('./polyfills.cjs.js');
var pluginHelper = /*#__PURE__*/Object.freeze({
__proto__: null,
AsyncHook: share.AsyncHook,
AsyncWaterfallHook: share.AsyncWaterfallHook,
PluginSystem: share.PluginSystem,
SyncHook: share.SyncHook,
SyncWaterfallHook: share.SyncWaterfallHook
});
const ShareUtils = {

@@ -38,5 +29,3 @@ getRegisteredShare: share.getRegisteredShare,

getPreloaded: share.getPreloaded,
setPreloaded: share.setPreloaded,
registerPlugins: share.registerPlugins,
pluginHelper
setPreloaded: share.setPreloaded
};

@@ -43,0 +32,0 @@ var helpers = {

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

import { A as AsyncHook, a as AsyncWaterfallHook, P as PluginSystem, S as SyncHook, b as SyncWaterfallHook, g as getRegisteredShare, c as getGlobalShareScope, G as Global, n as nativeGlobal, r as resetFederationGlobalInfo, d as getGlobalFederationInstance, s as setGlobalFederationInstance, e as getGlobalFederationConstructor, f as setGlobalFederationConstructor, h as getInfoWithoutType, i as getGlobalSnapshot, j as getTargetSnapshotInfoByModuleInfo, k as getGlobalSnapshotInfoByModuleInfo, l as setGlobalSnapshotInfoByModuleInfo, m as addGlobalSnapshot, o as getRemoteEntryExports, p as registerGlobalPlugins, q as getGlobalHostPlugins, t as getPreloaded, u as setPreloaded, v as registerPlugins } from './share.esm.js';
import { g as getRegisteredShare, a as getGlobalShareScope, G as Global, n as nativeGlobal, r as resetFederationGlobalInfo, b as getGlobalFederationInstance, s as setGlobalFederationInstance, c as getGlobalFederationConstructor, d as setGlobalFederationConstructor, e as getInfoWithoutType, f as getGlobalSnapshot, h as getTargetSnapshotInfoByModuleInfo, i as getGlobalSnapshotInfoByModuleInfo, j as setGlobalSnapshotInfoByModuleInfo, k as addGlobalSnapshot, l as getRemoteEntryExports, m as registerGlobalPlugins, o as getGlobalHostPlugins, p as getPreloaded, q as setPreloaded } from './share.esm.js';
import './polyfills.esm.js';
import '@module-federation/sdk';
import './polyfills.esm.js';
var pluginHelper = /*#__PURE__*/Object.freeze({
__proto__: null,
AsyncHook: AsyncHook,
AsyncWaterfallHook: AsyncWaterfallHook,
PluginSystem: PluginSystem,
SyncHook: SyncHook,
SyncWaterfallHook: SyncWaterfallHook
});
const ShareUtils = {

@@ -36,5 +27,3 @@ getRegisteredShare,

getPreloaded,
setPreloaded,
registerPlugins,
pluginHelper
setPreloaded
};

@@ -41,0 +30,0 @@ var helpers = {

2

dist/package.json
{
"name": "@module-federation/runtime",
"version": "0.6.11",
"version": "0.6.10",
"author": "zhouxiao <codingzx@gmail.com>",

@@ -5,0 +5,0 @@ "main": "./index.cjs.js",

@@ -25,2 +25,2 @@ function _extends() {

export { _extends as _, _object_without_properties_loose as a };
export { _object_without_properties_loose as _, _extends as a };
'use strict';
var polyfills = require('./polyfills.cjs.js');
var sdk = require('@module-federation/sdk');
var polyfills = require('./polyfills.cjs.js');

@@ -90,16 +90,2 @@ function getBuilderId() {

}
const processModuleAlias = (name, subPath)=>{
// @host/ ./button -> @host/button
let moduleName;
if (name.endsWith('/')) {
moduleName = name.slice(0, -1);
} else {
moduleName = name;
}
if (subPath.startsWith('.')) {
subPath = subPath.slice(1);
}
moduleName = moduleName + subPath;
return moduleName;
};

@@ -193,3 +179,3 @@ const nativeGlobal = (()=>{

globalThis.__FEDERATION__.__DEBUG_CONSTRUCTOR__ = FederationConstructor;
globalThis.__FEDERATION__.__DEBUG_CONSTRUCTOR_VERSION__ = "0.6.11";
globalThis.__FEDERATION__.__DEBUG_CONSTRUCTOR_VERSION__ = "0.6.10";
}

@@ -294,210 +280,5 @@ }

function registerPlugins(plugins, hookInstances) {
const globalPlugins = getGlobalHostPlugins();
// Incorporate global plugins
if (globalPlugins.length > 0) {
globalPlugins.forEach((plugin)=>{
if (plugins == null ? void 0 : plugins.find((item)=>item.name !== plugin.name)) {
plugins.push(plugin);
}
});
}
if (plugins && plugins.length > 0) {
plugins.forEach((plugin)=>{
hookInstances.forEach((hookInstance)=>{
hookInstance.applyPlugin(plugin);
});
});
}
return plugins;
}
const DEFAULT_SCOPE = 'default';
const DEFAULT_REMOTE_TYPE = 'global';
class SyncHook {
on(fn) {
if (typeof fn === 'function') {
this.listeners.add(fn);
}
}
once(fn) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const self = this;
this.on(function wrapper(...args) {
self.remove(wrapper);
// eslint-disable-next-line prefer-spread
return fn.apply(null, args);
});
}
emit(...data) {
let result;
if (this.listeners.size > 0) {
// eslint-disable-next-line prefer-spread
this.listeners.forEach((fn)=>{
result = fn(...data);
});
}
return result;
}
remove(fn) {
this.listeners.delete(fn);
}
removeAll() {
this.listeners.clear();
}
constructor(type){
this.type = '';
this.listeners = new Set();
if (type) {
this.type = type;
}
}
}
class AsyncHook extends SyncHook {
emit(...data) {
let result;
const ls = Array.from(this.listeners);
if (ls.length > 0) {
let i = 0;
const call = (prev)=>{
if (prev === false) {
return false; // Abort process
} else if (i < ls.length) {
return Promise.resolve(ls[i++].apply(null, data)).then(call);
} else {
return prev;
}
};
result = call();
}
return Promise.resolve(result);
}
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
function checkReturnData(originalData, returnedData) {
if (!isObject(returnedData)) {
return false;
}
if (originalData !== returnedData) {
// eslint-disable-next-line no-restricted-syntax
for(const key in originalData){
if (!(key in returnedData)) {
return false;
}
}
}
return true;
}
class SyncWaterfallHook extends SyncHook {
emit(data) {
if (!isObject(data)) {
error(`The data for the "${this.type}" hook should be an object.`);
}
for (const fn of this.listeners){
try {
const tempData = fn(data);
if (checkReturnData(data, tempData)) {
data = tempData;
} else {
this.onerror(`A plugin returned an unacceptable value for the "${this.type}" type.`);
break;
}
} catch (e) {
warn(e);
this.onerror(e);
}
}
return data;
}
constructor(type){
super(), this.onerror = error;
this.type = type;
}
}
class AsyncWaterfallHook extends SyncHook {
emit(data) {
if (!isObject(data)) {
error(`The response data for the "${this.type}" hook must be an object.`);
}
const ls = Array.from(this.listeners);
if (ls.length > 0) {
let i = 0;
const processError = (e)=>{
warn(e);
this.onerror(e);
return data;
};
const call = (prevData)=>{
if (checkReturnData(data, prevData)) {
data = prevData;
if (i < ls.length) {
try {
return Promise.resolve(ls[i++](data)).then(call, processError);
} catch (e) {
return processError(e);
}
}
} else {
this.onerror(`A plugin returned an incorrect value for the "${this.type}" type.`);
}
return data;
};
return Promise.resolve(call(data));
}
return Promise.resolve(data);
}
constructor(type){
super(), this.onerror = error;
this.type = type;
}
}
class PluginSystem {
applyPlugin(plugin) {
assert(isPlainObject(plugin), 'Plugin configuration is invalid.');
// The plugin's name is mandatory and must be unique
const pluginName = plugin.name;
assert(pluginName, 'A name must be provided by the plugin.');
if (!this.registerPlugins[pluginName]) {
this.registerPlugins[pluginName] = plugin;
Object.keys(this.lifecycle).forEach((key)=>{
const pluginLife = plugin[key];
if (pluginLife) {
this.lifecycle[key].on(pluginLife);
}
});
}
}
removePlugin(pluginName) {
assert(pluginName, 'A name is required.');
const plugin = this.registerPlugins[pluginName];
assert(plugin, `The plugin "${pluginName}" is not registered.`);
Object.keys(plugin).forEach((key)=>{
if (key !== 'name') {
this.lifecycle[key].remove(plugin[key]);
}
});
}
// eslint-disable-next-line @typescript-eslint/no-shadow
inherit({ lifecycle, registerPlugins }) {
Object.keys(lifecycle).forEach((hookName)=>{
assert(!this.lifecycle[hookName], `The hook "${hookName}" has a conflict and cannot be inherited.`);
this.lifecycle[hookName] = lifecycle[hookName];
});
Object.keys(registerPlugins).forEach((pluginName)=>{
assert(!this.registerPlugins[pluginName], `The plugin "${pluginName}" has a conflict and cannot be inherited.`);
this.applyPlugin(registerPlugins[pluginName]);
});
}
constructor(lifecycle){
this.registerPlugins = {};
this.lifecycle = lifecycle;
this.lifecycleKeys = Object.keys(lifecycle);
}
}
// fork from https://github.com/originjs/vite-plugin-federation/blob/v1.1.12/packages/lib/src/utils/semver/index.ts

@@ -1092,10 +873,5 @@ // those constants are based on https://www.rubydoc.info/gems/semantic_range/3.0.0/SemanticRange#BUILDIDENTIFIER-constant

exports.AsyncHook = AsyncHook;
exports.AsyncWaterfallHook = AsyncWaterfallHook;
exports.DEFAULT_REMOTE_TYPE = DEFAULT_REMOTE_TYPE;
exports.DEFAULT_SCOPE = DEFAULT_SCOPE;
exports.Global = Global;
exports.PluginSystem = PluginSystem;
exports.SyncHook = SyncHook;
exports.SyncWaterfallHook = SyncWaterfallHook;
exports.addGlobalSnapshot = addGlobalSnapshot;

@@ -1123,8 +899,8 @@ exports.addUniqueItem = addUniqueItem;

exports.globalLoading = globalLoading;
exports.isObject = isObject;
exports.isPlainObject = isPlainObject;
exports.isPureRemoteEntry = isPureRemoteEntry;
exports.isRemoteInfoWithEntry = isRemoteInfoWithEntry;
exports.nativeGlobal = nativeGlobal;
exports.processModuleAlias = processModuleAlias;
exports.registerGlobalPlugins = registerGlobalPlugins;
exports.registerPlugins = registerPlugins;
exports.resetFederationGlobalInfo = resetFederationGlobalInfo;

@@ -1135,1 +911,2 @@ exports.setGlobalFederationConstructor = setGlobalFederationConstructor;

exports.setPreloaded = setPreloaded;
exports.warn = warn;

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

import { _ as _object_without_properties_loose, a as _extends } from './polyfills.esm.js';
import { isBrowserEnv, isDebugMode } from '@module-federation/sdk';
import { a as _object_without_properties_loose, _ as _extends } from './polyfills.esm.js';

@@ -88,16 +88,2 @@ function getBuilderId() {

}
const processModuleAlias = (name, subPath)=>{
// @host/ ./button -> @host/button
let moduleName;
if (name.endsWith('/')) {
moduleName = name.slice(0, -1);
} else {
moduleName = name;
}
if (subPath.startsWith('.')) {
subPath = subPath.slice(1);
}
moduleName = moduleName + subPath;
return moduleName;
};

@@ -191,3 +177,3 @@ const nativeGlobal = (()=>{

globalThis.__FEDERATION__.__DEBUG_CONSTRUCTOR__ = FederationConstructor;
globalThis.__FEDERATION__.__DEBUG_CONSTRUCTOR_VERSION__ = "0.6.11";
globalThis.__FEDERATION__.__DEBUG_CONSTRUCTOR_VERSION__ = "0.6.10";
}

@@ -292,210 +278,5 @@ }

function registerPlugins(plugins, hookInstances) {
const globalPlugins = getGlobalHostPlugins();
// Incorporate global plugins
if (globalPlugins.length > 0) {
globalPlugins.forEach((plugin)=>{
if (plugins == null ? void 0 : plugins.find((item)=>item.name !== plugin.name)) {
plugins.push(plugin);
}
});
}
if (plugins && plugins.length > 0) {
plugins.forEach((plugin)=>{
hookInstances.forEach((hookInstance)=>{
hookInstance.applyPlugin(plugin);
});
});
}
return plugins;
}
const DEFAULT_SCOPE = 'default';
const DEFAULT_REMOTE_TYPE = 'global';
class SyncHook {
on(fn) {
if (typeof fn === 'function') {
this.listeners.add(fn);
}
}
once(fn) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const self = this;
this.on(function wrapper(...args) {
self.remove(wrapper);
// eslint-disable-next-line prefer-spread
return fn.apply(null, args);
});
}
emit(...data) {
let result;
if (this.listeners.size > 0) {
// eslint-disable-next-line prefer-spread
this.listeners.forEach((fn)=>{
result = fn(...data);
});
}
return result;
}
remove(fn) {
this.listeners.delete(fn);
}
removeAll() {
this.listeners.clear();
}
constructor(type){
this.type = '';
this.listeners = new Set();
if (type) {
this.type = type;
}
}
}
class AsyncHook extends SyncHook {
emit(...data) {
let result;
const ls = Array.from(this.listeners);
if (ls.length > 0) {
let i = 0;
const call = (prev)=>{
if (prev === false) {
return false; // Abort process
} else if (i < ls.length) {
return Promise.resolve(ls[i++].apply(null, data)).then(call);
} else {
return prev;
}
};
result = call();
}
return Promise.resolve(result);
}
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
function checkReturnData(originalData, returnedData) {
if (!isObject(returnedData)) {
return false;
}
if (originalData !== returnedData) {
// eslint-disable-next-line no-restricted-syntax
for(const key in originalData){
if (!(key in returnedData)) {
return false;
}
}
}
return true;
}
class SyncWaterfallHook extends SyncHook {
emit(data) {
if (!isObject(data)) {
error(`The data for the "${this.type}" hook should be an object.`);
}
for (const fn of this.listeners){
try {
const tempData = fn(data);
if (checkReturnData(data, tempData)) {
data = tempData;
} else {
this.onerror(`A plugin returned an unacceptable value for the "${this.type}" type.`);
break;
}
} catch (e) {
warn(e);
this.onerror(e);
}
}
return data;
}
constructor(type){
super(), this.onerror = error;
this.type = type;
}
}
class AsyncWaterfallHook extends SyncHook {
emit(data) {
if (!isObject(data)) {
error(`The response data for the "${this.type}" hook must be an object.`);
}
const ls = Array.from(this.listeners);
if (ls.length > 0) {
let i = 0;
const processError = (e)=>{
warn(e);
this.onerror(e);
return data;
};
const call = (prevData)=>{
if (checkReturnData(data, prevData)) {
data = prevData;
if (i < ls.length) {
try {
return Promise.resolve(ls[i++](data)).then(call, processError);
} catch (e) {
return processError(e);
}
}
} else {
this.onerror(`A plugin returned an incorrect value for the "${this.type}" type.`);
}
return data;
};
return Promise.resolve(call(data));
}
return Promise.resolve(data);
}
constructor(type){
super(), this.onerror = error;
this.type = type;
}
}
class PluginSystem {
applyPlugin(plugin) {
assert(isPlainObject(plugin), 'Plugin configuration is invalid.');
// The plugin's name is mandatory and must be unique
const pluginName = plugin.name;
assert(pluginName, 'A name must be provided by the plugin.');
if (!this.registerPlugins[pluginName]) {
this.registerPlugins[pluginName] = plugin;
Object.keys(this.lifecycle).forEach((key)=>{
const pluginLife = plugin[key];
if (pluginLife) {
this.lifecycle[key].on(pluginLife);
}
});
}
}
removePlugin(pluginName) {
assert(pluginName, 'A name is required.');
const plugin = this.registerPlugins[pluginName];
assert(plugin, `The plugin "${pluginName}" is not registered.`);
Object.keys(plugin).forEach((key)=>{
if (key !== 'name') {
this.lifecycle[key].remove(plugin[key]);
}
});
}
// eslint-disable-next-line @typescript-eslint/no-shadow
inherit({ lifecycle, registerPlugins }) {
Object.keys(lifecycle).forEach((hookName)=>{
assert(!this.lifecycle[hookName], `The hook "${hookName}" has a conflict and cannot be inherited.`);
this.lifecycle[hookName] = lifecycle[hookName];
});
Object.keys(registerPlugins).forEach((pluginName)=>{
assert(!this.registerPlugins[pluginName], `The plugin "${pluginName}" has a conflict and cannot be inherited.`);
this.applyPlugin(registerPlugins[pluginName]);
});
}
constructor(lifecycle){
this.registerPlugins = {};
this.lifecycle = lifecycle;
this.lifecycleKeys = Object.keys(lifecycle);
}
}
// fork from https://github.com/originjs/vite-plugin-federation/blob/v1.1.12/packages/lib/src/utils/semver/index.ts

@@ -1090,2 +871,2 @@ // those constants are based on https://www.rubydoc.info/gems/semantic_range/3.0.0/SemanticRange#BUILDIDENTIFIER-constant

export { AsyncHook as A, processModuleAlias as B, isRemoteInfoWithEntry as C, DEFAULT_REMOTE_TYPE as D, isPureRemoteEntry as E, getRemoteEntryInfoFromSnapshot as F, Global as G, error as H, arrayOptions as I, formatShareConfigs as J, getTargetSharedOptions as K, addUniqueItem as L, getBuilderId as M, PluginSystem as P, SyncHook as S, AsyncWaterfallHook as a, SyncWaterfallHook as b, getGlobalShareScope as c, getGlobalFederationInstance as d, getGlobalFederationConstructor as e, setGlobalFederationConstructor as f, getRegisteredShare as g, getInfoWithoutType as h, getGlobalSnapshot as i, getTargetSnapshotInfoByModuleInfo as j, getGlobalSnapshotInfoByModuleInfo as k, setGlobalSnapshotInfoByModuleInfo as l, addGlobalSnapshot as m, nativeGlobal as n, getRemoteEntryExports as o, registerGlobalPlugins as p, getGlobalHostPlugins as q, resetFederationGlobalInfo as r, setGlobalFederationInstance as s, getPreloaded as t, setPreloaded as u, registerPlugins as v, globalLoading as w, DEFAULT_SCOPE as x, assert as y, getFMId as z };
export { isPlainObject as A, isRemoteInfoWithEntry as B, isPureRemoteEntry as C, DEFAULT_REMOTE_TYPE as D, getRemoteEntryInfoFromSnapshot as E, arrayOptions as F, Global as G, formatShareConfigs as H, getTargetSharedOptions as I, addUniqueItem as J, getBuilderId as K, getGlobalShareScope as a, getGlobalFederationInstance as b, getGlobalFederationConstructor as c, setGlobalFederationConstructor as d, getInfoWithoutType as e, getGlobalSnapshot as f, getRegisteredShare as g, getTargetSnapshotInfoByModuleInfo as h, getGlobalSnapshotInfoByModuleInfo as i, setGlobalSnapshotInfoByModuleInfo as j, addGlobalSnapshot as k, getRemoteEntryExports as l, registerGlobalPlugins as m, nativeGlobal as n, getGlobalHostPlugins as o, getPreloaded as p, setPreloaded as q, resetFederationGlobalInfo as r, setGlobalFederationInstance as s, globalLoading as t, DEFAULT_SCOPE as u, assert as v, getFMId as w, isObject as x, error as y, warn as z };
import { resetFederationGlobalInfo, getGlobalFederationInstance, setGlobalFederationInstance, getGlobalFederationConstructor, setGlobalFederationConstructor, getInfoWithoutType, getGlobalSnapshot, getTargetSnapshotInfoByModuleInfo, getGlobalSnapshotInfoByModuleInfo, setGlobalSnapshotInfoByModuleInfo, addGlobalSnapshot, getRemoteEntryExports, registerGlobalPlugins, getGlobalHostPlugins, getPreloaded, setPreloaded, Global } from './global';
import { getRegisteredShare, getGlobalShareScope } from './utils/share';
import * as pluginHelper from './utils/hooks';
import { registerPlugins } from './utils';
interface IShareUtils {

@@ -28,4 +26,2 @@ getRegisteredShare: typeof getRegisteredShare;

setPreloaded: typeof setPreloaded;
registerPlugins: typeof registerPlugins;
pluginHelper: typeof pluginHelper;
}

@@ -32,0 +28,0 @@ declare const _default: {

@@ -35,7 +35,2 @@ import { GlobalModuleInfo, Manifest, ModuleInfo } from '@module-federation/sdk';

}>;
afterLoadSnapshot: AsyncWaterfallHook<{
options: Options;
moduleInfo: Remote;
remoteSnapshot: ModuleInfo;
}>;
}>;

@@ -42,0 +37,0 @@ loaderHook: FederationHost['loaderHook'];

@@ -7,3 +7,3 @@ import type { RemoteWithEntry, RemoteWithVersion, Module, RemoteEntryType } from '@module-federation/sdk';

};
export interface RemoteInfoCommon {
interface RemoteInfoCommon {
alias?: string;

@@ -10,0 +10,0 @@ shareScope?: string;

@@ -26,7 +26,6 @@ import { FederationHost } from '../core';

}>;
type LifeCycle = CoreLifeCyclePartial & SnapshotLifeCycleCyclePartial & SharedLifeCycleCyclePartial & RemoteLifeCycleCyclePartial & ModuleLifeCycleCyclePartial & {
export type FederationRuntimePlugin = CoreLifeCyclePartial & SnapshotLifeCycleCyclePartial & SharedLifeCycleCyclePartial & RemoteLifeCycleCyclePartial & ModuleLifeCycleCyclePartial & {
name: string;
version?: string;
};
export type FederationRuntimePlugin<T = LifeCycle> = LifeCycle & T;
export {};
import { FederationHost } from '../core';
import { UserOptions } from '../type';
import { Module } from '../module';
import { PluginSystem } from './hooks';
export declare function registerPlugins<Y extends Record<string, any>, T extends PluginSystem<Y>>(plugins: UserOptions['plugins'], hookInstances: Array<T | FederationHost['hooks'] | FederationHost['snapshotHandler']['hooks'] | FederationHost['sharedHandler']['hooks'] | FederationHost['remoteHandler']['hooks'] | Module['host']['loaderHook']>): import("../type").FederationRuntimePlugin[] | undefined;
export declare function registerPlugins(plugins: UserOptions['plugins'], hookInstances: Array<FederationHost['hooks'] | FederationHost['snapshotHandler']['hooks'] | FederationHost['sharedHandler']['hooks'] | FederationHost['remoteHandler']['hooks'] | Module['host']['loaderHook']>): import("../type").FederationRuntimePlugin[] | undefined;

@@ -18,2 +18,1 @@ import { RemoteWithEntry, ModuleInfo, RemoteEntryType } from '@module-federation/sdk';

};
export declare const processModuleAlias: (name: string, subPath: string) => string;
{
"name": "@module-federation/runtime",
"version": "0.0.0-next-20241018034826",
"version": "0.0.0-next-20241018073518",
"author": "zhouxiao <codingzx@gmail.com>",

@@ -53,4 +53,4 @@ "main": "./dist/index.cjs.js",

"dependencies": {
"@module-federation/sdk": "0.0.0-next-20241018034826"
"@module-federation/sdk": "0.0.0-next-20241018073518"
}
}

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

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