Socket
Socket
Sign inDemoInstall

unplugin

Package Overview
Dependencies
Maintainers
2
Versions
87
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

unplugin - npm Package Compare versions

Comparing version 1.5.1 to 1.6.0

14

dist/index.d.ts

@@ -12,3 +12,3 @@ import * as _rspack_core_dist_config_zod from '@rspack/core/dist/config/zod';

import * as esbuild from 'esbuild';
import { Plugin as Plugin$2, Loader, PluginBuild } from 'esbuild';
import { Plugin as Plugin$2, Loader, BuildOptions, PluginBuild } from 'esbuild';
export { Plugin as EsbuildPlugin } from 'esbuild';

@@ -50,3 +50,3 @@ import { Compiler as Compiler$1, RspackPluginInstance } from '@rspack/core';

load?: (this: UnpluginBuildContext & UnpluginContext, id: string) => Thenable<TransformResult>;
resolveId?: (id: string, importer: string | undefined, options: {
resolveId?: (this: UnpluginBuildContext & UnpluginContext, id: string, importer: string | undefined, options: {
isEntry: boolean;

@@ -77,2 +77,3 @@ }) => Thenable<string | ExternalIdResult | null | undefined>;

loader?: Loader | ((code: string, id: string) => Loader);
config?: (options: BuildOptions) => void;
};

@@ -122,2 +123,7 @@ }

}
declare module '@rspack/core' {
interface Compiler {
$unpluginContext: Record<string, ResolvedUnpluginOptions>;
}
}

@@ -127,6 +133,6 @@ declare function createUnplugin<UserOptions, Nested extends boolean = boolean>(factory: UnpluginFactory<UserOptions, Nested>): UnpluginInstance<UserOptions, Nested>;

declare function createRollupPlugin<UserOptions, Nested extends boolean = boolean>(factory: UnpluginFactory<UserOptions, Nested>): UnpluginFactoryOutput<UserOptions, Nested extends true ? rollup.Plugin<any>[] : rollup.Plugin<any>>;
declare function createVitePlugin<UserOptions, Nested extends boolean = boolean>(factory: UnpluginFactory<UserOptions, Nested>): UnpluginFactoryOutput<UserOptions, Nested extends true ? vite.Plugin[] : vite.Plugin>;
declare function createVitePlugin<UserOptions, Nested extends boolean = boolean>(factory: UnpluginFactory<UserOptions, Nested>): UnpluginFactoryOutput<UserOptions, Nested extends true ? vite.Plugin<any>[] : vite.Plugin<any>>;
declare function createWebpackPlugin<UserOptions, Nested extends boolean = boolean>(factory: UnpluginFactory<UserOptions, Nested>): UnpluginFactoryOutput<UserOptions, webpack.WebpackPluginInstance>;
declare function createRspackPlugin<UserOptions, Nested extends boolean = boolean>(factory: UnpluginFactory<UserOptions, Nested>): UnpluginFactoryOutput<UserOptions, _rspack_core_dist_config_zod.RspackPluginInstance>;
export { ExternalIdResult, ResolvedUnpluginOptions, SourceMapCompact, Thenable, TransformResult, UnpluginBuildContext, UnpluginContext, UnpluginContextMeta, UnpluginFactory, UnpluginFactoryOutput, UnpluginInstance, UnpluginOptions, createEsbuildPlugin, createRollupPlugin, createRspackPlugin, createUnplugin, createVitePlugin, createWebpackPlugin };
export { type ExternalIdResult, type ResolvedUnpluginOptions, type SourceMapCompact, type Thenable, type TransformResult, type UnpluginBuildContext, type UnpluginContext, type UnpluginContextMeta, type UnpluginFactory, type UnpluginFactoryOutput, type UnpluginInstance, type UnpluginOptions, createEsbuildPlugin, createRollupPlugin, createRspackPlugin, createUnplugin, createVitePlugin, createWebpackPlugin };

@@ -1138,2 +1138,20 @@ "use strict";

}
function shouldLoad(id, plugin, externalModules) {
if (id.startsWith(plugin.__virtualModulePrefix))
id = decodeURIComponent(id.slice(plugin.__virtualModulePrefix.length));
if (plugin.loadInclude && !plugin.loadInclude(id))
return false;
return !externalModules.has(id);
}
function transformUse(data, plugin, transformLoader) {
if (data.resource == null)
return [];
const id = normalizeAbsolutePath(data.resource + (data.resourceQuery || ""));
if (!plugin.transformInclude || plugin.transformInclude(id)) {
return [{
loader: `${transformLoader}?unpluginName=${encodeURIComponent(plugin.name)}`
}];
}
return [];
}

@@ -1216,3 +1234,4 @@ // src/esbuild/utils.ts

}
function createEsbuildContext(initialOptions) {
function createBuildContext(initialOptions) {
const watchFiles = [];
return {

@@ -1228,2 +1247,3 @@ parse(code, opts = {}) {

addWatchFile() {
throw new Error("unplugin/esbuild: addWatchFile outside supported hooks (resolveId, load, transform)");
},

@@ -1238,6 +1258,30 @@ emitFile(emittedFile) {

getWatchFiles() {
return [];
return watchFiles;
}
};
}
function createPluginContext(context) {
const errors = [];
const warnings = [];
const pluginContext = {
error(message) {
errors.push({ text: String(message) });
},
warn(message) {
warnings.push({ text: String(message) });
}
};
const mixedContext = {
...context,
...pluginContext,
addWatchFile(id) {
context.getWatchFiles().push(id);
}
};
return {
errors,
warnings,
mixedContext
};
}
function processCodeWithSourceMap(map, code) {

@@ -1268,3 +1312,5 @@ if (map) {

const loader = plugin.esbuild?.loader ?? guessLoader;
const context = createEsbuildContext(initialOptions);
const context = createBuildContext(initialOptions);
if (plugin.esbuild?.config)
plugin.esbuild.config.call(context, initialOptions);
if (plugin.buildStart)

@@ -1285,14 +1331,30 @@ onStart(() => plugin.buildStart.call(context));

}
const { errors, warnings, mixedContext } = createPluginContext(context);
const isEntry = args.kind === "entry-point";
const result = await plugin.resolveId(
const result = await plugin.resolveId.call(
mixedContext,
args.path,
// We explicitly have this if statement here for consistency with the integration of other bundelers.
// Here, `args.importer` is just an empty string on entry files whereas the euqivalent on other bundlers is `undefined.`
// We explicitly have this if statement here for consistency with the integration of other bundlers.
// Here, `args.importer` is just an empty string on entry files whereas the equivalent on other bundlers is `undefined.`
isEntry ? void 0 : args.importer,
{ isEntry }
);
if (typeof result === "string")
return { path: result, namespace: plugin.name };
else if (typeof result === "object" && result !== null)
return { path: result.id, external: result.external, namespace: plugin.name };
if (typeof result === "string") {
return {
path: result,
namespace: plugin.name,
errors,
warnings,
watchFiles: mixedContext.getWatchFiles()
};
} else if (typeof result === "object" && result !== null) {
return {
path: result.id,
external: result.external,
namespace: plugin.name,
errors,
warnings,
watchFiles: mixedContext.getWatchFiles()
};
}
});

@@ -1303,16 +1365,7 @@ }

const id = args.path + args.suffix;
const errors = [];
const warnings = [];
const pluginContext = {
error(message) {
errors.push({ text: String(message) });
},
warn(message) {
warnings.push({ text: String(message) });
}
};
const { errors, warnings, mixedContext } = createPluginContext(context);
const resolveDir = import_path3.default.dirname(args.path);
let code, map;
if (plugin.load && (!plugin.loadInclude || plugin.loadInclude(id))) {
const result = await plugin.load.call(Object.assign(context, pluginContext), id);
const result = await plugin.load.call(mixedContext, id);
if (typeof result === "string") {

@@ -1330,3 +1383,10 @@ code = result;

code = processCodeWithSourceMap(map, code);
return { contents: code, errors, warnings, loader: unwrapLoader(loader, code, args.path), resolveDir };
return {
contents: code,
errors,
warnings,
watchFiles: mixedContext.getWatchFiles(),
loader: unwrapLoader(loader, code, args.path),
resolveDir
};
}

@@ -1337,3 +1397,3 @@ if (!plugin.transformInclude || plugin.transformInclude(id)) {

}
const result = await plugin.transform.call(Object.assign(context, pluginContext), code, id);
const result = await plugin.transform.call(mixedContext, code, id);
if (typeof result === "string") {

@@ -1356,3 +1416,10 @@ code = result;

code = processCodeWithSourceMap(map, code);
return { contents: code, errors, warnings, loader: unwrapLoader(loader, code, args.path), resolveDir };
return {
contents: code,
errors,
warnings,
watchFiles: mixedContext.getWatchFiles(),
loader: unwrapLoader(loader, code, args.path),
resolveDir
};
}

@@ -1443,8 +1510,9 @@ });

__dirname,
false ? "../../dist/rspack/loaders/transform" : "rspack/loaders/transform"
false ? "../../dist/rspack/loaders/transform.js" : "rspack/loaders/transform"
);
var LOAD_LOADER = (0, import_path4.resolve)(
__dirname,
false ? "../../dist/rspack/loaders/load" : "rspack/loaders/load"
false ? "../../dist/rspack/loaders/load.js" : "rspack/loaders/load"
);
var VIRTUAL_MODULE_PREFIX = (0, import_path4.resolve)(process.cwd(), "_virtual_");
function getRspackPlugin(factory) {

@@ -1454,2 +1522,4 @@ return (userOptions) => {

apply(compiler) {
const injected = compiler.$unpluginContext || {};
compiler.$unpluginContext = injected;
const meta = {

@@ -1462,23 +1532,39 @@ framework: "rspack",

const rawPlugins = toArray(factory(userOptions, meta));
for (const plugin of rawPlugins) {
for (const rawPlugin of rawPlugins) {
const plugin = Object.assign(
rawPlugin,
{
__unpluginMeta: meta,
__virtualModulePrefix: VIRTUAL_MODULE_PREFIX
}
);
injected[plugin.name] = plugin;
compiler.hooks.thisCompilation.tap(plugin.name, (compilation) => {
if (typeof compilation.hooks.childCompiler === "undefined")
throw new Error("`compilation.hooks.childCompiler` only support by @rspack/core>=0.4.1");
compilation.hooks.childCompiler.tap(plugin.name, (childCompiler) => {
childCompiler.$unpluginContext = injected;
});
});
const externalModules = /* @__PURE__ */ new Set();
if (plugin.load) {
const use = {
loader: LOAD_LOADER,
options: { plugin }
};
compiler.options.module.rules.unshift({
enforce: plugin.enforce,
include: /.*/,
use
include(id) {
return shouldLoad(id, plugin, externalModules);
},
use: [{
loader: LOAD_LOADER,
options: {
unpluginName: plugin.name
}
}]
});
}
if (plugin.transform) {
const use = {
loader: TRANSFORM_LOADER,
options: { plugin }
};
compiler.options.module.rules.unshift({
enforce: plugin.enforce,
include: /.*/,
use
use(data) {
return transformUse(data, plugin, TRANSFORM_LOADER);
}
});

@@ -1550,2 +1636,4 @@ }

addWatchFile(id) {
if (!compilation)
throw new Error("unplugin/webpack: addWatchFile outside supported hooks (buildStart, buildEnd, load, transform, watchChange)");
(compilation.fileDependencies ?? compilation.compilationDependencies).add(

@@ -1558,2 +1646,4 @@ (0, import_path5.resolve)(import_process.default.cwd(), id)

if (emittedFile.source && outFileName) {
if (!compilation)
throw new Error("unplugin/webpack: emitFile outside supported hooks (buildStart, buildEnd, load, transform, watchChange)");
compilation.emitAsset(

@@ -1572,2 +1662,4 @@ outFileName,

getWatchFiles() {
if (!compilation)
throw new Error("unplugin/webpack: getWatchFiles outside supported hooks (buildStart, buildEnd, load, transform, watchChange)");
return Array.from(

@@ -1589,3 +1681,3 @@ compilation.fileDependencies ?? compilation.compilationDependencies

);
var VIRTUAL_MODULE_PREFIX = (0, import_path6.resolve)(import_process2.default.cwd(), "_virtual_");
var VIRTUAL_MODULE_PREFIX2 = (0, import_path6.resolve)(import_process2.default.cwd(), "_virtual_");
function getWebpackPlugin(factory) {

@@ -1609,3 +1701,3 @@ return (userOptions) => {

__unpluginMeta: meta,
__virtualModulePrefix: VIRTUAL_MODULE_PREFIX
__virtualModulePrefix: VIRTUAL_MODULE_PREFIX2
}

@@ -1640,3 +1732,18 @@ );

const isEntry = requestContext.issuer === "";
const resolveIdResult = await plugin.resolveId(id, importer, { isEntry });
const context = createContext();
let error;
const pluginContext = {
error(msg) {
if (error == null)
error = typeof msg === "string" ? new Error(msg) : msg;
else
console.error(`unplugin/webpack: multiple errors returned from resolveId hook: ${msg}`);
},
warn(msg) {
console.warn(`unplugin/webpack: warning from resolveId hook: ${msg}`);
}
};
const resolveIdResult = await plugin.resolveId.call({ ...context, ...pluginContext }, id, importer, { isEntry });
if (error != null)
return callback(error);
if (resolveIdResult == null)

@@ -1672,7 +1779,3 @@ return callback();

include(id) {
if (id.startsWith(plugin.__virtualModulePrefix))
id = decodeURIComponent(id.slice(plugin.__virtualModulePrefix.length));
if (plugin.loadInclude && !plugin.loadInclude(id))
return false;
return !externalModules.has(id);
return shouldLoad(id, plugin, externalModules);
},

@@ -1689,15 +1792,6 @@ enforce: plugin.enforce,

if (plugin.transform) {
const useLoader = [{
loader: `${TRANSFORM_LOADER2}?unpluginName=${encodeURIComponent(plugin.name)}`
}];
const useNone = [];
compiler.options.module.rules.unshift({
enforce: plugin.enforce,
use: (data) => {
if (data.resource == null)
return useNone;
const id = normalizeAbsolutePath(data.resource + (data.resourceQuery || ""));
if (!plugin.transformInclude || plugin.transformInclude(id))
return useLoader;
return useNone;
use(data) {
return transformUse(data, plugin, TRANSFORM_LOADER2);
}

@@ -1704,0 +1798,0 @@ });

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

const callback = this.async();
const { unpluginName } = this.query;
const plugin = this._compiler?.$unpluginContext[unpluginName];
const id = this.resource;
const { plugin } = this.getOptions();
if (!plugin?.load || !id)

@@ -87,0 +88,0 @@ return callback(null, source, map);

@@ -74,8 +74,13 @@ "use strict";

const callback = this.async();
let unpluginName;
if (typeof this.query === "string") {
const query = new URLSearchParams(this.query);
unpluginName = query.get("unpluginName");
} else {
unpluginName = this.query.unpluginName;
}
const id = this.resource;
const { plugin } = this.getOptions();
const plugin = this._compiler?.$unpluginContext[unpluginName];
if (!plugin?.transform)
return callback(null, source, map);
if (plugin.transformInclude && !plugin.transformInclude(id))
return callback(null, source, map);
const context = {

@@ -82,0 +87,0 @@ error: (error) => this.emitError(typeof error === "string" ? new Error(error) : error),

@@ -54,2 +54,4 @@ "use strict";

addWatchFile(id) {
if (!compilation)
throw new Error("unplugin/webpack: addWatchFile outside supported hooks (buildStart, buildEnd, load, transform, watchChange)");
(compilation.fileDependencies ?? compilation.compilationDependencies).add(

@@ -62,2 +64,4 @@ (0, import_path.resolve)(import_process.default.cwd(), id)

if (emittedFile.source && outFileName) {
if (!compilation)
throw new Error("unplugin/webpack: emitFile outside supported hooks (buildStart, buildEnd, load, transform, watchChange)");
compilation.emitAsset(

@@ -76,2 +80,4 @@ outFileName,

getWatchFiles() {
if (!compilation)
throw new Error("unplugin/webpack: getWatchFiles outside supported hooks (buildStart, buildEnd, load, transform, watchChange)");
return Array.from(

@@ -108,3 +114,3 @@ compilation.fileDependencies ?? compilation.compilationDependencies

const res = await plugin.load.call(
Object.assign(this._compilation && createContext(this._compilation), context),
{ ...this._compilation && createContext(this._compilation), ...context },
normalizeAbsolutePath(id)

@@ -111,0 +117,0 @@ );

@@ -54,2 +54,4 @@ "use strict";

addWatchFile(id) {
if (!compilation)
throw new Error("unplugin/webpack: addWatchFile outside supported hooks (buildStart, buildEnd, load, transform, watchChange)");
(compilation.fileDependencies ?? compilation.compilationDependencies).add(

@@ -62,2 +64,4 @@ (0, import_path.resolve)(import_process.default.cwd(), id)

if (emittedFile.source && outFileName) {
if (!compilation)
throw new Error("unplugin/webpack: emitFile outside supported hooks (buildStart, buildEnd, load, transform, watchChange)");
compilation.emitAsset(

@@ -76,2 +80,4 @@ outFileName,

getWatchFiles() {
if (!compilation)
throw new Error("unplugin/webpack: getWatchFiles outside supported hooks (buildStart, buildEnd, load, transform, watchChange)");
return Array.from(

@@ -101,3 +107,7 @@ compilation.fileDependencies ?? compilation.compilationDependencies

};
const res = await plugin.transform.call(Object.assign(this._compilation && createContext(this._compilation), context), source, this.resource);
const res = await plugin.transform.call(
{ ...this._compilation && createContext(this._compilation), ...context },
source,
this.resource
);
if (res == null)

@@ -104,0 +114,0 @@ callback(null, source, map);

{
"name": "unplugin",
"version": "1.5.1",
"packageManager": "pnpm@8.10.0",
"version": "1.6.0",
"packageManager": "pnpm@8.12.1",
"description": "Unified plugin system for build tools",

@@ -34,3 +34,3 @@ "license": "MIT",

"release": "bumpp --all -x 'npx conventional-changelog -p angular -i CHANGELOG.md -s' && npm publish",
"test": "nr lint && nr test:build && vitest run",
"test": "nr lint && nr test:build && vitest run --pool=forks",
"test:build": "jiti scripts/buildFixtures.ts"

@@ -42,29 +42,29 @@ },

"webpack-sources": "^3.2.3",
"webpack-virtual-modules": "^0.6.0"
"webpack-virtual-modules": "^0.6.1"
},
"devDependencies": {
"@ampproject/remapping": "^2.2.1",
"@antfu/eslint-config": "^1.0.0-beta.29",
"@antfu/ni": "^0.21.8",
"@rspack/cli": "^0.3.8",
"@rspack/core": "^0.3.8",
"@types/fs-extra": "^11.0.3",
"@types/node": "^20.8.9",
"@types/webpack-sources": "^3.2.2",
"bumpp": "^9.2.0",
"@antfu/eslint-config": "^2.6.0",
"@antfu/ni": "^0.21.12",
"@rspack/cli": "^0.4.5",
"@rspack/core": "^0.4.5",
"@types/fs-extra": "^11.0.4",
"@types/node": "^20.10.5",
"@types/webpack-sources": "^3.2.3",
"bumpp": "^9.2.1",
"conventional-changelog-cli": "^4.1.0",
"esbuild": "^0.19.5",
"eslint": "^8.52.0",
"fast-glob": "^3.3.1",
"fs-extra": "^11.1.1",
"jiti": "^1.20.0",
"lint-staged": "^15.0.2",
"esbuild": "^0.19.10",
"eslint": "^8.56.0",
"fast-glob": "^3.3.2",
"fs-extra": "^11.2.0",
"jiti": "^1.21.0",
"lint-staged": "^15.2.0",
"magic-string": "^0.30.5",
"picocolors": "^1.0.0",
"rollup": "^4.1.4",
"rollup": "^4.9.1",
"simple-git-hooks": "^2.9.0",
"tsup": "^7.2.0",
"typescript": "^5.2.2",
"vite": "^4.5.0",
"vitest": "^0.34.6",
"tsup": "^8.0.1",
"typescript": "^5.3.3",
"vite": "^5.0.10",
"vitest": "^1.1.0",
"webpack": "^5.89.0",

@@ -71,0 +71,0 @@ "webpack-cli": "4.10.0"

@@ -47,12 +47,14 @@ # unplugin

| Hook | Rollup | Vite | Webpack 4 | Webpack 5 | esbuild | Rspack |
| -------------------------------------------------------------------------- | :----: | :--: | :-------: | :-------: | :-----: | :----: |
| [`this.parse`](https://rollupjs.org/guide/en/#thisparse) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| [`this.addWatchFile`](https://rollupjs.org/guide/en/#thisaddwatchfile) | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| [`this.emitFile`](https://rollupjs.org/guide/en/#thisemitfile)<sup>5</sup> | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| [`this.getWatchFiles`](https://rollupjs.org/guide/en/#thisgetwatchfiles) | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| [`this.warn`](https://rollupjs.org/guide/en/#thiswarn) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| [`this.error`](https://rollupjs.org/guide/en/#thiserror) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Hook | Rollup | Vite | Webpack 4 | Webpack 5 | esbuild | Rspack |
| -------------------------------------------------------------------------- | :----: | :--: | :-------: | :-------: | :------------: | :----: |
| [`this.parse`](https://rollupjs.org/guide/en/#thisparse) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| [`this.addWatchFile`](https://rollupjs.org/guide/en/#thisaddwatchfile) | ✅ | ✅ | ✅<sup>6</sup> | ✅ | ✅<sup>7</sup> | ❌ |
| [`this.emitFile`](https://rollupjs.org/guide/en/#thisemitfile)<sup>5</sup> | ✅ | ✅ | ✅<sup>6</sup> | ✅ | ✅ | ✅ |
| [`this.getWatchFiles`](https://rollupjs.org/guide/en/#thisgetwatchfiles) | ✅ | ✅ | ✅<sup>6</sup> | ✅ | ✅<sup>7</sup> | ❌ |
| [`this.warn`](https://rollupjs.org/guide/en/#thiswarn) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| [`this.error`](https://rollupjs.org/guide/en/#thiserror) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
5. Currently, [`this.emitFile`](https://rollupjs.org/guide/en/#thisemitfile) only supports the `EmittedAsset` variant.
6. Currently, in Webpack, [`this.addWatchFile`](https://rollupjs.org/guide/en/#thisgetwatchfiles), [`this.emitFile`](https://rollupjs.org/guide/en/#thisemitfile), and [`this.getWatchFiles`](https://rollupjs.org/guide/en/#thisgetwatchfiles) are not supported within `resolveId` hooks.
7. Currently, in esbuild, [`this.addWatchFile`](https://rollupjs.org/guide/en/#thisgetwatchfiles) and [`this.getWatchFiles`](https://rollupjs.org/guide/en/#thisgetwatchfiles) are supported only within `resolveId`, `load`, and `transform` hooks; and [`this.getWatchFiles`](https://rollupjs.org/guide/en/#thisgetwatchfiles) returns an array of only the files explicitly watched via [`this.addWatchFile`](https://rollupjs.org/guide/en/#thisaddwatchfile) during the same resolve step (`resolveId` hook) or load step (`load` and `transform` hooks).

@@ -175,3 +177,2 @@ ## Usage

###### Rspack

@@ -228,2 +229,6 @@

// Read and/or modify build.initialOptions
// [https://esbuild.github.io/plugins/#build-options]
// config?: (initialOptions: BuildOptions) => void
// Or you can completely replace the setup logic

@@ -230,0 +235,0 @@ // setup?: EsbuildPlugin.setup,

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc