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

aki-api

Package Overview
Dependencies
Maintainers
1
Versions
29
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

aki-api - npm Package Compare versions

Comparing version 6.0.9 to 7.0.0

239

dist/src/Akinator.js

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

const https_proxy_agent_1 = require("https-proxy-agent");
const axios_1 = require("axios");
const html_entities_1 = require("html-entities");
const FormData = require("form-data");
var answers;

@@ -15,3 +18,3 @@ (function (answers) {

answers[answers["ProbablyNot"] = 4] = "ProbablyNot";
})(answers = exports.answers || (exports.answers = {}));
})(answers || (exports.answers = answers = {}));
class Akinator {

@@ -25,10 +28,8 @@ constructor({ region, childMode, proxyOptions }) {

this.uri = undefined;
this.urlApiWs = undefined;
this.guess = undefined;
this.progress = 0.00;
this.step_last_proposition = '';
this.guessCount = 0;
this.childMode = {
childMod: childMode === true,
softConstraint: childMode === true ? encodeURIComponent("ETAT='EN'") : '',
questionFilter: childMode === true ? encodeURIComponent('cat=1') : '',
};
this.childMode = childMode === true;
this.uri = `https://${this.region}.akinator.com`;
if (proxyOptions) {

@@ -50,33 +51,21 @@ this.config = {

async start() {
const server = await (0, functions_1.regionURL)(this.region, this.config);
if (!server)
throw new Error(`Could not find a server matching the region ${this.region}`);
this.uri = server.url;
this.urlApiWs = server.urlWs;
this.uriObj = await (0, functions_1.getSession)(this.config);
if (this.uriObj instanceof Error) {
throw this.uriObj;
const url = `${this.uri}/game`;
const formData = new FormData();
formData.append('sid', '1');
formData.append('cm', this.childMode.toString());
const { status, data: text } = await axios_1.default.postForm(url, formData, this.config);
if (status !== 200) {
throw new functions_1.AkinatorAPIError('starting session error...', this.region);
}
this.uid = this.uriObj.uid;
this.frontaddr = this.uriObj.frontaddr;
const url = `${this.uri}/new_session?callback=${Client_1.jQuery + new Date().getTime()}&urlApiWs=${this.urlApiWs}&partner=1&childMod=${this.childMode.childMod}&player=website-desktop&uid_ext_session=${this.uid}&frontaddr=${this.frontaddr}&constraint=ETAT<>'AV'&soft_constraint=${this.childMode.softConstraint}&question_filter=${this.childMode.questionFilter}`;
const result = await (0, functions_1.request)(url, 'identification', this.region, this.config);
if (result instanceof functions_1.AkinatorAPIError) {
throw result;
}
const { parameters } = result;
if ('identification' in parameters) {
this.session = parameters.identification.session;
this.signature = parameters.identification.signature;
this.question = parameters.step_information.question;
this.challenge_auth = parameters.identification.challenge_auth;
this.answers = parameters.step_information.answers.map((ans) => ans.answer);
return {
answers: parameters.step_information.answers.map((ans) => ans.answer),
question: parameters.step_information.question
};
}
else {
throw new functions_1.AkinatorAPIError(result, this.region);
}
this.question = text.match(/<p class="question-text" id="question-label">(.+)<\/p>/)[1];
this.session = text.match(/session: '(.+)'/)[1];
this.signature = text.match(/signature: '(.+)'/)[1];
this.answers = [
(0, html_entities_1.decode)(text.match(/<a class="li-game" href="#" id="a_yes" onclick="chooseAnswer\(0\)">(.+)<\/a>/)[1]),
(0, html_entities_1.decode)(text.match(/<a class="li-game" href="#" id="a_no" onclick="chooseAnswer\(1\)">(.+)<\/a>/)[1]),
(0, html_entities_1.decode)(text.match(/<a class="li-game" href="#" id="a_dont_know" onclick="chooseAnswer\(2\)">(.+)<\/a>/)[1]),
(0, html_entities_1.decode)(text.match(/<a class="li-game" href="#" id="a_probably" onclick="chooseAnswer\(3\)">(.+)<\/a>/)[1]),
(0, html_entities_1.decode)(text.match(/<a class="li-game" href="#" id="a_probaly_not" onclick="chooseAnswer\(4\)">(.+)<\/a>/)[1])
];
return this;
}

@@ -87,35 +76,24 @@ /*

async continue() {
if (!this.uri || !this.urlApiWs)
if (!this.uri) {
throw new Error(Client_1.noUriMsg);
if (!this.uriObj || !this.session || !this.signature)
}
if (!this.session || !this.signature) {
throw new Error(Client_1.noSessionMsg);
const query = new URLSearchParams({
callback: Client_1.jQuery + new Date().getTime(),
session: this.session,
signature: this.signature,
step: this.currentStep.toString(),
question_filter: this.childMode.questionFilter
});
if (this.childMode.childMod) {
query.append('childMod', this.childMode.childMod.toString());
}
const url = `${this.urlApiWs}/exclusion?${query.toString()}`;
const result = await (0, functions_1.request)(url, 'answers', this.region, this.config);
const formData = new FormData();
formData.append('step', this.currentStep.toString());
formData.append('progression', this.progress.toString());
formData.append('sid', '1');
formData.append('cm', this.childMode.toString());
formData.append('session', this.session);
formData.append('signature', this.signature);
const url = `${this.uri}/exclude`;
const result = await (0, functions_1.request)(url, formData, this.config);
if (result instanceof functions_1.AkinatorAPIError) {
throw result;
}
const { parameters } = result;
if ('progression' in parameters) {
this.currentStep += 1;
this.progress = parseFloat(parameters.progression);
this.question = parameters.question;
this.answers = parameters.answers.map((ans) => ans.answer);
return {
answers: parameters.answers.map((ans) => ans.answer),
question: parameters.question
};
}
else {
throw new functions_1.AkinatorAPIError(result, this.region);
}
this.progress = parseFloat(result.progression);
this.question = result.question;
this.currentStep = parseInt(result.step, 10);
return result;
}

@@ -127,36 +105,34 @@ /**

async step(answer) {
if (!this.uri || !this.urlApiWs)
if (!this.uri) {
throw new Error(Client_1.noUriMsg);
if (!this.uriObj || !this.session || !this.signature || !this.frontaddr)
}
if (!this.session || !this.signature) {
throw new Error(Client_1.noSessionMsg);
const query = new URLSearchParams({
callback: Client_1.jQuery + new Date().getTime(),
urlApiWs: this.urlApiWs,
childMod: this.childMode.childMod.toString(),
session: this.session,
signature: this.signature,
step: this.currentStep.toString(),
answer: answer.toString(),
frontaddr: this.frontaddr,
question_filter: this.childMode.questionFilter
});
const url = `${this.uri}/answer_api?${query.toString()}`;
const result = await (0, functions_1.request)(url, 'answers', this.region, this.config);
}
const formData = new FormData();
formData.append('step', this.currentStep.toString());
formData.append('progression', this.progress.toString());
formData.append('sid', '1');
formData.append('cm', this.childMode.toString());
formData.append('answer', answer.toString());
formData.append('step_last_proposition', '');
formData.append('session', this.session);
formData.append('signature', this.signature);
const url = `${this.uri}/answer`;
const result = await (0, functions_1.request)(url, formData, this.config);
if (result instanceof functions_1.AkinatorAPIError) {
throw result;
}
const { parameters } = result;
if ('progression' in parameters) {
this.currentStep += 1;
this.progress = parseFloat(parameters.progression);
this.question = parameters.question;
this.answers = parameters.answers.map((ans) => ans.answer);
return {
answers: parameters.answers.map((ans) => ans.answer),
question: parameters.question
};
const guess = result;
// akinator has guessed
if (guess.id_base_proposition) {
this.guess = guess;
return guess;
}
else {
throw new functions_1.AkinatorAPIError(result, this.region);
}
// a normal step
const akinatorResult = result;
this.currentStep = parseInt(akinatorResult.step, 10);
this.question = akinatorResult.question;
this.progress = parseFloat(akinatorResult.progression);
return akinatorResult;
}

@@ -167,71 +143,24 @@ /**

async back() {
if (!this.uri || !this.urlApiWs)
if (!this.uri) {
throw new Error(Client_1.noUriMsg);
if (!this.uriObj || !this.session || !this.signature)
}
if (!this.session || !this.signature) {
throw new Error(Client_1.noSessionMsg);
const query = new URLSearchParams({
callback: Client_1.jQuery + new Date().getTime(),
session: this.session,
childMod: this.childMode.childMod.toString(),
signature: this.signature,
step: this.currentStep.toString(),
answer: '-1',
question_filter: this.childMode.questionFilter
});
const url = `${this.urlApiWs}/cancel_answer?${query.toString()}`;
const result = await (0, functions_1.request)(url, 'answers', this.region, this.config);
if (result instanceof functions_1.AkinatorAPIError) {
throw result;
}
const { parameters } = result;
if ('progression' in parameters) {
this.currentStep -= 1;
this.progress = parseFloat(parameters.progression);
this.question = parameters.question;
this.answers = parameters.answers.map((ans) => ans.answer);
return {
answers: parameters.answers.map((ans) => ans.answer),
question: parameters.question
};
}
else {
throw new functions_1.AkinatorAPIError(result, this.region);
}
}
/**
* The akinator attempts to make a guess and win the game.
*/
async win() {
if (!this.uri || !this.urlApiWs)
throw new Error(Client_1.noUriMsg);
if (!this.uriObj || !this.signature || !this.session)
throw new Error(Client_1.noSessionMsg);
const query = new URLSearchParams({
callback: Client_1.jQuery + new Date().getTime(),
signature: this.signature,
step: this.currentStep.toString(),
session: this.session
});
const url = `${this.urlApiWs}/list?${query.toString()}`;
const result = await (0, functions_1.request)(url, 'elements', this.region, this.config);
const formData = new FormData();
formData.append('step', this.currentStep.toString());
formData.append('progression', this.progress.toString());
formData.append('sid', '1');
formData.append('cm', this.childMode.toString());
formData.append('session', this.session);
formData.append('signature', this.signature);
const url = `${this.uri}/cancel_answer`;
const result = await (0, functions_1.request)(url, formData, this.config);
if (result instanceof functions_1.AkinatorAPIError) {
throw result;
}
const { parameters } = result;
if ('elements' in parameters) {
const answers = (parameters.elements || []).map((ele) => ele.element);
for (let i = 0; i < answers.length; i += 1) {
answers[i].nsfw = answers[i].valide_contrainte == '0';
}
const guessCount = parseInt(parameters.NbObjetsPertinents, 10);
this.answers = answers;
this.guessCount = guessCount;
return {
guesses: answers,
guessCount: guessCount
};
}
else {
throw new functions_1.AkinatorAPIError(result, this.region);
}
this.currentStep = parseInt(result.step, 10);
this.progress = parseFloat(result.progression);
this.question = result.question;
return result;
}

@@ -238,0 +167,0 @@ }

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.regions = exports.noSessionMsg = exports.noUriMsg = exports.jQuery = exports.issues = exports.patternSession = void 0;
exports.regions = exports.noSessionMsg = exports.noUriMsg = exports.issues = exports.patternSession = void 0;
exports.patternSession = new RegExp("var uid_ext_session = '(.*)';\\n.*var frontaddr = '(.*)';");
exports.issues = 'https://github.com/jgoralcz/aki-api/issues';
exports.jQuery = 'jQuery331023608747682107778_';
exports.noUriMsg = 'Could not find the uri or UrlApiWs. This most likely means that you have not started the game!';

@@ -11,18 +10,10 @@ exports.noSessionMsg = 'Could not find the game session. Please make sure you have started the game!';

'en',
'en_objects',
'en_animals',
'ar',
'cn',
'de',
'de_animals',
'es',
'es_animals',
'fr',
'fr_objects',
'fr_animals',
'il',
'it',
'it_animals',
'jp',
'jp_animals',
'kr',

@@ -29,0 +20,0 @@ 'nl',

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.regionURL = exports.request = exports.AkinatorAPIError = exports.getSession = void 0;
var GetSession_1 = require("./GetSession");
Object.defineProperty(exports, "getSession", { enumerable: true, get: function () { return GetSession_1.getSession; } });
exports.request = exports.AkinatorAPIError = void 0;
var Request_1 = require("./Request");
Object.defineProperty(exports, "AkinatorAPIError", { enumerable: true, get: function () { return Request_1.AkinatorAPIError; } });
Object.defineProperty(exports, "request", { enumerable: true, get: function () { return Request_1.request; } });
Object.defineProperty(exports, "regionURL", { enumerable: true, get: function () { return Request_1.regionURL; } });
//# sourceMappingURL=index.js.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.regionURL = exports.request = exports.AkinatorAPIError = void 0;
exports.request = exports.AkinatorAPIError = void 0;
const axios_1 = require("axios");
const Client_1 = require("../constants/Client");
const os = require("os");
const params = Object.freeze({
gzip: true,
resolveWithFullResponse: true,
validateStatus: () => true,
timeout: 10000,
});
// Mozilla/5.0 (Macintosh; Intel Mac OS X x.y; rv:10.0) Gecko/20100101 Firefox/10.0
const headers = {
'User-Agent': `Mozilla/5.0 (${os.type().replace('_', ' ')} ${os.release()}; ${os.platform()}; ${os.arch()}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36`,
'x-requested-with': 'XMLHttpRequest',
};
const subject_ids = {
characters: 1,
Objects: 2,
Animals: 14
};
/**
* gets the server based on the provided region, so we don't rely on hard coded values.
* @param {string} region the requested region to be parsed
* @return {object} obj with url and urlWs or undefined
*/
const getServer = async (region, axiosConfig) => {
try {
const split = region.split('_');
const [language, themeName] = split;
const url = `https://${language}.akinator.com`;
const { data } = await axios_1.default.get(url, Object.assign({}, axiosConfig));
const regex = /\[{"translated_theme_name":"[\s\S]*","urlWs":"https:\\\/\\\/srv[0-9]+\.akinator\.com:[0-9]+\\\/ws","subject_id":"[0-9]+"}]/gim;
const parsed = JSON.parse(data.match(regex));
if (!parsed || !parsed[0] || !parsed[0].urlWs || parsed.length <= 0)
return undefined;
const _themeName = themeName ? themeName.replace(themeName.charAt(0), themeName.charAt(0).toUpperCase()) : 'characters';
const subjectId = subject_ids[_themeName];
const found = parsed.find(theme => parseInt(theme.subject_id) === subjectId);
const obj = {
url,
urlWs: themeName && found && found.urlWs ? found.urlWs : parsed[0].urlWs,
};
return obj;
}
catch (error) {
console.error(error);
}
return undefined;
};
class AkinatorAPIError extends Error {
constructor(data, region) {
super(`A problem occurred with making the request data: ${data}: region: ${region}`);
this.message = this.mapError(data.completion, region);
this.message = this.mapError(data.completion || '', region);
}

@@ -72,13 +26,10 @@ mapError(c, region) {

exports.AkinatorAPIError = AkinatorAPIError;
// example output: jQuery331023608747682107778_1615444627875({"completion":"OK","parameters":{"identification":{"channel":0,"session":"459","signature":"223731835","challenge_auth":"8ebe521c-5991-4625-b081-6066352649e5"},"step_information":{"question":"Does your character really exist?","answers":[{"answer":"Yes"},{"answer":"No"},{"answer":"Don't know"},{"answer":"Probably"},{"answer":"Probably not"}],"step":"0","progression":"0.00000","questionid":"266","infogain":"0.607602"}}}
const request = async (url, checkParamProperty, region, axiosConfig) => {
const { status, data } = await axios_1.default.get(url, Object.assign({ headers, params }, axiosConfig));
if (status !== 200 || !data) {
throw new Error(`A problem occurred with making the request. status: ${status}`);
const request = async (url, formData, axiosConfig) => {
const { status, data: result } = await axios_1.default.postForm(url, formData, axiosConfig);
if (status !== 200 || !result) {
throw new AkinatorAPIError(result, url);
}
const beginningParse = data.indexOf('(');
const jsonString = data.substring(beginningParse + 1, data.length - 1);
const result = JSON.parse(jsonString);
if (!result || result.completion != 'OK' || !(checkParamProperty in result.parameters)) {
throw new AkinatorAPIError(result, region);
const guess = result;
if (guess.id_proposition) {
return guess;
}

@@ -88,10 +39,2 @@ return result;

exports.request = request;
/**
* Returns the url from the correct region.
* @param userRegion the region provided
* @param axiosConfig the proxy config for axios
* @returns {Promise<AkiURL>} the generated url for that region
*/
const regionURL = async (userRegion, axiosConfig) => getServer(userRegion.toLowerCase(), axiosConfig);
exports.regionURL = regionURL;
//# sourceMappingURL=Request.js.map
{
"author": "Joshua Goralczyk",
"version": "6.0.9",
"version": "7.0.0",
"main": "./dist/src/index.js",

@@ -12,5 +12,7 @@ "types": "typings/src/index.d.ts",

"dependencies": {
"axios": "^1.4.0",
"https-proxy-agent": "^6.1.0",
"node_extra_ca_certs_mozilla_bundle": "^1.0.5"
"axios": "^1.6.8",
"form-data": "^4.0.0",
"html-entities": "^2.5.2",
"https-proxy-agent": "^6.2.1",
"node_extra_ca_certs_mozilla_bundle": "^1.0.6"
},

@@ -41,9 +43,9 @@ "description": "An API for Akinator. Supports up to 15 languages.",

"devDependencies": {
"@types/node": "^20.1.0",
"@typescript-eslint/eslint-plugin": "^5.59.2",
"@typescript-eslint/parser": "^5.59.2",
"eslint": "^8.40.0",
"ts-node": "^10.9.1",
"typescript": "^5.0.4"
"@types/node": "^20.12.7",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
"eslint": "^8.57.0",
"ts-node": "^10.9.2",
"typescript": "^5.4.5"
}
}

@@ -1,13 +0,6 @@

import { guess } from './functions';
import { AkinatorAPIError } from './functions';
import { region } from './constants/Client';
import { HttpsProxyAgentOptions } from 'https-proxy-agent';
import { AxiosRequestConfig } from 'axios';
interface question {
question: string;
answers: ('Yes' | 'No' | 'Don\'t Know' | 'Probably' | 'Probably not' | string)[];
}
interface winResult {
guessCount: number;
guesses: guess[];
}
import { AkinatorResult, AkinatorResultGuess } from './functions/Request';
interface AkinatorConstructor {

@@ -28,26 +21,15 @@ region: region;

region: region;
uri: string | undefined;
urlApiWs: string | undefined;
uriObj: {
uid: string;
frontaddr: string;
} | undefined;
session: string | undefined;
uri?: string;
session?: string;
progress: number;
childMode: {
childMod: boolean;
softConstraint: string;
questionFilter: string;
};
/** @deprecated use the `guesses` property from `win()` instead. */
answers: ('Yes' | 'No' | 'Don\'t Know' | 'Probably' | 'Probably not')[] | guess[];
childMode: boolean;
step_last_proposition: string;
answers: string[];
/** @deprecated use the `guessCount` property from `start()` and `step()` instead */
guessCount: number;
/** @deprecated use the `question` property from `start()` and `step()` instead */
question: string | undefined;
uid: string | undefined;
frontaddr: string | undefined;
signature: string | undefined;
challenge_auth: string | undefined;
question?: string;
signature?: string;
config: AxiosRequestConfig;
guess?: AkinatorResultGuess;
constructor({ region, childMode, proxyOptions }: AkinatorConstructor);

@@ -57,4 +39,4 @@ /**

*/
start(): Promise<question>;
continue(): Promise<question>;
start(): Promise<this>;
continue(): Promise<AkinatorResult | AkinatorAPIError>;
/**

@@ -64,12 +46,8 @@ * Gets the next question for the akinator session.

*/
step(answer: answers): Promise<question>;
step(answer: answers): Promise<AkinatorResult | AkinatorResultGuess | AkinatorAPIError>;
/**
* Reverts the game back a previous step.
*/
back(): Promise<question>;
/**
* The akinator attempts to make a guess and win the game.
*/
win(): Promise<winResult>;
back(): Promise<AkinatorResult | AkinatorAPIError>;
}
export {};
export declare const patternSession: RegExp;
export declare const issues = "https://github.com/jgoralcz/aki-api/issues";
export declare const jQuery = "jQuery331023608747682107778_";
export declare const noUriMsg = "Could not find the uri or UrlApiWs. This most likely means that you have not started the game!";
export declare const noSessionMsg = "Could not find the game session. Please make sure you have started the game!";
export declare const regions: readonly ["en", "en_objects", "en_animals", "ar", "cn", "de", "de_animals", "es", "es_animals", "fr", "fr_objects", "fr_animals", "il", "it", "it_animals", "jp", "jp_animals", "kr", "nl", "pl", "pt", "ru", "tr", "id"];
export declare const regions: readonly ["en", "ar", "cn", "de", "es", "fr", "il", "it", "jp", "kr", "nl", "pl", "pt", "ru", "tr", "id"];
export type region = (typeof regions)[number];

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

export { getSession } from './GetSession';
export { AkinatorAPIError, request, regionURL, guess } from './Request';
export { AkinatorAPIError, request } from './Request';
import { AxiosRequestConfig } from 'axios';
import { region } from '../constants/Client';
export type guess = {
id: string;
name: string;
id_base: string;
proba: string;
absolute_picture_path: string;
award_id: string;
corrupt: string;
description: string;
picture_path: string;
pseudo: string;
ranking: string;
relative: string;
valide_contrainte: string;
nsfw?: boolean;
};
export type AkinatorResultParams = {
NbObjetsPertinents: string;
elements: {
element: guess;
}[];
} | {
identification: {
challenge_auth: string;
channel: number;
session: string;
signature: string;
};
step_information: {
answers: [{
answer: 'Yes';
}, {
answer: 'No';
}, {
answer: 'Don\'t Know';
}, {
answer: 'Probably';
}, {
answer: 'Probably not';
}];
infogain: string;
progression: string;
question: string;
questionid: string;
step: string;
};
} | {
answers: [{
answer: 'Yes';
}, {
answer: 'No';
}, {
answer: 'Don\'t Know';
}, {
answer: 'Probably';
}, {
answer: 'Probably not';
}];
infogain: string;
options: string[];
import * as FormData from 'form-data';
export interface AkinatorResult {
completion?: string;
akitude: string;
step: string;
progression: string;
question_id: string;
question: string;
questionid: string;
status_minibase: string;
step: string;
};
interface AkinatorResult {
}
export interface AkinatorResultGuess {
completion: string;
parameters: AkinatorResultParams;
description_proposition: string;
flag_photo: string;
id_base_proposition: string;
id_proposition: string;
name_proposition: string;
nb_elements: number;
photo: string;
pseudo: string;
valide_constrainte: string;
}
type checkParamProperty = 'elements' | 'answers' | 'identification';
interface AkiURL {
url: string;
urlWs: string;
}
export declare class AkinatorAPIError extends Error {
constructor(data: AkinatorResult, region: string);
constructor(data: any, region: string);
private mapError;
}
export declare const request: (url: string, checkParamProperty: checkParamProperty, region: "en" | "en_objects" | "en_animals" | "ar" | "cn" | "de" | "de_animals" | "es" | "es_animals" | "fr" | "fr_objects" | "fr_animals" | "il" | "it" | "it_animals" | "jp" | "jp_animals" | "kr" | "nl" | "pl" | "pt" | "ru" | "tr" | "id", axiosConfig: AxiosRequestConfig) => Promise<AkinatorAPIError | AkinatorResult>;
/**
* Returns the url from the correct region.
* @param userRegion the region provided
* @param axiosConfig the proxy config for axios
* @returns {Promise<AkiURL>} the generated url for that region
*/
export declare const regionURL: (userRegion: region, axiosConfig: AxiosRequestConfig) => Promise<AkiURL | undefined>;
export {};
export declare const request: (url: string, formData: FormData, axiosConfig: AxiosRequestConfig) => Promise<AkinatorAPIError | AkinatorResult | AkinatorResultGuess>;
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