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

unleash-proxy-client

Package Overview
Dependencies
Maintainers
1
Versions
94
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

unleash-proxy-client - npm Package Compare versions

Comparing version 1.0.1 to 1.1.0

examples/react-app/package-lock.json

25

build/index.d.ts
import { TinyEmitter } from 'tiny-emitter';
import IStorageProvider from './storage-provider';
export interface IConfig {
export interface IStaticContext {
appName: string;
environment?: string;
}
export interface IMutableContext {
userId?: string;
sessionId?: string;
remoteAddress?: string;
properties?: {
[key: string]: string;
};
}
export declare type IContext = IStaticContext & IMutableContext;
export interface IConfig extends IStaticContext {
url: string;
clientKey: string;
appName: string;
environment?: string;
refreshInterval?: number;

@@ -12,6 +23,4 @@ metricsInterval?: number;

storageProvider?: IStorageProvider;
context?: IMutableContext;
}
export interface IContext {
[key: string]: string;
}
export interface IVariant {

@@ -43,6 +52,6 @@ name: string;

private metrics;
constructor({ storageProvider, url, clientKey, refreshInterval, metricsInterval, disableMetrics, environment, appName }: IConfig);
constructor({ storageProvider, url, clientKey, refreshInterval, metricsInterval, disableMetrics, appName, environment, context }: IConfig);
isEnabled(toggleName: string): boolean;
getVariant(toggleName: string): IVariant;
updateContext(context: IContext): void;
updateContext(context: IMutableContext): void;
start(): Promise<void>;

@@ -49,0 +58,0 @@ stop(): void;

@@ -74,3 +74,3 @@ "use strict";

function UnleashClient(_a) {
var storageProvider = _a.storageProvider, url = _a.url, clientKey = _a.clientKey, _b = _a.refreshInterval, refreshInterval = _b === void 0 ? 30 : _b, _c = _a.metricsInterval, metricsInterval = _c === void 0 ? 30 : _c, _d = _a.disableMetrics, disableMetrics = _d === void 0 ? false : _d, _e = _a.environment, environment = _e === void 0 ? 'default' : _e, appName = _a.appName;
var storageProvider = _a.storageProvider, url = _a.url, clientKey = _a.clientKey, _b = _a.refreshInterval, refreshInterval = _b === void 0 ? 30 : _b, _c = _a.metricsInterval, metricsInterval = _c === void 0 ? 30 : _c, _d = _a.disableMetrics, disableMetrics = _d === void 0 ? false : _d, appName = _a.appName, _e = _a.environment, environment = _e === void 0 ? 'default' : _e, context = _a.context;
var _this = _super.call(this) || this;

@@ -93,3 +93,3 @@ _this.toggles = [];

_this.refreshInterval = refreshInterval * 1000;
_this.context = { environment: environment, appName: appName };
_this.context = __assign({ appName: appName, environment: environment }, context);
_this.toggles = _this.storage.get(storeKey) || [];

@@ -123,2 +123,8 @@ _this.metrics = new metrics_1.default({

UnleashClient.prototype.updateContext = function (context) {
// Give the user a nicer error message when including
// static fields in the mutable context object
// @ts-ignore
if (context.appName || context.environment) {
console.warn("appName and environment are static. They can't be updated with updateContext.");
}
var staticContext = { environment: this.context.environment, appName: this.context.appName };

@@ -168,3 +174,3 @@ this.context = __assign({}, staticContext, context);

return __awaiter(this, void 0, void 0, function () {
var context_1, urlWithQuery_1, response, data, e_1;
var context, urlWithQuery_1, response, data, e_1;
return __generator(this, function (_a) {

@@ -177,5 +183,19 @@ switch (_a.label) {

_a.trys.push([1, 5, , 6]);
context_1 = this.context;
context = this.context;
urlWithQuery_1 = new URL(this.url.toString());
Object.keys(context_1).forEach(function (key) { return urlWithQuery_1.searchParams.append(key, context_1[key]); });
// Add context information to url search params. If the properties
// object is included in the context, flatten it into the search params
// e.g. /?...&property.param1=param1Value&property.param2=param2Value
Object.entries(context).forEach(function (_a) {
var contextKey = _a[0], contextValue = _a[1];
if (contextKey === 'properties' && contextValue) {
Object.entries(contextValue).forEach(function (_a) {
var propertyKey = _a[0], propertyValue = _a[1];
return urlWithQuery_1.searchParams.append("properties[" + propertyKey + "]", propertyValue);
});
}
else {
urlWithQuery_1.searchParams.append(contextKey, contextValue);
}
});
return [4 /*yield*/, fetch(urlWithQuery_1.toString(), {

@@ -182,0 +202,0 @@ cache: 'no-cache',

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

var unleash=function(a){'use strict';function b(a,c){function b(){this.constructor=a}f(a,c),a.prototype=null===c?Object.create(c):(b.prototype=c.prototype,new b)}function c(a,b,c,d){return new(c||(c=Promise))(function(e,f){function g(a){try{i(d.next(a))}catch(a){f(a)}}function h(a){try{i(d["throw"](a))}catch(a){f(a)}}function i(a){a.done?e(a.value):new c(function(b){b(a.value)}).then(g,h)}i((d=d.apply(a,b||[])).next())})}function d(a,b){function c(a){return function(b){return d([a,b])}}function d(c){if(e)throw new TypeError("Generator is already executing.");for(;k;)try{if(e=1,h&&(i=2&c[0]?h["return"]:c[0]?h["throw"]||((i=h["return"])&&i.call(h),0):h.next)&&!(i=i.call(h,c[1])).done)return i;switch((h=0,i)&&(c=[2&c[0],i.value]),c[0]){case 0:case 1:i=c;break;case 4:return k.label++,{value:c[1],done:!1};case 5:k.label++,h=c[1],c=[0];continue;case 7:c=k.ops.pop(),k.trys.pop();continue;default:if((i=k.trys,!(i=0<i.length&&i[i.length-1]))&&(6===c[0]||2===c[0])){k=0;continue}if(3===c[0]&&(!i||c[1]>i[0]&&c[1]<i[3])){k.label=c[1];break}if(6===c[0]&&k.label<i[1]){k.label=i[1],i=c;break}if(i&&k.label<i[2]){k.label=i[2],k.ops.push(c);break}i[2]&&k.ops.pop(),k.trys.pop();continue;}c=b.call(a,k)}catch(a){c=[6,a],h=0}finally{e=i=0}if(5&c[0])throw c[1];return{value:c[0]?c[1]:void 0,done:!0}}var e,h,i,j,k={label:0,sent:function(){if(1&i[0])throw i[1];return i[1]},trys:[],ops:[]};return j={next:c(0),throw:c(1),return:c(2)},"function"==typeof Symbol&&(j[Symbol.iterator]=function(){return this}),j}function e(){}var f=function(a,c){return f=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(a,c){a.__proto__=c}||function(a,c){for(var b in c)c.hasOwnProperty(b)&&(a[b]=c[b])},f(a,c)},g=function(){return g=Object.assign||function(a){for(var b,c=1,d=arguments.length;c<d;c++)for(var e in b=arguments[c],b)Object.prototype.hasOwnProperty.call(b,e)&&(a[e]=b[e]);return a},g.apply(this,arguments)};e.prototype={on:function(a,b,c){var d=this.e||(this.e={});return(d[a]||(d[a]=[])).push({fn:b,ctx:c}),this},once:function(a,b,c){function d(){e.off(a,d),b.apply(c,arguments)}var e=this;return d._=b,this.on(a,d,c)},emit:function(a){var b=[].slice.call(arguments,1),c=((this.e||(this.e={}))[a]||[]).slice(),d=0,e=c.length;for(d;d<e;d++)c[d].fn.apply(c[d].ctx,b);return this},off:function(a,b){var c=this.e||(this.e={}),d=c[a],e=[];if(d&&b)for(var f=0,g=d.length;f<g;f++)d[f].fn!==b&&d[f].fn._!==b&&e.push(d[f]);return e.length?c[a]=e:delete c[a],this}};var h=e;e.TinyEmitter=h;var i=function(){function a(a){var b=a.appName,c=a.metricsInterval,d=a.disableMetrics,e=a.url,f=a.clientKey;this.disabled=void 0!==d&&d,this.metricsInterval=1e3*c,this.appName=b,this.url=e,this.started=new Date,this.clientKey=f,this.resetBucket(),"number"==typeof this.metricsInterval&&0<this.metricsInterval&&this.startTimer(2e3)}return a.prototype.stop=function(){this.timer&&(clearTimeout(this.timer),delete this.timer),this.disabled=!0},a.prototype.sendMetrics=function(){return c(this,void 0,void 0,function(){var a,b;return d(this,function(c){switch(c.label){case 0:return this.disabled?[2,!1]:this.bucketIsEmpty()?(this.resetBucket(),this.startTimer(),[2,!0]):(a=this.url+"/client/metrics",b=this.getPayload(),[4,fetch(a,{cache:"no-cache",method:"POST",headers:{Authorization:this.clientKey,Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(b)})]);case 1:return c.sent(),[2,!0];}})})},a.prototype.count=function(a,b){return!this.disabled&&this.bucket&&(this.assertBucket(a),this.bucket.toggles[a][b?"yes":"no"]++,!0)},a.prototype.assertBucket=function(a){return!this.disabled&&this.bucket&&void(!this.bucket.toggles[a]&&(this.bucket.toggles[a]={yes:0,no:0}))},a.prototype.startTimer=function(a){var b=this;return!this.disabled&&(this.timer=setTimeout(function(){b.sendMetrics()},a||this.metricsInterval),!0)},a.prototype.bucketIsEmpty=function(){return!!this.bucket&&0===Object.keys(this.bucket.toggles).length},a.prototype.resetBucket=function(){var a={start:new Date,stop:null,toggles:{}};this.bucket=a},a.prototype.closeBucket=function(){this.bucket&&(this.bucket.stop=new Date)},a.prototype.getPayload=function(){this.closeBucket();var a=this.getMetricsData();return this.resetBucket(),a},a.prototype.getMetricsData=function(){return{appName:this.appName,instanceId:"browser",bucket:this.bucket}},a}(),j=function(){function a(){this.prefix="unleash:repository"}return a.prototype.save=function(a,b){try{var c=JSON.stringify(b),d=this.prefix+":"+a;window.localStorage.setItem(d,c)}catch(a){console.error(a)}},a.prototype.get=function(a){try{var b=this.prefix+":"+a,c=window.localStorage.getItem(b);return c?JSON.parse(c):void 0}catch(a){console.error(a)}},a}(),k={READY:"ready",UPDATE:"update"},l={name:"disabled"},m="repo",n=function(a){function e(b){var c=b.storageProvider,d=b.url,e=b.clientKey,f=b.refreshInterval,g=void 0===f?30:f,h=b.metricsInterval,k=void 0===h?30:h,l=b.disableMetrics,n=b.environment,o=void 0===n?"default":n,p=b.appName,q=a.call(this)||this;if(q.toggles=[],q.etag="",!d)throw new Error("url is required");if(!e)throw new Error("clientKey is required");if(!p)throw new Error("appName is required.");return q.url=new URL(""+d),q.clientKey=e,q.storage=c||new j,q.refreshInterval=1e3*g,q.context={environment:o,appName:p},q.toggles=q.storage.get(m)||[],q.metrics=new i({appName:p,metricsInterval:k,disableMetrics:void 0!==l&&l,url:d,clientKey:e}),q}return b(e,a),e.prototype.isEnabled=function(a){var b=this.toggles.find(function(b){return b.name===a}),c=!!b&&b.enabled;return this.metrics.count(a,c),c},e.prototype.getVariant=function(a){var b=this.toggles.find(function(b){return b.name===a});return b?(this.metrics.count(a,!0),b.variant):(this.metrics.count(a,!1),l)},e.prototype.updateContext=function(a){var b={environment:this.context.environment,appName:this.context.appName};this.context=g({},b,a),this.timerRef&&this.fetchToggles()},e.prototype.start=function(){return c(this,void 0,void 0,function(){var a,b=this;return d(this,function(c){switch(c.label){case 0:return fetch?(this.stop(),a=this.refreshInterval,[4,this.fetchToggles()]):[3,2];case 1:return c.sent(),this.emit(k.READY),this.timerRef=setInterval(function(){return b.fetchToggles()},a),[3,3];case 2:console.error("Unleash: Client does not support fetch."),c.label=3;case 3:return[2];}})})},e.prototype.stop=function(){this.timerRef&&(clearInterval(this.timerRef),this.timerRef=void 0)},e.prototype.storeToggles=function(a){this.toggles=a,this.emit(k.UPDATE),this.storage.save(m,a)},e.prototype.fetchToggles=function(){return c(this,void 0,void 0,function(){var a,b,c,e,f;return d(this,function(d){switch(d.label){case 0:if(!fetch)return[3,6];d.label=1;case 1:return d.trys.push([1,5,,6]),a=this.context,b=new URL(this.url.toString()),Object.keys(a).forEach(function(c){return b.searchParams.append(c,a[c])}),[4,fetch(b.toString(),{cache:"no-cache",headers:{Authorization:this.clientKey,Accept:"application/json","Content-Type":"application/json","If-None-Match":this.etag}})];case 2:return(c=d.sent(),!(c.ok&&304!==c.status))?[3,4]:(this.etag=c.headers.get("ETag")||"",[4,c.json()]);case 3:e=d.sent(),this.storeToggles(e.toggles),d.label=4;case 4:return[3,6];case 5:return f=d.sent(),console.error("Unleash: unable to fetch feature toggles",f),[3,6];case 6:return[2];}})})},e}(h);return a.EVENTS=k,a.UnleashClient=n,a}({});
var unleash=function(a){'use strict';function b(a,c){function b(){this.constructor=a}f(a,c),a.prototype=null===c?Object.create(c):(b.prototype=c.prototype,new b)}function c(a,b,c,d){return new(c||(c=Promise))(function(e,f){function g(a){try{i(d.next(a))}catch(a){f(a)}}function h(a){try{i(d["throw"](a))}catch(a){f(a)}}function i(a){a.done?e(a.value):new c(function(b){b(a.value)}).then(g,h)}i((d=d.apply(a,b||[])).next())})}function d(a,b){function c(a){return function(b){return d([a,b])}}function d(c){if(e)throw new TypeError("Generator is already executing.");for(;k;)try{if(e=1,h&&(i=2&c[0]?h["return"]:c[0]?h["throw"]||((i=h["return"])&&i.call(h),0):h.next)&&!(i=i.call(h,c[1])).done)return i;switch((h=0,i)&&(c=[2&c[0],i.value]),c[0]){case 0:case 1:i=c;break;case 4:return k.label++,{value:c[1],done:!1};case 5:k.label++,h=c[1],c=[0];continue;case 7:c=k.ops.pop(),k.trys.pop();continue;default:if((i=k.trys,!(i=0<i.length&&i[i.length-1]))&&(6===c[0]||2===c[0])){k=0;continue}if(3===c[0]&&(!i||c[1]>i[0]&&c[1]<i[3])){k.label=c[1];break}if(6===c[0]&&k.label<i[1]){k.label=i[1],i=c;break}if(i&&k.label<i[2]){k.label=i[2],k.ops.push(c);break}i[2]&&k.ops.pop(),k.trys.pop();continue;}c=b.call(a,k)}catch(a){c=[6,a],h=0}finally{e=i=0}if(5&c[0])throw c[1];return{value:c[0]?c[1]:void 0,done:!0}}var e,h,i,j,k={label:0,sent:function(){if(1&i[0])throw i[1];return i[1]},trys:[],ops:[]};return j={next:c(0),throw:c(1),return:c(2)},"function"==typeof Symbol&&(j[Symbol.iterator]=function(){return this}),j}function e(){}var f=function(a,c){return f=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(a,c){a.__proto__=c}||function(a,c){for(var b in c)c.hasOwnProperty(b)&&(a[b]=c[b])},f(a,c)},g=function(){return g=Object.assign||function(a){for(var b,c=1,d=arguments.length;c<d;c++)for(var e in b=arguments[c],b)Object.prototype.hasOwnProperty.call(b,e)&&(a[e]=b[e]);return a},g.apply(this,arguments)};e.prototype={on:function(a,b,c){var d=this.e||(this.e={});return(d[a]||(d[a]=[])).push({fn:b,ctx:c}),this},once:function(a,b,c){function d(){e.off(a,d),b.apply(c,arguments)}var e=this;return d._=b,this.on(a,d,c)},emit:function(a){var b=[].slice.call(arguments,1),c=((this.e||(this.e={}))[a]||[]).slice(),d=0,e=c.length;for(d;d<e;d++)c[d].fn.apply(c[d].ctx,b);return this},off:function(a,b){var c=this.e||(this.e={}),d=c[a],e=[];if(d&&b)for(var f=0,g=d.length;f<g;f++)d[f].fn!==b&&d[f].fn._!==b&&e.push(d[f]);return e.length?c[a]=e:delete c[a],this}};var h=e;e.TinyEmitter=h;var i=function(){function a(a){var b=a.appName,c=a.metricsInterval,d=a.disableMetrics,e=a.url,f=a.clientKey;this.disabled=void 0!==d&&d,this.metricsInterval=1e3*c,this.appName=b,this.url=e,this.started=new Date,this.clientKey=f,this.resetBucket(),"number"==typeof this.metricsInterval&&0<this.metricsInterval&&this.startTimer(2e3)}return a.prototype.stop=function(){this.timer&&(clearTimeout(this.timer),delete this.timer),this.disabled=!0},a.prototype.sendMetrics=function(){return c(this,void 0,void 0,function(){var a,b;return d(this,function(c){switch(c.label){case 0:return this.disabled?[2,!1]:this.bucketIsEmpty()?(this.resetBucket(),this.startTimer(),[2,!0]):(a=this.url+"/client/metrics",b=this.getPayload(),[4,fetch(a,{cache:"no-cache",method:"POST",headers:{Authorization:this.clientKey,Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(b)})]);case 1:return c.sent(),[2,!0];}})})},a.prototype.count=function(a,b){return!this.disabled&&this.bucket&&(this.assertBucket(a),this.bucket.toggles[a][b?"yes":"no"]++,!0)},a.prototype.assertBucket=function(a){return!this.disabled&&this.bucket&&void(!this.bucket.toggles[a]&&(this.bucket.toggles[a]={yes:0,no:0}))},a.prototype.startTimer=function(a){var b=this;return!this.disabled&&(this.timer=setTimeout(function(){b.sendMetrics()},a||this.metricsInterval),!0)},a.prototype.bucketIsEmpty=function(){return!!this.bucket&&0===Object.keys(this.bucket.toggles).length},a.prototype.resetBucket=function(){var a={start:new Date,stop:null,toggles:{}};this.bucket=a},a.prototype.closeBucket=function(){this.bucket&&(this.bucket.stop=new Date)},a.prototype.getPayload=function(){this.closeBucket();var a=this.getMetricsData();return this.resetBucket(),a},a.prototype.getMetricsData=function(){return{appName:this.appName,instanceId:"browser",bucket:this.bucket}},a}(),j=function(){function a(){this.prefix="unleash:repository"}return a.prototype.save=function(a,b){try{var c=JSON.stringify(b),d=this.prefix+":"+a;window.localStorage.setItem(d,c)}catch(a){console.error(a)}},a.prototype.get=function(a){try{var b=this.prefix+":"+a,c=window.localStorage.getItem(b);return c?JSON.parse(c):void 0}catch(a){console.error(a)}},a}(),k={READY:"ready",UPDATE:"update"},l={name:"disabled"},m="repo",n=function(a){function e(b){var c=b.storageProvider,d=b.url,e=b.clientKey,f=b.refreshInterval,h=void 0===f?30:f,k=b.metricsInterval,l=void 0===k?30:k,n=b.disableMetrics,o=b.appName,p=b.environment,q=void 0===p?"default":p,r=b.context,s=a.call(this)||this;if(s.toggles=[],s.etag="",!d)throw new Error("url is required");if(!e)throw new Error("clientKey is required");if(!o)throw new Error("appName is required.");return s.url=new URL(""+d),s.clientKey=e,s.storage=c||new j,s.refreshInterval=1e3*h,s.context=g({appName:o,environment:q},r),s.toggles=s.storage.get(m)||[],s.metrics=new i({appName:o,metricsInterval:l,disableMetrics:void 0!==n&&n,url:d,clientKey:e}),s}return b(e,a),e.prototype.isEnabled=function(a){var b=this.toggles.find(function(b){return b.name===a}),c=!!b&&b.enabled;return this.metrics.count(a,c),c},e.prototype.getVariant=function(a){var b=this.toggles.find(function(b){return b.name===a});return b?(this.metrics.count(a,!0),b.variant):(this.metrics.count(a,!1),l)},e.prototype.updateContext=function(a){(a.appName||a.environment)&&console.warn("appName and environment are static. They can't be updated with updateContext.");var b={environment:this.context.environment,appName:this.context.appName};this.context=g({},b,a),this.timerRef&&this.fetchToggles()},e.prototype.start=function(){return c(this,void 0,void 0,function(){var a,b=this;return d(this,function(c){switch(c.label){case 0:return fetch?(this.stop(),a=this.refreshInterval,[4,this.fetchToggles()]):[3,2];case 1:return c.sent(),this.emit(k.READY),this.timerRef=setInterval(function(){return b.fetchToggles()},a),[3,3];case 2:console.error("Unleash: Client does not support fetch."),c.label=3;case 3:return[2];}})})},e.prototype.stop=function(){this.timerRef&&(clearInterval(this.timerRef),this.timerRef=void 0)},e.prototype.storeToggles=function(a){this.toggles=a,this.emit(k.UPDATE),this.storage.save(m,a)},e.prototype.fetchToggles=function(){return c(this,void 0,void 0,function(){var a,b,c,e,f;return d(this,function(d){switch(d.label){case 0:if(!fetch)return[3,6];d.label=1;case 1:return d.trys.push([1,5,,6]),a=this.context,b=new URL(this.url.toString()),Object.entries(a).forEach(function(a){var c=a[0],d=a[1];"properties"===c&&d?Object.entries(d).forEach(function(a){var c=a[0],d=a[1];return b.searchParams.append("properties["+c+"]",d)}):b.searchParams.append(c,d)}),[4,fetch(b.toString(),{cache:"no-cache",headers:{Authorization:this.clientKey,Accept:"application/json","Content-Type":"application/json","If-None-Match":this.etag}})];case 2:return(c=d.sent(),!(c.ok&&304!==c.status))?[3,4]:(this.etag=c.headers.get("ETag")||"",[4,c.json()]);case 3:e=d.sent(),this.storeToggles(e.toggles),d.label=4;case 4:return[3,6];case 5:return f=d.sent(),console.error("Unleash: unable to fetch feature toggles",f),[3,6];case 6:return[2];}})})},e}(h);return a.EVENTS=k,a.UnleashClient=n,a}({});

@@ -6,6 +6,6 @@ {

"dependencies": {
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-scripts": "3.3.0",
"unleash-proxy-client": "^1.0.0"
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-scripts": "^3.4.1",
"unleash-proxy-client": "^1.0.1"
},

@@ -12,0 +12,0 @@ "scripts": {

{
"name": "unleash-proxy-client",
"version": "1.0.1",
"version": "1.1.0",
"description": "A browser client that can be used together with the unleash-proxy.",

@@ -12,3 +12,3 @@ "main": "./build/index.js",

"scripts": {
"preversion": "npm run build",
"preversion": "rm -rf build && npm run build",
"build": "npm run build:ts && npm run build:web",

@@ -15,0 +15,0 @@ "build:ts": "tsc",

@@ -72,3 +72,3 @@ # Unleash Proxy Client for the browser (js)

var client = new unleash.UnleashClient(config);
clinet.updateContext({userId: '1233'})
client.updateContext({userId: '1233'})

@@ -75,0 +75,0 @@ client.on('update', () => {

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