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

@coorpacademy/player-services

Package Overview
Dependencies
Maintainers
17
Versions
201
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@coorpacademy/player-services - npm Package Compare versions

Comparing version 1.2.2 to 1.3.0

es/answers.js.flow

17

es/answers.js

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

// strict
import assign from 'lodash/fp/assign';

@@ -7,6 +9,17 @@ import includes from 'lodash/fp/includes';

const { findProgressionById, findSlideById, getCorrectAnswer } = fixtures;
const slide = await findSlideById(slideId);
const progression = await findProgressionById(progressionId);
if (!includes(slideId, progression.state.slides)) throw new Error('Answer is not available');
if (!progression) {
throw new Error(`progression "${progressionId}" not found`);
}
const state = progression.state;
if (!state) {
throw new Error(`progression "${progressionId}" has no state`);
}
const slide = await findSlideById(slideId);
if (!includes(slideId, state.slides)) throw new Error('Answer is not available');
const config = getConfigForProgression(progression);

@@ -13,0 +26,0 @@ const correctAnswer = await getCorrectAnswer(slideId);

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

// strict
import includes from 'lodash/fp/includes';
const findById = fixtures => async (progressionId, slideId) => {

@@ -7,12 +10,22 @@ const { findProgressionById, getClue } = fixtures;

if (!includes(slideId, progression.state.requestedClues)) throw new Error('Clue is not available');
if (!progression) {
throw new Error(`progression "${progressionId}" not found`);
}
const state = progression.state;
if (!state) {
throw new Error(`progression "${progressionId}" has no state`);
}
if (!includes(slideId, state.requestedClues)) throw new Error('Clue is not available');
return getClue(slideId);
};
const Clues = fixtures => ({
const createCluesService = fixtures => ({
findById: findById(fixtures)
});
export default Clues;
export default createCluesService;
//# sourceMappingURL=clues.js.map

6

es/content.js

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

// strict
import get from 'lodash/fp/get';

@@ -37,3 +39,3 @@ import pipe from 'lodash/fp/pipe';

const Content = fixtures => ({
const createContentService = fixtures => ({
find: find(fixtures),

@@ -43,3 +45,3 @@ getInfo: getInfo(fixtures)

export default Content;
export default createContentService;
//# sourceMappingURL=content.js.map

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

// eslint-disable-next-line import/prefer-default-export,require-await
// eslint-disable-next-line import/prefer-default-export
export const findById = fixtures => async id => {

@@ -6,3 +8,3 @@ const { getExitNode } = fixtures;

return exitNode;
};
}; // strict

@@ -9,0 +11,0 @@ const ExitNodes = fixtures => ({

@@ -0,27 +1,29 @@

// strict
import * as AnalyticsService from './analytics';
import AnswersService from './answers';
import CluesService from './clues';
import createAnswersService from './answers';
import createCluesService from './clues';
import * as CoachService from './coach';
import * as CommentsService from './comments';
import ContentService from './content';
import ExitNodesService from './exit-nodes';
import createContentService from './content';
import createExitNodesService from './exit-nodes';
import * as LeaderBoardService from './leaderboard';
import * as LocationService from './location';
import ProgressionsService from './progressions';
import RecommendationsService from './recommendations';
import SlidesService from './slides';
import createProgressionsService from './progressions';
import createRecommendationsService from './recommendations';
import createSlidesService from './slides';
export const Analytics = AnalyticsService;
export const Answers = AnswersService;
export const Clues = CluesService;
export const Answers = createAnswersService;
export const Clues = createCluesService;
export const Coach = CoachService;
export const Comments = CommentsService;
export const Content = ContentService;
export const ExitNodes = ExitNodesService;
export const Content = createContentService;
export const ExitNodes = createExitNodesService;
export const LeaderBoard = LeaderBoardService;
export const Location = LocationService; // eslint-disable-line no-shadow
export const Logger = console; // eslint-disable-line no-console
export const Progressions = ProgressionsService;
export const Recommendations = RecommendationsService;
export const Slides = SlidesService;
export const Progressions = createProgressionsService;
export const Recommendations = createRecommendationsService;
export const Slides = createSlidesService;
//# sourceMappingURL=index.js.map

@@ -0,7 +1,9 @@

// strict
import random from 'lodash/fp/random';
// eslint-disable-next-line import/prefer-default-export
export const getRank = () => {
export const getRank = userId => {
return Promise.resolve(random(0, 10));
};
//# sourceMappingURL=leaderboard.js.map

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

// strict
export const exit = () => {

@@ -5,3 +7,3 @@ window.location.reload();

export const retry = () => {
export const retry = contentRef => {
window.location.reload();

@@ -14,9 +16,13 @@ };

export const nextLevel = () => {
export const nextLevel = contentRef => {
window.location.reload();
};
export const seeComment = () => {
export const seeComment = content => {
window.location.reload();
};
export const openRecommendation = recommendation => {
window.location.reload();
};
//# sourceMappingURL=location.js.map
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
// strict
import { createProgression, createState, computeNextStepAfterAnswer, computeNextStepOnAcceptExtraLife, computeNextStepOnRefuseExtraLife, getConfig, getConfigForProgression } from '@coorpacademy/progression-engine';

@@ -13,4 +15,6 @@ import uniqueId from 'lodash/fp/uniqueId';

import map from 'lodash/fp/map';
import Content from './content';
import { CONTENT_TYPE } from './definitions';
const generateId = () => uniqueId('progression');

@@ -35,5 +39,15 @@

const { getChapterRulesByContent, findSlideByChapter } = fixtures;
const { find: findContent } = Content(fixtures);
const chapters = content.type === 'level' ? map(ref => ({ type: 'chapter', ref }), (await findContent(content.type, content.ref)).chapterIds) : [content];
const { findLevelById } = fixtures;
let chapters;
if (content.type === CONTENT_TYPE.LEVEL) {
const level = await findLevelById(content.ref);
if (!level) {
throw new Error(`level ${content.ref} has no chapterIds`);
}
chapters = map(ref => ({ type: CONTENT_TYPE.CHAPTER, ref }), level.chapterIds);
} else {
chapters = [content];
}
return Promise.all(chapters.map(async chapter => ({

@@ -52,7 +66,7 @@ ref: chapter.ref,

const findBestOf = fixtures => (engineRef, contentRef, progressionId = null) => {
const findBestOf = fixtures => (engineRef, contentRef, progressionId = '') => {
const { getAllProgressions } = fixtures;
const progressions = getAllProgressions();
const bestProgression = pipe(filter(p => get('content.ref', p) === contentRef && get('_id', p) !== progressionId), maxBy(p => p.state.stars || 0))(progressions);
const bestProgression = pipe(filter(p => get('content.ref', p) === contentRef && get('_id', p) !== progressionId), maxBy(p => p.state && p.state.stars || 0))(progressions);
return bestProgression || set('state.stars', 0, {});

@@ -70,8 +84,18 @@ };

const { findSlideById, findProgressionById } = fixtures;
const userAnswer = getOr([''], 'answer', payload);
const slideId = payload.content.ref;
const slide = await findSlideById(slideId);
const progression = await findProgressionById(progressionId);
if (!progression) {
throw new Error(`progression "${progressionId}" not found`);
}
const state = progression.state;
if (!state) {
throw new Error(`progression "${progressionId}" has no state`);
}
const answer = getOr([''], 'answer', payload);
const slideId = payload.content.ref;
const slide = await findSlideById(slideId);
const partialAnswerAction = {

@@ -81,3 +105,3 @@ type: 'answer',

content: payload.content,
answer: userAnswer,
answer,
godMode: false

@@ -92,2 +116,7 @@ }

/* istanbul ignore if */
if (!action) {
throw new Error(`computeNextStepAfterAnswer failed`);
}
return addActionAndSaveProgression(fixtures)(progression, action);

@@ -100,2 +129,6 @@ };

if (!progression) {
throw new Error(`progression "${progressionId}" not found`);
}
const action = {

@@ -112,8 +145,23 @@ type: 'clue',

const progression = await findProgressionById(progressionId);
if (!progression) {
throw new Error(`progression "${progressionId}" not found`);
}
const state = progression.state;
if (!state) {
throw new Error(`progression "${progressionId}" has no state`);
}
const config = getConfigForProgression(progression);
const _getAvailableContent = getAvailableContent(fixtures);
const availableContent = await _getAvailableContent(progression.content);
const action = computeNextStepOnAcceptExtraLife(config, progression.state, availableContent);
const action = computeNextStepOnAcceptExtraLife(config, state, availableContent);
/* istanbul ignore if */
if (!action) {
throw new Error(`computeNextStepOnAcceptExtraLife failed`);
}
return addActionAndSaveProgression(fixtures)(progression, action);

@@ -125,4 +173,15 @@ };

const progression = await findProgressionById(progressionId);
if (!progression) {
throw new Error(`progression "${progressionId}" not found`);
}
const state = progression.state;
if (!state) {
throw new Error(`progression "${progressionId}" has no state`);
}
const config = getConfigForProgression(progression);
const action = computeNextStepOnRefuseExtraLife(config, progression.state);
const action = computeNextStepOnRefuseExtraLife(config, state);

@@ -132,3 +191,3 @@ return addActionAndSaveProgression(fixtures)(progression, action);

const create = fixtures => async (engine, content, engineOptions = {}) => {
const create = fixtures => async (engine, content, engineOptions) => {
const _id = generateId();

@@ -140,2 +199,7 @@

const newProgression = createProgression(engine, content, engineOptions, availableContent);
if (!newProgression) {
throw new Error(`progression could not be created properly`);
}
const state = createState(newProgression);

@@ -154,2 +218,6 @@

if (!progression) {
throw new Error(`progression "${progressionId}" not found`);
}
const action = {

@@ -163,3 +231,3 @@ type: 'resource',

const Progressions = fixtures => ({
const createProgressionsService = fixtures => ({
acceptExtraLife: acceptExtraLife(fixtures),

@@ -179,3 +247,3 @@ create: create(fixtures),

export default Progressions;
export default createProgressionsService;
//# sourceMappingURL=progressions.js.map

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

// strict
import { CONTENT_TYPE } from './definitions';
const find = fixtures => (type, ref) => {

@@ -10,10 +14,11 @@ const { findRecommendations } = fixtures;

switch (type) {
case 'chapter':
case CONTENT_TYPE.LEVEL:
return Promise.resolve(getNextLevel(ref));
case CONTENT_TYPE.CHAPTER:
default:
return Promise.resolve(undefined);
case 'level':
return Promise.resolve(getNextLevel(ref));
}
};
const Recommendations = fixtures => ({
const createRecommendationsService = fixtures => ({
find: find(fixtures),

@@ -23,3 +28,3 @@ getNext: getNext(fixtures)

export default Recommendations;
export default createRecommendationsService;
//# sourceMappingURL=recommendations.js.map

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

// strict
const findById = fixtures => async slideId => {

@@ -7,7 +9,7 @@ const { findSlideById } = fixtures;

const Slides = fixtures => ({
const createSlidesService = fixtures => ({
findById: findById(fixtures)
});
export default Slides;
export default createSlidesService;
//# sourceMappingURL=slides.js.map

@@ -19,6 +19,17 @@ 'use strict';

const { findProgressionById, findSlideById, getCorrectAnswer } = fixtures;
const slide = await findSlideById(slideId);
const progression = await findProgressionById(progressionId);
if (!(0, _includes2.default)(slideId, progression.state.slides)) throw new Error('Answer is not available');
if (!progression) {
throw new Error(`progression "${progressionId}" not found`);
}
const state = progression.state;
if (!state) {
throw new Error(`progression "${progressionId}" has no state`);
}
const slide = await findSlideById(slideId);
if (!(0, _includes2.default)(slideId, state.slides)) throw new Error('Answer is not available');
const config = (0, _progressionEngine.getConfigForProgression)(progression);

@@ -36,3 +47,3 @@ const correctAnswer = await getCorrectAnswer(slideId);

};
};
}; // strict

@@ -39,0 +50,0 @@ const Answers = fixtures => ({

@@ -15,12 +15,22 @@ 'use strict';

if (!(0, _includes2.default)(slideId, progression.state.requestedClues)) throw new Error('Clue is not available');
if (!progression) {
throw new Error(`progression "${progressionId}" not found`);
}
const state = progression.state;
if (!state) {
throw new Error(`progression "${progressionId}" has no state`);
}
if (!(0, _includes2.default)(slideId, state.requestedClues)) throw new Error('Clue is not available');
return getClue(slideId);
};
}; // strict
const Clues = fixtures => ({
const createCluesService = fixtures => ({
findById: findById(fixtures)
});
exports.default = Clues;
exports.default = createCluesService;
//# sourceMappingURL=clues.js.map

@@ -20,3 +20,3 @@ 'use strict';

return findContent(type, ref);
};
}; // strict

@@ -50,3 +50,3 @@ const getNbSlides = fixtures => (contentRef, engineRef, version) => {

const Content = fixtures => ({
const createContentService = fixtures => ({
find: find(fixtures),

@@ -56,3 +56,3 @@ getInfo: getInfo(fixtures)

exports.default = Content;
exports.default = createContentService;
//# sourceMappingURL=content.js.map

@@ -1,5 +0,7 @@

"use strict";
'use strict';
exports.__esModule = true;
// eslint-disable-next-line import/prefer-default-export,require-await
// eslint-disable-next-line import/prefer-default-export
const findById = exports.findById = fixtures => async id => {

@@ -9,3 +11,3 @@ const { getExitNode } = fixtures;

return exitNode;
};
}; // strict

@@ -12,0 +14,0 @@ const ExitNodes = fixtures => ({

@@ -58,2 +58,4 @@ 'use strict';

// strict
const Analytics = exports.Analytics = AnalyticsService;

@@ -60,0 +62,0 @@ const Answers = exports.Answers = _answers2.default;

@@ -13,5 +13,5 @@ 'use strict';

// eslint-disable-next-line import/prefer-default-export
const getRank = exports.getRank = () => {
const getRank = exports.getRank = userId => {
return Promise.resolve((0, _random2.default)(0, 10));
};
}; // strict
//# sourceMappingURL=leaderboard.js.map

@@ -1,4 +0,6 @@

"use strict";
'use strict';
exports.__esModule = true;
// strict
const exit = exports.exit = () => {

@@ -8,3 +10,3 @@ window.location.reload();

const retry = exports.retry = () => {
const retry = exports.retry = contentRef => {
window.location.reload();

@@ -17,9 +19,13 @@ };

const nextLevel = exports.nextLevel = () => {
const nextLevel = exports.nextLevel = contentRef => {
window.location.reload();
};
const seeComment = exports.seeComment = () => {
const seeComment = exports.seeComment = content => {
window.location.reload();
};
const openRecommendation = exports.openRecommendation = recommendation => {
window.location.reload();
};
//# sourceMappingURL=location.js.map

@@ -5,3 +5,3 @@ 'use strict';

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; // strict

@@ -46,6 +46,4 @@ var _progressionEngine = require('@coorpacademy/progression-engine');

var _content = require('./content');
var _definitions = require('./definitions');
var _content2 = _interopRequireDefault(_content);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@@ -72,5 +70,15 @@

const { getChapterRulesByContent, findSlideByChapter } = fixtures;
const { find: findContent } = (0, _content2.default)(fixtures);
const chapters = content.type === 'level' ? (0, _map2.default)(ref => ({ type: 'chapter', ref }), (await findContent(content.type, content.ref)).chapterIds) : [content];
const { findLevelById } = fixtures;
let chapters;
if (content.type === _definitions.CONTENT_TYPE.LEVEL) {
const level = await findLevelById(content.ref);
if (!level) {
throw new Error(`level ${content.ref} has no chapterIds`);
}
chapters = (0, _map2.default)(ref => ({ type: _definitions.CONTENT_TYPE.CHAPTER, ref }), level.chapterIds);
} else {
chapters = [content];
}
return Promise.all(chapters.map(async chapter => ({

@@ -89,7 +97,7 @@ ref: chapter.ref,

const findBestOf = fixtures => (engineRef, contentRef, progressionId = null) => {
const findBestOf = fixtures => (engineRef, contentRef, progressionId = '') => {
const { getAllProgressions } = fixtures;
const progressions = getAllProgressions();
const bestProgression = (0, _pipe2.default)((0, _filter2.default)(p => (0, _get2.default)('content.ref', p) === contentRef && (0, _get2.default)('_id', p) !== progressionId), (0, _maxBy2.default)(p => p.state.stars || 0))(progressions);
const bestProgression = (0, _pipe2.default)((0, _filter2.default)(p => (0, _get2.default)('content.ref', p) === contentRef && (0, _get2.default)('_id', p) !== progressionId), (0, _maxBy2.default)(p => p.state && p.state.stars || 0))(progressions);
return bestProgression || (0, _set2.default)('state.stars', 0, {});

@@ -107,8 +115,18 @@ };

const { findSlideById, findProgressionById } = fixtures;
const userAnswer = (0, _getOr2.default)([''], 'answer', payload);
const slideId = payload.content.ref;
const slide = await findSlideById(slideId);
const progression = await findProgressionById(progressionId);
if (!progression) {
throw new Error(`progression "${progressionId}" not found`);
}
const state = progression.state;
if (!state) {
throw new Error(`progression "${progressionId}" has no state`);
}
const answer = (0, _getOr2.default)([''], 'answer', payload);
const slideId = payload.content.ref;
const slide = await findSlideById(slideId);
const partialAnswerAction = {

@@ -118,3 +136,3 @@ type: 'answer',

content: payload.content,
answer: userAnswer,
answer,
godMode: false

@@ -129,2 +147,7 @@ }

/* istanbul ignore if */
if (!action) {
throw new Error(`computeNextStepAfterAnswer failed`);
}
return addActionAndSaveProgression(fixtures)(progression, action);

@@ -137,2 +160,6 @@ };

if (!progression) {
throw new Error(`progression "${progressionId}" not found`);
}
const action = {

@@ -149,8 +176,23 @@ type: 'clue',

const progression = await findProgressionById(progressionId);
if (!progression) {
throw new Error(`progression "${progressionId}" not found`);
}
const state = progression.state;
if (!state) {
throw new Error(`progression "${progressionId}" has no state`);
}
const config = (0, _progressionEngine.getConfigForProgression)(progression);
const _getAvailableContent = getAvailableContent(fixtures);
const availableContent = await _getAvailableContent(progression.content);
const action = (0, _progressionEngine.computeNextStepOnAcceptExtraLife)(config, progression.state, availableContent);
const action = (0, _progressionEngine.computeNextStepOnAcceptExtraLife)(config, state, availableContent);
/* istanbul ignore if */
if (!action) {
throw new Error(`computeNextStepOnAcceptExtraLife failed`);
}
return addActionAndSaveProgression(fixtures)(progression, action);

@@ -162,4 +204,15 @@ };

const progression = await findProgressionById(progressionId);
if (!progression) {
throw new Error(`progression "${progressionId}" not found`);
}
const state = progression.state;
if (!state) {
throw new Error(`progression "${progressionId}" has no state`);
}
const config = (0, _progressionEngine.getConfigForProgression)(progression);
const action = (0, _progressionEngine.computeNextStepOnRefuseExtraLife)(config, progression.state);
const action = (0, _progressionEngine.computeNextStepOnRefuseExtraLife)(config, state);

@@ -169,3 +222,3 @@ return addActionAndSaveProgression(fixtures)(progression, action);

const create = fixtures => async (engine, content, engineOptions = {}) => {
const create = fixtures => async (engine, content, engineOptions) => {
const _id = generateId();

@@ -177,2 +230,7 @@

const newProgression = (0, _progressionEngine.createProgression)(engine, content, engineOptions, availableContent);
if (!newProgression) {
throw new Error(`progression could not be created properly`);
}
const state = (0, _progressionEngine.createState)(newProgression);

@@ -191,2 +249,6 @@

if (!progression) {
throw new Error(`progression "${progressionId}" not found`);
}
const action = {

@@ -200,3 +262,3 @@ type: 'resource',

const Progressions = fixtures => ({
const createProgressionsService = fixtures => ({
acceptExtraLife: acceptExtraLife(fixtures),

@@ -216,3 +278,3 @@ create: create(fixtures),

exports.default = Progressions;
exports.default = createProgressionsService;
//# sourceMappingURL=progressions.js.map
'use strict';
exports.__esModule = true;
var _definitions = require('./definitions');
const find = fixtures => (type, ref) => {

@@ -8,3 +11,3 @@ const { findRecommendations } = fixtures;

return Promise.resolve(recommendations);
};
}; // strict

@@ -14,10 +17,11 @@ const getNext = fixtures => (type, ref) => {

switch (type) {
case 'chapter':
case _definitions.CONTENT_TYPE.LEVEL:
return Promise.resolve(getNextLevel(ref));
case _definitions.CONTENT_TYPE.CHAPTER:
default:
return Promise.resolve(undefined);
case 'level':
return Promise.resolve(getNextLevel(ref));
}
};
const Recommendations = fixtures => ({
const createRecommendationsService = fixtures => ({
find: find(fixtures),

@@ -27,3 +31,3 @@ getNext: getNext(fixtures)

exports.default = Recommendations;
exports.default = createRecommendationsService;
//# sourceMappingURL=recommendations.js.map

@@ -1,4 +0,6 @@

"use strict";
'use strict';
exports.__esModule = true;
// strict
const findById = fixtures => async slideId => {

@@ -10,7 +12,7 @@ const { findSlideById } = fixtures;

const Slides = fixtures => ({
const createSlidesService = fixtures => ({
findById: findById(fixtures)
});
exports.default = Slides;
exports.default = createSlidesService;
//# sourceMappingURL=slides.js.map
{
"name": "@coorpacademy/player-services",
"version": "1.2.2",
"version": "1.3.0",
"description": "Implements reactions to redux actions from player-store",

@@ -50,3 +50,3 @@ "main": "lib/index.js",

"dependencies": {
"@coorpacademy/progression-engine": "9.2.5",
"@coorpacademy/progression-engine": "9.3.0",
"lodash": "^4.17.4"

@@ -72,4 +72,3 @@ },

}
},
"gitHead": "4ec5dc2d397329114b1fdadf0166982ef7e5e987"
}
}

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

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

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

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

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