Socket
Socket
Sign inDemoInstall

atom.storage

Package Overview
Dependencies
Maintainers
1
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

atom.storage - npm Package Compare versions

Comparing version 0.5.3 to 0.5.4

26

dist/atom.storage.cjs.js

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

function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
var storages = new WeakMap();
var usedOptions = void 0;
if (process.env.NODE_ENV !== "production") usedOptions = new WeakMap();
if (process.env.NODE_ENV !== 'production') usedOptions = new WeakMap();

@@ -29,3 +27,3 @@ var getAtoms = function getAtoms(storage) {

var seemsValid = function seemsValid(data) {
return data && data.constructor === Object && "value" in data;
return !(data instanceof Error) && data && 'value' in data;
};

@@ -81,8 +79,6 @@

var atom_storage = (function (_ref3) {
var key = _ref3.key,
storage = _ref3.storage,
options = _objectWithoutProperties(_ref3, ["key", "storage"]);
var defaultValue = options.value,
function Stored(options) {
var key = options.key,
storage = options.storage,
defaultValue = options.value,
Atom = options.Atom,

@@ -100,3 +96,3 @@ time = options.time,

if (process.env.NODE_ENV !== "production") usedOptions.set(atom, options);
if (process.env.NODE_ENV !== 'production') usedOptions.set(atom, options);

@@ -119,6 +115,6 @@ var changes = atom.changes();

});
} else if (process.env.NODE_ENV !== "production") {
} else if (process.env.NODE_ENV !== 'production') {
var oldOptions = usedOptions.get(atom);
for (var k in options) {
if (!infestines.acyclicEqualsU(options[k], oldOptions[k])) throw new Error("atom.storage: Created two atoms with same storage and key " + JSON.stringify(key) + ", but different " + JSON.stringify(k) + ": first " + JSON.stringify(oldOptions[k]) + " and later " + JSON.stringify(options[k]) + ".");
if (!infestines.acyclicEqualsU(options[k], oldOptions[k])) console.warn('atom.storage: Created two atoms with same storage and key ' + JSON.stringify(key) + ', but different ' + JSON.stringify(k) + ': first ' + JSON.stringify(oldOptions[k]) + ' and later ' + JSON.stringify(options[k]) + '.');
}

@@ -128,6 +124,6 @@ }

return atom;
});
}
exports.unsafeDeleteAtom = unsafeDeleteAtom;
exports.expireNow = expireNow;
exports['default'] = atom_storage;
exports.default = Stored;
import { acyclicEqualsU } from 'infestines';
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
var storages = new WeakMap();
var usedOptions = void 0;
if (process.env.NODE_ENV !== "production") usedOptions = new WeakMap();
if (process.env.NODE_ENV !== 'production') usedOptions = new WeakMap();

@@ -24,3 +22,3 @@ var getAtoms = function getAtoms(storage) {

var seemsValid = function seemsValid(data) {
return data && data.constructor === Object && "value" in data;
return !(data instanceof Error) && data && 'value' in data;
};

@@ -76,8 +74,6 @@

var atom_storage = (function (_ref3) {
var key = _ref3.key,
storage = _ref3.storage,
options = _objectWithoutProperties(_ref3, ["key", "storage"]);
var defaultValue = options.value,
function Stored(options) {
var key = options.key,
storage = options.storage,
defaultValue = options.value,
Atom = options.Atom,

@@ -95,3 +91,3 @@ time = options.time,

if (process.env.NODE_ENV !== "production") usedOptions.set(atom, options);
if (process.env.NODE_ENV !== 'production') usedOptions.set(atom, options);

@@ -114,6 +110,6 @@ var changes = atom.changes();

});
} else if (process.env.NODE_ENV !== "production") {
} else if (process.env.NODE_ENV !== 'production') {
var oldOptions = usedOptions.get(atom);
for (var k in options) {
if (!acyclicEqualsU(options[k], oldOptions[k])) throw new Error("atom.storage: Created two atoms with same storage and key " + JSON.stringify(key) + ", but different " + JSON.stringify(k) + ": first " + JSON.stringify(oldOptions[k]) + " and later " + JSON.stringify(options[k]) + ".");
if (!acyclicEqualsU(options[k], oldOptions[k])) console.warn('atom.storage: Created two atoms with same storage and key ' + JSON.stringify(key) + ', but different ' + JSON.stringify(k) + ': first ' + JSON.stringify(oldOptions[k]) + ' and later ' + JSON.stringify(options[k]) + '.');
}

@@ -123,4 +119,5 @@ }

return atom;
});
}
export { unsafeDeleteAtom, expireNow };export default atom_storage;
export default Stored;
export { unsafeDeleteAtom, expireNow };
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('infestines')) :
typeof define === 'function' && define.amd ? define(['exports', 'infestines'], factory) :
(factory((global.atom = global.atom || {}, global.atom.storage = global.atom.storage || {}),global.I));
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('infestines')) :
typeof define === 'function' && define.amd ? define(['exports', 'infestines'], factory) :
(factory((global.atom = global.atom || {}, global.atom.storage = {}),global.I));
}(this, (function (exports,infestines) { 'use strict';
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
var storages = new WeakMap();
var usedOptions = void 0;
usedOptions = new WeakMap();
var storages = new WeakMap();
var usedOptions = void 0;
usedOptions = new WeakMap();
var getAtoms = function getAtoms(storage) {
var atoms = storages.get(storage);
if (!atoms) storages.set(storage, atoms = {});
return atoms;
};
var getAtoms = function getAtoms(storage) {
var atoms = storages.get(storage);
if (!atoms) storages.set(storage, atoms = {});
return atoms;
};
var tryParse = function tryParse(json) {
try {
return JSON.parse(json);
} catch (error) {
return error;
}
};
var tryParse = function tryParse(json) {
try {
return JSON.parse(json);
} catch (error) {
return error;
}
};
var seemsValid = function seemsValid(data) {
return !(data instanceof Error) && data && 'value' in data;
};
var seemsValid = function seemsValid(data) {
return data && data.constructor === Object && "value" in data;
};
var getValue = function getValue(storage, key, schema, defaultValue, time) {
var json = storage.getItem(key);
if (!json) return defaultValue;
var getValue = function getValue(storage, key, schema, defaultValue, time) {
var json = storage.getItem(key);
if (!json) return defaultValue;
var data = tryParse(json);
if (!seemsValid(data) || !infestines.acyclicEqualsU(data.schema, schema) || infestines.acyclicEqualsU(data.value, defaultValue)) {
storage.removeItem(key);
return defaultValue;
}
var data = tryParse(json);
if (!seemsValid(data) || !infestines.acyclicEqualsU(data.schema, schema) || infestines.acyclicEqualsU(data.value, defaultValue)) {
storage.removeItem(key);
return defaultValue;
}
if (0 <= time) {
data.expires = time + Date.now();
if (0 <= time) {
data.expires = time + Date.now();
storage.setItem(key, JSON.stringify(data));
}
storage.setItem(key, JSON.stringify(data));
}
return data.value;
};
return data.value;
};
var unsafeDeleteAtom = function unsafeDeleteAtom(_ref) {
var storage = _ref.storage,
key = _ref.key;
var unsafeDeleteAtom = function unsafeDeleteAtom(_ref) {
var storage = _ref.storage,
key = _ref.key;
var atoms = getAtoms(storage);
delete atoms[key];
};
var atoms = getAtoms(storage);
delete atoms[key];
};
var expireNow = function expireNow(_ref2) {
var storage = _ref2.storage,
regex = _ref2.regex,
unsafeDeleteAtoms = _ref2.unsafeDeleteAtoms;
var expireNow = function expireNow(_ref2) {
var storage = _ref2.storage,
regex = _ref2.regex,
unsafeDeleteAtoms = _ref2.unsafeDeleteAtoms;
for (var i = 0; i < storage.length; ++i) {
var key = storage.key(i);
for (var i = 0; i < storage.length; ++i) {
var key = storage.key(i);
if (!regex.test(key)) continue;
if (!regex.test(key)) continue;
var data = tryParse(storage.getItem(key));
if (!seemsValid(data)) continue;
var data = tryParse(storage.getItem(key));
if (!seemsValid(data)) continue;
if (data.expires <= Date.now()) {
storage.removeItem(key);
if (data.expires <= Date.now()) {
storage.removeItem(key);
if (unsafeDeleteAtoms) unsafeDeleteAtom({ storage: storage, key: key });
if (unsafeDeleteAtoms) unsafeDeleteAtom({ storage: storage, key: key });
}
}
}
};
};
var atom_storage = (function (_ref3) {
var key = _ref3.key,
storage = _ref3.storage,
options = _objectWithoutProperties(_ref3, ["key", "storage"]);
function Stored(options) {
var key = options.key,
storage = options.storage,
defaultValue = options.value,
Atom = options.Atom,
time = options.time,
schema = options.schema,
debounce = options.debounce;
var defaultValue = options.value,
Atom = options.Atom,
time = options.time,
schema = options.schema,
debounce = options.debounce;
var atoms = getAtoms(storage);
var atoms = getAtoms(storage);
var atom = atoms[key];
if (!atom) {
atoms[key] = atom = Atom(getValue(storage, key, schema, defaultValue, time));
var atom = atoms[key];
if (!atom) {
atoms[key] = atom = Atom(getValue(storage, key, schema, defaultValue, time));
usedOptions.set(atom, options);
usedOptions.set(atom, options);
var changes = atom.changes();
if (0 <= debounce) changes = changes.debounce(debounce);
var changes = atom.changes();
if (0 <= debounce) changes = changes.debounce(debounce);
changes.onValue(function (value) {
if (infestines.acyclicEqualsU(value, defaultValue)) {
storage.removeItem(key);
} else {
var data = { value: value };
changes.onValue(function (value) {
if (infestines.acyclicEqualsU(value, defaultValue)) {
storage.removeItem(key);
} else {
var data = { value: value };
if (schema !== undefined) data.schema = schema;
if (schema !== undefined) data.schema = schema;
if (0 <= time) data.expires = time + Date.now();
if (0 <= time) data.expires = time + Date.now();
storage.setItem(key, JSON.stringify(data));
storage.setItem(key, JSON.stringify(data));
}
});
} else {
var oldOptions = usedOptions.get(atom);
for (var k in options) {
if (!infestines.acyclicEqualsU(options[k], oldOptions[k])) console.warn('atom.storage: Created two atoms with same storage and key ' + JSON.stringify(key) + ', but different ' + JSON.stringify(k) + ': first ' + JSON.stringify(oldOptions[k]) + ' and later ' + JSON.stringify(options[k]) + '.');
}
});
} else {
var oldOptions = usedOptions.get(atom);
for (var k in options) {
if (!infestines.acyclicEqualsU(options[k], oldOptions[k])) throw new Error("atom.storage: Created two atoms with same storage and key " + JSON.stringify(key) + ", but different " + JSON.stringify(k) + ": first " + JSON.stringify(oldOptions[k]) + " and later " + JSON.stringify(options[k]) + ".");
}
return atom;
}
return atom;
});
exports.unsafeDeleteAtom = unsafeDeleteAtom;
exports.expireNow = expireNow;
exports.default = Stored;
exports.unsafeDeleteAtom = unsafeDeleteAtom;
exports.expireNow = expireNow;
exports['default'] = atom_storage;
Object.defineProperty(exports, '__esModule', { value: true });
Object.defineProperty(exports, '__esModule', { value: true });
})));

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

!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("infestines")):"function"==typeof define&&define.amd?define(["exports","infestines"],t):t((e.atom=e.atom||{},e.atom.storage=e.atom.storage||{}),e.I)}(this,function(e,t){"use strict";function r(e,t){var r={};for(var n in e)t.indexOf(n)>=0||Object.prototype.hasOwnProperty.call(e,n)&&(r[n]=e[n]);return r}var n=new WeakMap,a=function(e){var t=n.get(e);return t||n.set(e,t={}),t},o=function(e){try{return JSON.parse(e)}catch(e){return e}},i=function(e){return e&&e.constructor===Object&&"value"in e},s=function(e,r,n,a,s){var u=e.getItem(r);if(!u)return a;var c=o(u);return i(c)&&t.acyclicEqualsU(c.schema,n)&&!t.acyclicEqualsU(c.value,a)?(0<=s&&(c.expires=s+Date.now(),e.setItem(r,JSON.stringify(c))),c.value):(e.removeItem(r),a)},u=function(e){var t=e.storage,r=e.key;delete a(t)[r]},c=function(e){for(var t=e.storage,r=e.regex,n=e.unsafeDeleteAtoms,a=0;a<t.length;++a){var s=t.key(a);if(r.test(s)){var c=o(t.getItem(s));i(c)&&c.expires<=Date.now()&&(t.removeItem(s),n&&u({storage:t,key:s}))}}},f=function(e){var n=e.key,o=e.storage,i=r(e,["key","storage"]),u=i.value,c=i.Atom,f=i.time,l=i.schema,m=i.debounce,v=a(o),y=v[n];if(!y){v[n]=y=c(s(o,n,l,u,f));var p=y.changes();0<=m&&(p=p.debounce(m)),p.onValue(function(e){if(t.acyclicEqualsU(e,u))o.removeItem(n);else{var r={value:e};void 0!==l&&(r.schema=l),0<=f&&(r.expires=f+Date.now()),o.setItem(n,JSON.stringify(r))}})}return y};e.unsafeDeleteAtom=u,e.expireNow=c,e.default=f,Object.defineProperty(e,"__esModule",{value:!0})});
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("infestines")):"function"==typeof define&&define.amd?define(["exports","infestines"],t):t((e.atom=e.atom||{},e.atom.storage={}),e.I)}(this,function(e,m){"use strict";var n=new WeakMap,l=function(e){var t=n.get(e);return t||n.set(e,t={}),t},v=function(e){try{return JSON.parse(e)}catch(e){return e}},d=function(e){return!(e instanceof Error)&&e&&"value"in e},s=function(e){var t=e.key;delete l(e.storage)[t]};e.unsafeDeleteAtom=s,e.expireNow=function(e){for(var t=e.storage,n=e.regex,r=e.unsafeDeleteAtoms,a=0;a<t.length;++a){var o=t.key(a);if(n.test(o)){var i=v(t.getItem(o));d(i)&&i.expires<=Date.now()&&(t.removeItem(o),r&&s({storage:t,key:o}))}}},e.default=function(e){var n=e.key,r=e.storage,a=e.value,t=e.Atom,o=e.time,i=e.schema,s=e.debounce,u=l(r),c=u[n];if(!c){u[n]=c=t(function(e,t,n,r,a){var o=e.getItem(t);if(!o)return r;var i=v(o);return d(i)&&m.acyclicEqualsU(i.schema,n)&&!m.acyclicEqualsU(i.value,r)?(0<=a&&(i.expires=a+Date.now(),e.setItem(t,JSON.stringify(i))),i.value):(e.removeItem(t),r)}(r,n,i,a,o));var f=c.changes();0<=s&&(f=f.debounce(s)),f.onValue(function(e){if(m.acyclicEqualsU(e,a))r.removeItem(n);else{var t={value:e};void 0!==i&&(t.schema=i),0<=o&&(t.expires=o+Date.now()),r.setItem(n,JSON.stringify(t))}})}return c},Object.defineProperty(e,"__esModule",{value:!0})});
{
"name": "atom.storage",
"version": "0.5.3",
"version": "0.5.4",
"description": "Reactive variables with Storage",
"module": "dist/atom.storage.es.js",
"main": "dist/atom.storage.cjs.js",
"sideEffects": false,
"scripts": {
"dist": "npm run dist:umd & npm run dist:umd.min & npm run dist:es & npm run dist:cjs & wait",
"dist:cjs": " NODE_ENV= rollup -c -n atom.storage -i src/atom.storage.js -f cjs -o dist/atom.storage.cjs.js",
"dist:es": " NODE_ENV= rollup -c -n atom.storage -i src/atom.storage.js -f es -o dist/atom.storage.es.js",
"dist:umd": " NODE_ENV=dev rollup -c -n atom.storage -i src/atom.storage.js -f umd -o dist/atom.storage.js",
"dist:umd.min": "NODE_ENV=production rollup -c -n atom.storage -i src/atom.storage.js -f umd -o dist/atom.storage.min.js",
"dist": "rollup -c",
"lint": "eslint src test",
"prepublish": "npm run lint && npm run dist && npm run test",
"prepare": "npm run lint && npm run dist && npm run test",
"report-coverage": "nyc report --reporter=lcov > coverage.lcov && codecov",
"test": "nyc mocha"

@@ -31,24 +29,25 @@ },

"dependencies": {
"infestines": "^0.4.0"
"infestines": "^0.4.9"
},
"devDependencies": {
"babel-cli": "^6.24.1",
"babel-eslint": "^7.2.2",
"babel-plugin-transform-es2015-modules-commonjs": "^6.24.1",
"babel-cli": "^6.26.0",
"babel-eslint": "^8.2.6",
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-3": "^6.24.1",
"babel-register": "^6.24.1",
"eslint": "^3.19.0",
"kefir": "^3.7.1",
"kefir.atom": "^5.3.4",
"mocha": "^3.2.0",
"node-localstorage": "^1.3.0",
"nyc": "^10.2.0",
"rollup": "^0.41.6",
"rollup-plugin-babel": "^2.7.1",
"rollup-plugin-commonjs": "^8.0.2",
"rollup-plugin-node-resolve": "^3.0.0",
"rollup-plugin-replace": "^1.1.1",
"rollup-plugin-uglify": "^1.0.1"
"babel-register": "^6.26.0",
"codecov": "^3.0.4",
"eslint": "^5.3.0",
"kefir": "^3.8.3",
"kefir.atom": "^5.5.1",
"mocha": "^5.2.0",
"node-localstorage": "^1.3.1",
"nyc": "^12.0.2",
"rollup": "^0.64.0",
"rollup-plugin-babel": "^3.0.7",
"rollup-plugin-commonjs": "^9.1.4",
"rollup-plugin-node-resolve": "^3.3.0",
"rollup-plugin-replace": "^2.0.0",
"rollup-plugin-uglify": "^4.0.0"
}
}

@@ -6,3 +6,7 @@ A [`Storage`](https://developer.mozilla.org/en-US/docs/Web/API/Storage)

[![npm version](https://badge.fury.io/js/atom.storage.svg)](http://badge.fury.io/js/atom.storage) [![Build Status](https://travis-ci.org/calmm-js/atom.storage.svg?branch=master)](https://travis-ci.org/calmm-js/atom.storage) [![](https://david-dm.org/calmm-js/atom.storage.svg)](https://david-dm.org/calmm-js/atom.storage) [![](https://david-dm.org/calmm-js/atom.storage/dev-status.svg)](https://david-dm.org/calmm-js/atom.storage?type=dev)
[![npm version](https://badge.fury.io/js/atom.storage.svg)](http://badge.fury.io/js/atom.storage)
[![Build Status](https://travis-ci.org/calmm-js/atom.storage.svg?branch=master)](https://travis-ci.org/calmm-js/atom.storage)
[![Code Coverage](https://img.shields.io/codecov/c/github/calmm-js/atom.storage/master.svg)](https://codecov.io/github/calmm-js/atom.storage?branch=master)
[![](https://david-dm.org/calmm-js/atom.storage.svg)](https://david-dm.org/calmm-js/atom.storage)
[![](https://david-dm.org/calmm-js/atom.storage/dev-status.svg)](https://david-dm.org/calmm-js/atom.storage?type=dev)

@@ -26,3 +30,3 @@ ## Usage

The default import
The default export

@@ -29,0 +33,0 @@ ```js

@@ -1,12 +0,10 @@

import {acyclicEqualsU} from "infestines"
import {acyclicEqualsU} from 'infestines'
const storages = new WeakMap()
let usedOptions
if (process.env.NODE_ENV !== "production")
usedOptions = new WeakMap()
if (process.env.NODE_ENV !== 'production') usedOptions = new WeakMap()
const getAtoms = storage => {
let atoms = storages.get(storage)
if (!atoms)
storages.set(storage, atoms = {})
if (!atoms) storages.set(storage, (atoms = {}))
return atoms

@@ -23,14 +21,14 @@ }

const seemsValid =
data => data && data.constructor === Object && "value" in data
const seemsValid = data => !(data instanceof Error) && data && 'value' in data
const getValue = (storage, key, schema, defaultValue, time) => {
const json = storage.getItem(key)
if (!json)
return defaultValue
if (!json) return defaultValue
const data = tryParse(json)
if (!seemsValid(data) ||
!acyclicEqualsU(data.schema, schema) ||
acyclicEqualsU(data.value, defaultValue)) {
if (
!seemsValid(data) ||
!acyclicEqualsU(data.schema, schema) ||
acyclicEqualsU(data.value, defaultValue)
) {
storage.removeItem(key)

@@ -55,11 +53,9 @@ return defaultValue

export const expireNow = ({storage, regex, unsafeDeleteAtoms}) => {
for (let i=0; i<storage.length; ++i) {
for (let i = 0; i < storage.length; ++i) {
const key = storage.key(i)
if (!regex.test(key))
continue
if (!regex.test(key)) continue
const data = tryParse(storage.getItem(key))
if (!seemsValid(data))
continue
if (!seemsValid(data)) continue

@@ -69,4 +65,3 @@ if (data.expires <= Date.now()) {

if (unsafeDeleteAtoms)
unsafeDeleteAtom({storage, key})
if (unsafeDeleteAtoms) unsafeDeleteAtom({storage, key})
}

@@ -76,4 +71,12 @@ }

export default ({key, storage, ...options}) => {
const {value: defaultValue, Atom, time, schema, debounce} = options
function Stored(options) {
const {
key,
storage,
value: defaultValue,
Atom,
time,
schema,
debounce
} = options

@@ -86,8 +89,6 @@ const atoms = getAtoms(storage)

if (process.env.NODE_ENV !== "production")
usedOptions.set(atom, options)
if (process.env.NODE_ENV !== 'production') usedOptions.set(atom, options)
let changes = atom.changes()
if (0 <= debounce)
changes = changes.debounce(debounce)
if (0 <= debounce) changes = changes.debounce(debounce)

@@ -100,7 +101,5 @@ changes.onValue(value => {

if (schema !== undefined)
data.schema = schema
if (schema !== undefined) data.schema = schema
if (0 <= time)
data.expires = time + Date.now()
if (0 <= time) data.expires = time + Date.now()

@@ -110,7 +109,13 @@ storage.setItem(key, JSON.stringify(data))

})
} else if (process.env.NODE_ENV !== "production") {
} else if (process.env.NODE_ENV !== 'production') {
const oldOptions = usedOptions.get(atom)
for (const k in options)
if (!acyclicEqualsU(options[k], oldOptions[k]))
throw new Error(`atom.storage: Created two atoms with same storage and key ${JSON.stringify(key)}, but different ${JSON.stringify(k)}: first ${JSON.stringify(oldOptions[k])} and later ${JSON.stringify(options[k])}.`)
console.warn(
`atom.storage: Created two atoms with same storage and key ${JSON.stringify(
key
)}, but different ${JSON.stringify(k)}: first ${JSON.stringify(
oldOptions[k]
)} and later ${JSON.stringify(options[k])}.`
)
}

@@ -120,1 +125,3 @@

}
export default Stored
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