New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@neo4j/practicle

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@neo4j/practicle - npm Package Compare versions

Comparing version 0.1.4 to 0.1.5

HEAD

106

lib/draftReleaseToGithub.js

@@ -9,109 +9,7 @@ #!/usr/bin/env node

var _regenerator = require("babel-runtime/regenerator");
var _releaseToGithub = require("./releaseToGithub");
var _regenerator2 = _interopRequireDefault(_regenerator);
var _asyncToGenerator2 = require("babel-runtime/helpers/asyncToGenerator");
var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);
var publishDraftRelease = function () {
var _ref = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee(args, content, repoInfo) {
var owner, repo, nextVersion, commit, result;
return _regenerator2.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
owner = repoInfo.owner, repo = repoInfo.repo;
nextVersion = args.nextVersion, commit = args.commit;
_context.prev = 2;
_context.next = 5;
return octokit.repos.createRelease({
owner: owner,
repo: repo,
tag_name: nextVersion,
target_commitish: commit,
name: nextVersion,
body: content,
draft: true,
prerelease: false
});
case 5:
result = _context.sent;
if (result.status === 201) {
console.log(result.data.html_url.split("/").reverse()[0]);
} else {
console.log("Draft release failed", result.status);
}
return _context.abrupt("return", result);
case 10:
_context.prev = 10;
_context.t0 = _context["catch"](2);
console.error("Cannot create github release: " + _context.t0);
case 13:
case "end":
return _context.stop();
}
}
}, _callee, this, [[2, 10]]);
}));
return function publishDraftRelease(_x, _x2, _x3) {
return _ref.apply(this, arguments);
};
}();
var main = function () {
var _ref2 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee2(args, content) {
return _regenerator2.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
_context2.next = 2;
return publishDraftRelease(args, content, (0, _github.extractFromGithubUrl)(args.repo));
case 2:
case "end":
return _context2.stop();
}
}
}, _callee2, this);
}));
return function main(_x4, _x5) {
return _ref2.apply(this, arguments);
};
}();
/* main*/
var _fs = require("fs");
var fs = _interopRequireWildcard(_fs);
var _rest = require("@octokit/rest");
var _rest2 = _interopRequireDefault(_rest);
var _github = require("./helpers/github");
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var octokit = new _rest2.default();
var init = exports.init = function init(args) {
octokit.authenticate({
type: "token",
token: args.token
});
main(args, fs.readFileSync(args.file, "utf8"));
(0, _releaseToGithub.init)({ ...args, draft: true });
};

@@ -7,3 +7,3 @@ #!/usr/bin/env node

});
exports.init = undefined;
exports.init = exports.isValidReleaseTag = exports.defaultReleaseTagFormat = undefined;

@@ -18,2 +18,10 @@ var _getIterator2 = require("babel-runtime/core-js/get-iterator");

var _set = require("babel-runtime/core-js/set");
var _set2 = _interopRequireDefault(_set);
var _from = require("babel-runtime/core-js/array/from");
var _from2 = _interopRequireDefault(_from);
var _toConsumableArray2 = require("babel-runtime/helpers/toConsumableArray");

@@ -31,4 +39,4 @@

var fetchAllReleases = function () {
var _ref = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee2(repoInfo) {
var fetchAllTags = function () {
var _ref = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee2(repoInfo, options) {
var getReleases = function () {

@@ -61,3 +69,3 @@ var _ref2 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee(page) {

return function getReleases(_x2) {
return function getReleases(_x3) {
return _ref2.apply(this, arguments);

@@ -96,8 +104,15 @@ };

case 13:
return _context2.abrupt("return", results.filter(function (_) {
return (/^\d/.test(_.name)
);
if (!options.filterString) {
_context2.next = 17;
break;
}
return _context2.abrupt("return", results.filter(function (res) {
return isValidReleaseTag(options.filterString, res.name);
}));
case 14:
case 17:
return _context2.abrupt("return", results);
case 18:
case "end":

@@ -110,3 +125,3 @@ return _context2.stop();

return function fetchAllReleases(_x) {
return function fetchAllTags(_x, _x2) {
return _ref.apply(this, arguments);

@@ -143,3 +158,3 @@ };

return function fetchCommitsBetween(_x3, _x4, _x5) {
return function fetchCommitsBetween(_x4, _x5, _x6) {
return _ref3.apply(this, arguments);

@@ -150,3 +165,3 @@ };

var getAllPullRequests = function () {
var _ref4 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee5(repoInfo) {
var _ref4 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee5(repoInfo, labelFilter) {
var getPullRequests = function () {

@@ -180,3 +195,3 @@ var _ref5 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee4(page) {

return function getPullRequests(_x7) {
return function getPullRequests(_x9) {
return _ref5.apply(this, arguments);

@@ -216,3 +231,4 @@ };

return _context5.abrupt("return", results.map(function (pr) {
var changelogMessage = (0, _changelog.extractChangeLogMessage)(pr);
var changelogMessage = (0, _changelog.extractChangeLogMessage)(pr, labelFilter);
var issues = (0, _changelog.extractIssuesFromString)(pr.body);
var url = pr.url,

@@ -226,2 +242,3 @@ merge_commit_sha = pr.merge_commit_sha,

message: changelogMessage,
issues: issues,
number: number,

@@ -243,3 +260,3 @@ url: url

return function getAllPullRequests(_x6) {
return function getAllPullRequests(_x7, _x8) {
return _ref4.apply(this, arguments);

@@ -251,3 +268,3 @@ };

var _ref6 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee6(args) {
var repoInfo, prs, releases, releaseTags, sortedList, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, _ref7, _ref8, index, value, nextRelease, thisRelease, commits, commitsToPrs;
var repoInfo, prs, releases, releaseTags, nextTag, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, _ref7, _ref8, index, value, nextRelease, thisRelease, commits, commitsToPrs;

@@ -260,3 +277,3 @@ return _regenerator2.default.wrap(function _callee6$(_context6) {

_context6.next = 3;
return getAllPullRequests(repoInfo);
return getAllPullRequests(repoInfo, args.labelFilter);

@@ -266,14 +283,29 @@ case 3:

_context6.next = 6;
return fetchAllReleases(repoInfo);
return fetchAllTags(repoInfo, {
filterString: args.releaseTagFilter || defaultReleaseTagFormat
});
case 6:
releases = _context6.sent;
releaseTags = releases.map(function (release) {
releaseTags = [args.nextVersion].concat((0, _from2.default)(new _set2.default(releases.map(function (release) {
return release.name;
}).filter(function (name) {
return (0, _utils.versionFilter)(name, args.prevVersion, args.nextVersion);
});
}))));
releaseTags.push(args.nextVersion);
sortedList = _semverSort2.default.desc(releaseTags);
if ((0, _utils.isValidSemVer)(args.prevVersion)) {
releaseTags = releaseTags.filter(function (name) {
return (0, _utils.versionFilter)(name, args.prevVersion, args.nextVersion);
});
releaseTags = _semverSort2.default.desc(releaseTags);
}
if (args.prevVersion === true) {
releaseTags = releaseTags.filter(function (t) {
return t && (0, _utils.isValidSemVer)(t);
});
releaseTags = _semverSort2.default.desc(releaseTags);
nextTag = releaseTags.indexOf(args.nextVersion);
releaseTags = releaseTags.slice(nextTag, nextTag + 2);
}
_iteratorNormalCompletion = true;

@@ -283,3 +315,3 @@ _didIteratorError = false;

_context6.prev = 13;
_iterator = (0, _getIterator3.default)(sortedList.entries());
_iterator = (0, _getIterator3.default)(releaseTags.entries());

@@ -296,4 +328,4 @@ case 15:

value = _ref8[1];
nextRelease = sortedList[index + 1];
thisRelease = value === args.nextVersion ? args.lastCommit : value;
nextRelease = releaseTags[index + 1];
thisRelease = value === args.nextVersion ? args.releaseCommit : value;

@@ -372,3 +404,3 @@ if (!(!value || !nextRelease)) {

return function main(_x8) {
return function main(_x10) {
return _ref6.apply(this, arguments);

@@ -399,2 +431,7 @@ };

var defaultReleaseTagFormat = exports.defaultReleaseTagFormat = "^v?\\d+\\.\\d+\\.\\d+$";
var isValidReleaseTag = exports.isValidReleaseTag = function isValidReleaseTag(re, tag) {
return new RegExp(re, "i").test(tag);
};
var init = exports.init = function init(args) {

@@ -401,0 +438,0 @@ octokit.authenticate({

@@ -6,9 +6,8 @@ "use strict";

});
var extractChangeLogMessage = exports.extractChangeLogMessage = function extractChangeLogMessage(obj) {
var extractChangeLogMessage = exports.extractChangeLogMessage = function extractChangeLogMessage(obj, labelFilter) {
var label = obj.labels.filter(function (l) {
return l.name === "changelog";
return labelFilter.includes(l.name);
});
var changelogRegex = /(^|\n|\r)changelog\:(.*)/i;
var changelogRegex = /(^|\n|\r)changelog\:(.*)/;
var getMessage = function getMessage(obj) {

@@ -22,9 +21,16 @@ var regexMatch = obj.body && obj.body.match(changelogRegex);

var extractIssuesFromString = exports.extractIssuesFromString = function extractIssuesFromString(str) {
var fixesRegex = /(^|\n|\r)fixes\:(.*)/i;
var regexMatch = str && str.match(fixesRegex);
return regexMatch && regexMatch.length >= 2 && regexMatch[2] ? "Issue(s): " + regexMatch[2].trim() : "";
};
var newLine = "\n";
var buildOutput = exports.buildOutput = function buildOutput(logs, header, repoInfo, outputPrLinks) {
var out = "\n## " + header + "\n ";
var out = "\n## " + header + "\n";
logs.forEach(function (_) {
out += outputPrLinks ? "\n- " + _.message + " [#" + _.number + "](https://github.com/" + repoInfo.owner + "/" + repoInfo.repo + "/pull/" + _.number + ")" : "\n- " + _.message;
out += outputPrLinks ? newLine + ("- " + _.message + " PR: [#" + _.number + "](https://github.com/" + repoInfo.owner + "/" + repoInfo.repo + "/pull/" + _.number + ") " + _.issues).trim() + newLine : newLine + ("- " + _.message + " " + _.issues).trim() + newLine;
});
console.log(out);
};

@@ -16,8 +16,12 @@ "use strict";

var _releaseToGithub = require("../releaseToGithub");
var _relaseNotesFromGithub = require("../relaseNotesFromGithub");
var _utils = require("./utils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var setUpCli = exports.setUpCli = function setUpCli() {
return _yargs2.default.command("generate-changelog", "Generate release notes", commandLineSetUp, _generateChangelog.init).command("draft-release", "Create draft release on Github", commandLineSetUpPublish, _draftReleaseToGithub.init).command("fetch-release-notes", "Fetch release notes from Github", commandLineSetUpFetch, _relaseNotesFromGithub.init).demandCommand().argv;
return _yargs2.default.command("generate-changelog", "Generate release notes", commandLineSetUp, _generateChangelog.init).command("draft-release", "Create draft release on Github", commandLineSetUpPublish, _draftReleaseToGithub.init).command("release", "Create release on Github", commandLineSetUpPublish, _releaseToGithub.init).command("fetch-release-notes", "Fetch release notes from Github", commandLineSetUpFetch, _relaseNotesFromGithub.init).demandCommand().argv;
};

@@ -40,5 +44,5 @@

},
"last-commit": {
alias: "lc",
describe: "The last commit hash to be considered for the changelog",
"release-commit": {
alias: "rc",
describe: "The commit hash to be considered as the release for the changelog",
demandOption: true

@@ -52,4 +56,21 @@ },

alias: "pv",
describe: "The prev version tag you wish to begin the log generation from"
describe: "The prev version to generate the changelog from.\n - If arg is a valid Semver string (x.x.x) then the changelog will generate notes from the tag\n - If used as a flag then the changelog is generated from the previous semver tag.\n - If ommitted then the semver major.minor version is used to generate changelogs over that range\n "
},
"release-tag-filter": {
alias: "rtf",
describe: "The regex to filter out releases by their release tags",
default: "^v?\\d+\\.\\d+\\.\\d+$"
},
"label-filter": {
alias: "lf",
describe: "Override the pull requests label filter",
type: "array",
default: ["changelog"]
}
}).check(function (argv) {
if (!(argv.prevVersion === undefined || argv.prevVersion === true || (0, _utils.isValidSemVer)(argv.prevVersion))) {
throw new Error("--prevVersion is invalid");
} else {
return true;
}
}).help().alias("h", "help");

@@ -59,3 +80,3 @@ };

var commandLineSetUpPublish = function commandLineSetUpPublish(y) {
return y.env("GITHUB_TOKEN").option("token", {
return y.env("GITHUB").option("token", {
describe: "GITHUB_TOKEN env should be set",

@@ -87,3 +108,3 @@ demandOption: true

var commandLineSetUpFetch = function commandLineSetUpFetch(y) {
return y.env("GITHUB_TOKEN").option("token", {
return y.env("GITHUB").option("token", {
describe: "GITHUB_TOKEN env should be set",

@@ -90,0 +111,0 @@ demandOption: true

@@ -6,4 +6,8 @@ "use strict";

});
exports.versionFilter = undefined;
exports.isValidSemVer = exports.versionFilter = undefined;
var _semver = require("semver");
var _semver2 = _interopRequireDefault(_semver);
var _semverCompare = require("semver-compare");

@@ -18,2 +22,6 @@

return prevVersion ? (0, _semverCompare2.default)(name, prevVersion) >= 0 : name.startsWith(prevVersion || [tokenizedNextVersion[0], tokenizedNextVersion[1]].join("."));
};
var isValidSemVer = exports.isValidSemVer = function isValidSemVer(str) {
return _semver2.default.valid(str);
};

@@ -9,2 +9,6 @@ #!/usr/bin/env node

var _toConsumableArray2 = require("babel-runtime/helpers/toConsumableArray");
var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2);
var _regenerator = require("babel-runtime/regenerator");

@@ -18,30 +22,76 @@

var getRelease = function () {
var _ref = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee(tag, repoInfo) {
var owner, repo, result;
return _regenerator2.default.wrap(function _callee$(_context) {
var fetchAllReleases = function () {
var _ref = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee2(repoInfo) {
var getReleases = function () {
var _ref2 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee(page) {
var result;
return _regenerator2.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return octokit.repos.getReleases({
owner: repoInfo.owner,
repo: repoInfo.repo,
per_page: perPage,
page: page
});
case 2:
result = _context.sent;
return _context.abrupt("return", result.data);
case 4:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
return function getReleases(_x2) {
return _ref2.apply(this, arguments);
};
}();
var perPage, results, page, stillGettingReleases, data;
return _regenerator2.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context.prev = _context.next) {
switch (_context2.prev = _context2.next) {
case 0:
owner = repoInfo.owner, repo = repoInfo.repo;
_context.next = 3;
return octokit.repos.getReleaseByTag({
owner: owner,
repo: repo,
tag: tag
});
perPage = 30;
results = [];
page = 1;
stillGettingReleases = true;
case 3:
result = _context.sent;
return _context.abrupt("return", result.data);
case 4:
if (!stillGettingReleases) {
_context2.next = 13;
break;
}
case 5:
_context2.next = 7;
return getReleases(page);
case 7:
data = _context2.sent;
results = [].concat((0, _toConsumableArray3.default)(results), (0, _toConsumableArray3.default)(data));
stillGettingReleases = data.length === perPage;
page += 1;
_context2.next = 4;
break;
case 13:
return _context2.abrupt("return", results);
case 14:
case "end":
return _context.stop();
return _context2.stop();
}
}
}, _callee, this);
}, _callee2, this);
}));
return function getRelease(_x, _x2) {
return function fetchAllReleases(_x) {
return _ref.apply(this, arguments);

@@ -52,17 +102,20 @@ };

var main = function () {
var _ref2 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee2(args) {
var release;
return _regenerator2.default.wrap(function _callee2$(_context2) {
var _ref3 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee3(args) {
var releases, release;
return _regenerator2.default.wrap(function _callee3$(_context3) {
while (1) {
switch (_context2.prev = _context2.next) {
switch (_context3.prev = _context3.next) {
case 0:
_context2.prev = 0;
_context2.next = 3;
return getRelease(args.tag, (0, _github.extractFromGithubUrl)(args.repo));
_context3.prev = 0;
_context3.next = 3;
return fetchAllReleases((0, _github.extractFromGithubUrl)(args.repo));
case 3:
release = _context2.sent;
releases = _context3.sent;
release = releases.find(function (_) {
return _.tag_name === args.tag;
});
if (!(release && release.body)) {
_context2.next = 8;
if (!(release && release.body !== undefined)) {
_context3.next = 9;
break;

@@ -72,28 +125,28 @@ }

console.log(release.body);
_context2.next = 9;
_context3.next = 10;
break;
case 8:
case 9:
throw new Error("No release body found");
case 9:
_context2.next = 14;
case 10:
_context3.next = 15;
break;
case 11:
_context2.prev = 11;
_context2.t0 = _context2["catch"](0);
case 12:
_context3.prev = 12;
_context3.t0 = _context3["catch"](0);
console.log("An error occurred. Make sure you specify a Github release tag (a tag that is marked as a release in Github)", _context2.t0.message);
console.log("An error occurred. Make sure you specify a Github release tag (a tag that is marked as a release in Github)", _context3.t0.message);
case 14:
case 15:
case "end":
return _context2.stop();
return _context3.stop();
}
}
}, _callee2, this, [[0, 11]]);
}, _callee3, this, [[0, 12]]);
}));
return function main(_x3) {
return _ref2.apply(this, arguments);
return _ref3.apply(this, arguments);
};

@@ -114,3 +167,2 @@ }();

var octokit = new _rest2.default();
var init = exports.init = function init(args) {

@@ -117,0 +169,0 @@ octokit.authenticate({

{
"name": "@neo4j/practicle",
"version": "0.1.4",
"version": "0.1.5",
"description": "the pr-activated-changelog-emitter - Generate a changelog from PR:s in a Github repo",

@@ -51,2 +51,3 @@ "repository": {

"babel-runtime": "^6.26.0",
"semver": "^5.5.1",
"semver-compare": "^1.0.0",

@@ -53,0 +54,0 @@ "semver-sort": "^0.0.4",

@@ -7,4 +7,2 @@ <p align="center">

# Installation

@@ -36,20 +34,38 @@

If `release-tag-filter` is included, which should be a **regex** string, it will be used to filter out releases by their tags. Default value complies with semantic versioning that can optionally start with a _v_, like 1.0.1 or v1.0.1
# Usage
```bash
Options:
--token GITHUB_TOKEN env should be set [required]
--repo, -r Github repo to pull changes from [required]
--next-version, --nv The next version of the software to be release
--token GITHUB_TOKEN env should be set [required]
--repo, -r Github repo to pull changes from [required]
--next-version, --nv The next version of the software to be release
[required]
--last-commit, --lc The last commit hash to be considered for the
changelog [required]
--output-pr-links, --opl Adds the corresponding Github link at the end of the
change message
--prev-version, --pv The prev version tag you wish to begin the log
generation from
--release-commit, --rc The commit hash to be considered as the release
for the changelog [required]
--output-pr-links, --opl Adds the corresponding Github link at the end of
the change message
--prev-version, --pv The prev version to generate the
changelog from.
- If arg is a valid Semver string
(x.x.x) then the changelog will
generate notes from the tag
- If used as a flag then the changelog
is generated from the previous semver
tag.
- If ommitted then the semver
major.minor version is used to
generate changelogs over that range
--release-tag-filter, --rtf The regex to filter out releases by their release
tags [default: "^v?\d+\.\d+\.\d+$"]
--label-filter, --lf Override the pull requests label filter
[array] [default: ["changelog"]]
```
## `draft-release`
Takes contents from a file and creates a draft release on GitHub using that contents.
Takes contents from a file and creates a _draft_ release on GitHub using that contents.
```bash

@@ -63,7 +79,22 @@ Options:

release description [required]
```
## `release`
Takes contents from a file and creates a release on GitHub using that contents.
```bash
Options:
--token GITHUB_TOKEN env should be set [required]
--repo, -r Github repo to push draft release to [required]
--next-version, --nv The next version of the software to be release[required]
--commit, -c The commit that will be tagged [required]
--file File from which to read that will be used for the
release description [required]
```
## `fetch-release-notes`
Fetches release notes from a release tag (or draft release tag) from Github and outputs it to standard out.
```

@@ -86,3 +117,3 @@ Options:

--next-version=3.2.5 \
--last-commit=195694b5479ccc22d144d4ad5f81d74a1ceedb0e \
--release-commit=195694b5479ccc22d144d4ad5f81d74a1ceedb0e \
--output-pr-links \

@@ -98,3 +129,3 @@ --token=xxx

--prev-version=3.2.4 \
--last-commit=195694b5479ccc22d144d4ad5f81d74a1ceedb0e \
--release-commit=195694b5479ccc22d144d4ad5f81d74a1ceedb0e \
--output-pr-links \

@@ -105,2 +136,13 @@ --token=xxx \

```bash
# Only consider releases with name being in the format of `d.d.0`, so where patch is 0
# Output to standard output
practicle generate-changelog \
--repo=https://github.com/neo4j/neo4j-browser \
--next-version=3.2.5 \
--release-commit=195694b5479ccc22d144d4ad5f81d74a1ceedb0e \
--token=xxx
--release-tag-filter='^(?:\d*\.){2}0$'
```
### Output

@@ -114,3 +156,3 @@

--next-version=3.2.6 \
--last-commit=7ee472bedcc2e73023e9cf09708e597913ff70cd \
--release-commit=7ee472bedcc2e73023e9cf09708e597913ff70cd \
--output-pr-links \

@@ -117,0 +159,0 @@ --token=xxx

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