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

@deckstar/final-form

Package Overview
Dependencies
Maintainers
1
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@deckstar/final-form - npm Package Compare versions

Comparing version 1.0.3 to 1.0.4

2

dist/package.json
{
"name": "@deckstar/final-form",
"version": "1.0.2",
"version": "1.0.3",
"description": "🏁 Framework agnostic, high performance, subscription-based form state management",

@@ -5,0 +5,0 @@ "main": "dist/src",

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

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ARRAY_ERROR = exports.FORM_ERROR = void 0;
/**

@@ -9,3 +6,3 @@ * A special `string` key used to return a whole-form

*/
exports.FORM_ERROR = "FINAL_FORM/form-error";
export const FORM_ERROR = "FINAL_FORM/form-error";
/**

@@ -15,2 +12,2 @@ * A special `string` key used to return an error for an

*/
exports.ARRAY_ERROR = "FINAL_FORM/array-error";
export const ARRAY_ERROR = "FINAL_FORM/array-error";

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

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**

@@ -30,2 +28,2 @@ * An _à la carte_ list of all the possible things you

];
exports.default = fieldSubscriptionItems;
export default fieldSubscriptionItems;

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

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fieldSubscriptionItems_1 = __importDefault(require("./fieldSubscriptionItems"));
const subscriptionFilter_1 = __importDefault(require("./subscriptionFilter"));
import fieldSubscriptionItems from "./fieldSubscriptionItems";
import subscriptionFilter from "./subscriptionFilter";
const shallowEqualKeys = ["data"];

@@ -19,6 +14,6 @@ /**

};
const different = (0, subscriptionFilter_1.default)(result, state, previousState, subscription, fieldSubscriptionItems_1.default, shallowEqualKeys) || !previousState;
const different = subscriptionFilter(result, state, previousState, subscription, fieldSubscriptionItems, shallowEqualKeys) || !previousState;
const stateResult = different || force ? result : undefined;
return stateResult;
};
exports.default = filterFieldState;
export default filterFieldState;

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

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const formSubscriptionItems_1 = __importDefault(require("./formSubscriptionItems"));
const subscriptionFilter_1 = __importDefault(require("./subscriptionFilter"));
import formSubscriptionItems from "./formSubscriptionItems";
import subscriptionFilter from "./subscriptionFilter";
const shallowEqualKeys = ["touched", "visited"];

@@ -13,8 +8,7 @@ /**

*/
function filterFormState(state, previousState, subscription, force) {
export default function filterFormState(state, previousState, subscription, force) {
const result = {};
const different = (0, subscriptionFilter_1.default)(result, state, previousState, subscription, formSubscriptionItems_1.default, shallowEqualKeys) || !previousState;
const different = subscriptionFilter(result, state, previousState, subscription, formSubscriptionItems, shallowEqualKeys) || !previousState;
const stateResult = different || force ? result : undefined;
return stateResult;
}
exports.default = filterFormState;

@@ -1,18 +0,12 @@

"use strict";
/* eslint-disable @typescript-eslint/no-dynamic-delete */
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.configOptions = void 0;
const constants_1 = require("./constants");
const filterFieldState_1 = __importDefault(require("./filterFieldState"));
const filterFormState_1 = __importDefault(require("./filterFormState"));
const isPromise_1 = __importDefault(require("./isPromise"));
const memoize_1 = __importDefault(require("./memoize"));
const publishFieldState_1 = __importDefault(require("./publishFieldState"));
const shallowEqual_1 = __importDefault(require("./shallowEqual"));
const getIn_1 = __importDefault(require("./structure/getIn"));
const setIn_1 = __importDefault(require("./structure/setIn"));
exports.configOptions = [
import { ARRAY_ERROR, FORM_ERROR } from "./constants";
import filterFieldState from "./filterFieldState";
import filterFormState from "./filterFormState";
import isPromise from "./isPromise";
import memoize from "./memoize";
import publishFieldState from "./publishFieldState";
import shallowEqual from "./shallowEqual";
import getIn from "./structure/getIn";
import setIn from "./structure/setIn";
export const configOptions = [
"debug",

@@ -137,5 +131,5 @@ "initialValues",

const changeValue = (mState, name, mutate) => {
const before = (0, getIn_1.default)(mState.formState.values, name);
const before = getIn(mState.formState.values, name);
const after = mutate(before);
mState.formState.values = (0, setIn_1.default)(mState.formState.values, name, after) || {};
mState.formState.values = setIn(mState.formState.values, name, after) || {};
};

@@ -150,6 +144,6 @@ const renameField = (mState, from, to) => {

delete mState.fieldSubscribers[from];
const value = (0, getIn_1.default)(mState.formState.values, from);
const value = getIn(mState.formState.values, from);
mState.formState.values =
(0, setIn_1.default)(mState.formState.values, from, undefined) || {};
mState.formState.values = (0, setIn_1.default)(mState.formState.values, to, value);
setIn(mState.formState.values, from, undefined) || {};
mState.formState.values = setIn(mState.formState.values, to, value);
delete mState.lastFormState;

@@ -169,8 +163,8 @@ }

changeValue,
getIn: getIn_1.default,
getIn,
renameField,
resetFieldState: api.resetFieldState,
setIn: setIn_1.default,
setIn,
setStatus: api.setStatus,
shallowEqual: shallowEqual_1.default,
shallowEqual,
});

@@ -198,3 +192,3 @@ state.formState = mutableState.formState;

const errorsOrPromise = validate(Object.assign({}, state.formState.values)); // clone to avoid writing
if ((0, isPromise_1.default)(errorsOrPromise)) {
if (isPromise(errorsOrPromise)) {
promises.push(errorsOrPromise.then((errors) => setErrors(errors, true)));

@@ -221,6 +215,6 @@ }

validators.forEach((validator) => {
const errorOrPromise = validator((0, getIn_1.default)(state.formState.values, field.name), state.formState.values, validator.length === 0 || validator.length === 3
? (0, publishFieldState_1.default)(state.formState, state.fields[field.name])
const errorOrPromise = validator(getIn(state.formState.values, field.name), state.formState.values, validator.length === 0 || validator.length === 3
? publishFieldState(state.formState, state.fields[field.name])
: undefined);
if (errorOrPromise && (0, isPromise_1.default)(errorOrPromise)) {
if (errorOrPromise && isPromise(errorOrPromise)) {
field.validating = true;

@@ -307,4 +301,4 @@ const promise = errorOrPromise.then((err) => {

// field-level errors take precedent over record-level errors
const recordLevelError = (0, getIn_1.default)(recordLevelErrors, name);
const errorFromParent = (0, getIn_1.default)(merged, name);
const recordLevelError = getIn(recordLevelErrors, name);
const errorFromParent = getIn(merged, name);
const hasFieldLevelValidation = getValidators(safeFields[name]).length;

@@ -321,13 +315,13 @@ const fieldLevelError = fieldLevelErrors[name];

forEachError((name, error) => {
merged = (0, setIn_1.default)(merged, name, error) || {};
merged = setIn(merged, name, error) || {};
});
forEachError((name, error) => {
if (error && error[constants_1.ARRAY_ERROR]) {
const existing = (0, getIn_1.default)(merged, name);
if (error && error[ARRAY_ERROR]) {
const existing = getIn(merged, name);
const copy = [...existing];
copy[constants_1.ARRAY_ERROR] = error[constants_1.ARRAY_ERROR];
merged = (0, setIn_1.default)(merged, name, copy);
copy[ARRAY_ERROR] = error[ARRAY_ERROR];
merged = setIn(merged, name, copy);
}
});
if (!(0, shallowEqual_1.default)(formState.errors, merged)) {
if (!shallowEqual(formState.errors, merged)) {
formState.errors = merged;

@@ -338,3 +332,3 @@ }

}
formState.error = recordLevelErrors[constants_1.FORM_ERROR];
formState.error = recordLevelErrors[FORM_ERROR];
};

@@ -381,3 +375,3 @@ if (hasAsyncValidations) {

const field = safeFields[fieldName];
const fieldState = (0, publishFieldState_1.default)(formState, field);
const fieldState = publishFieldState(formState, field);
const { lastFieldState } = field;

@@ -387,3 +381,3 @@ field.lastFieldState = fieldState;

if (fieldSubscriber) {
notify(fieldSubscriber, fieldState, lastFieldState, filterFieldState_1.default, lastFieldState === undefined);
notify(fieldSubscriber, fieldState, lastFieldState, filterFieldState, lastFieldState === undefined);
}

@@ -411,3 +405,3 @@ };

const dirtyFields = safeFieldKeys.reduce((result, key) => {
const dirty = !safeFields[key].isEqual((0, getIn_1.default)(formState.values, key), (0, getIn_1.default)(formState.initialValues || {}, key));
const dirty = !safeFields[key].isEqual(getIn(formState.values, key), getIn(formState.initialValues || {}, key));
if (dirty) {

@@ -421,3 +415,3 @@ foundDirty = true;

const nonNullLastSubmittedValues = formState.lastSubmittedValues || {}; // || {} is for flow, but causes branch coverage complaint
if (!safeFields[key].isEqual((0, getIn_1.default)(formState.values, key), (0, getIn_1.default)(nonNullLastSubmittedValues, key))) {
if (!safeFields[key].isEqual(getIn(formState.values, key), getIn(nonNullLastSubmittedValues, key))) {
result[key] = true;

@@ -456,3 +450,3 @@ }

nextFormState.dirtyFields =
lastFormState && (0, shallowEqual_1.default)(lastFormState.dirtyFields, dirtyFields)
lastFormState && shallowEqual(lastFormState.dirtyFields, dirtyFields)
? lastFormState.dirtyFields

@@ -462,18 +456,18 @@ : dirtyFields;

lastFormState &&
(0, shallowEqual_1.default)(lastFormState.dirtyFieldsSinceLastSubmit, dirtyFieldsSinceLastSubmit)
shallowEqual(lastFormState.dirtyFieldsSinceLastSubmit, dirtyFieldsSinceLastSubmit)
? lastFormState.dirtyFieldsSinceLastSubmit
: dirtyFieldsSinceLastSubmit;
nextFormState.modified =
lastFormState && (0, shallowEqual_1.default)(lastFormState.modified, modified)
lastFormState && shallowEqual(lastFormState.modified, modified)
? lastFormState.modified
: modified;
nextFormState.touched =
lastFormState && (0, shallowEqual_1.default)(lastFormState.touched, touched)
lastFormState && shallowEqual(lastFormState.touched, touched)
? lastFormState.touched
: touched;
nextFormState.visited =
lastFormState && (0, shallowEqual_1.default)(lastFormState.visited, visited)
lastFormState && shallowEqual(lastFormState.visited, visited)
? lastFormState.visited
: visited;
return lastFormState && (0, shallowEqual_1.default)(lastFormState, nextFormState)
return lastFormState && shallowEqual(lastFormState, nextFormState)
? lastFormState

@@ -503,3 +497,3 @@ : nextFormState;

state.lastFormState = nextFormState;
notify(state.subscribers, nextFormState, lastFormState, filterFormState_1.default);
notify(state.subscribers, nextFormState, lastFormState, filterFormState);
}

@@ -556,3 +550,3 @@ }

const { fields, formState } = state;
if ((0, getIn_1.default)(formState.values, name) !== value) {
if (getIn(formState.values, name) !== value) {
changeValue(state, name, () => value);

@@ -616,5 +610,5 @@ const previous = fields[name];

const field = safeFields[key];
const pristine = field.isEqual((0, getIn_1.default)(formState.values, key), (0, getIn_1.default)(formState.initialValues || {}, key));
const pristine = field.isEqual(getIn(formState.values, key), getIn(formState.initialValues || {}, key));
if (!pristine) {
result[key] = (0, getIn_1.default)(formState.values, key);
result[key] = getIn(formState.values, key);
}

@@ -632,3 +626,3 @@ return result;

formState.values =
(0, setIn_1.default)(formState.values, key, savedDirtyValues[key]) || {};
setIn(formState.values, key, savedDirtyValues[key]) || {};
});

@@ -653,3 +647,3 @@ runValidation(undefined, () => {

// @ts-ignore
subscriber: (0, memoize_1.default)(subscriber),
subscriber: memoize(subscriber),
subscription,

@@ -698,13 +692,13 @@ notified: false,

}
const noValueInFormState = (0, getIn_1.default)(state.formState.values, name) === undefined;
const noValueInFormState = getIn(state.formState.values, name) === undefined;
if (fieldConfig.initialValue !== undefined &&
(noValueInFormState ||
// @ts-ignore
(0, getIn_1.default)(state.formState.values, name) ===
(0, getIn_1.default)(state.formState.initialValues, name))
getIn(state.formState.values, name) ===
getIn(state.formState.initialValues, name))
// only initialize if we don't yet have any value for this field
) {
state.formState.initialValues = (0, setIn_1.default)(state.formState.initialValues ||
state.formState.initialValues = setIn(state.formState.initialValues ||
{}, name, fieldConfig.initialValue);
state.formState.values = (0, setIn_1.default)(state.formState.values, name, fieldConfig.initialValue);
state.formState.values = setIn(state.formState.values, name, fieldConfig.initialValue);
runValidation(undefined, notifyListeners);

@@ -715,5 +709,5 @@ }

fieldConfig.initialValue === undefined &&
(0, getIn_1.default)(state.formState.initialValues, name) === undefined &&
getIn(state.formState.initialValues, name) === undefined &&
noValueInFormState) {
state.formState.values = (0, setIn_1.default)(state.formState.values, name, fieldConfig.defaultValue);
state.formState.values = setIn(state.formState.values, name, fieldConfig.defaultValue);
}

@@ -747,7 +741,7 @@ }

state.formState.errors =
(0, setIn_1.default)(state.formState.errors, name, undefined) || {};
setIn(state.formState.errors, name, undefined) || {};
}
if (destroyOnUnregister) {
state.formState.values =
(0, setIn_1.default)(state.formState.values, name, undefined, true) || {};
setIn(state.formState.values, name, undefined, true) || {};
}

@@ -924,3 +918,3 @@ }

formState.submitErrors = errors;
formState.submitError = errors[constants_1.FORM_ERROR];
formState.submitError = errors[FORM_ERROR];
markAllFieldsTouched();

@@ -951,3 +945,3 @@ }

if (!completeCalled) {
if (result && (0, isPromise_1.default)(result)) {
if (result && isPromise(result)) {
// onSubmit is async with a Promise

@@ -982,3 +976,3 @@ notifyFormListeners(); // let everyone know we are submitting

}
const memoized = (0, memoize_1.default)(subscriber);
const memoized = memoize(subscriber);
const { subscribers } = state;

@@ -993,3 +987,3 @@ const index = subscribers.index++;

const nextFormState = calculateNextFormState();
notifySubscriber(memoized, subscription, nextFormState, nextFormState, filterFormState_1.default, true);
notifySubscriber(memoized, subscription, nextFormState, nextFormState, filterFormState, true);
return () => {

@@ -1002,2 +996,2 @@ delete subscribers.entries[index];

}
exports.default = createForm;
export default createForm;

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

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**

@@ -35,2 +33,2 @@ * An _à la carte_ list of all the possible things you

];
exports.default = formSubscriptionItems;
export default formSubscriptionItems;

@@ -1,20 +0,6 @@

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.setIn = exports.getIn = exports.formSubscriptionItems = exports.createForm = exports.configOptions = exports.fieldSubscriptionItems = exports.FORM_ERROR = exports.ARRAY_ERROR = void 0;
var constants_1 = require("./constants");
Object.defineProperty(exports, "ARRAY_ERROR", { enumerable: true, get: function () { return constants_1.ARRAY_ERROR; } });
Object.defineProperty(exports, "FORM_ERROR", { enumerable: true, get: function () { return constants_1.FORM_ERROR; } });
var fieldSubscriptionItems_1 = require("./fieldSubscriptionItems");
Object.defineProperty(exports, "fieldSubscriptionItems", { enumerable: true, get: function () { return __importDefault(fieldSubscriptionItems_1).default; } });
var FinalForm_1 = require("./FinalForm");
Object.defineProperty(exports, "configOptions", { enumerable: true, get: function () { return FinalForm_1.configOptions; } });
Object.defineProperty(exports, "createForm", { enumerable: true, get: function () { return __importDefault(FinalForm_1).default; } });
var formSubscriptionItems_1 = require("./formSubscriptionItems");
Object.defineProperty(exports, "formSubscriptionItems", { enumerable: true, get: function () { return __importDefault(formSubscriptionItems_1).default; } });
var getIn_1 = require("./structure/getIn");
Object.defineProperty(exports, "getIn", { enumerable: true, get: function () { return __importDefault(getIn_1).default; } });
var setIn_1 = require("./structure/setIn");
Object.defineProperty(exports, "setIn", { enumerable: true, get: function () { return __importDefault(setIn_1).default; } });
export { ARRAY_ERROR, FORM_ERROR } from "./constants";
export { default as fieldSubscriptionItems } from "./fieldSubscriptionItems";
export { configOptions, default as createForm } from "./FinalForm";
export { default as formSubscriptionItems } from "./formSubscriptionItems";
export { default as getIn } from "./structure/getIn";
export { default as setIn } from "./structure/setIn";

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

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const isPromise = (obj) => !!obj &&

@@ -7,2 +5,2 @@ (typeof obj === "object" || typeof obj === "function") &&

typeof obj.then === "function";
exports.default = isPromise;
export default isPromise;

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

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const shallowEqual_1 = __importDefault(require("./shallowEqual"));
import shallowEqual from "./shallowEqual";
const memoize = (fn) => {

@@ -13,3 +8,3 @@ let lastArgs;

args.length !== lastArgs.length ||
args.some((arg, index) => !(0, shallowEqual_1.default)(lastArgs[index], arg))) {
args.some((arg, index) => !shallowEqual(lastArgs[index], arg))) {
lastArgs = args;

@@ -22,2 +17,2 @@ lastResult = fn(...args);

};
exports.default = memoize;
export default memoize;

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

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const constants_1 = require("./constants");
const getIn_1 = __importDefault(require("./structure/getIn"));
import { ARRAY_ERROR } from "./constants";
import getIn from "./structure/getIn";
/**

@@ -14,12 +9,12 @@ * Converts internal field state to published field state.

const { active, blur, change, data, focus, modified, modifiedSinceLastSubmit, name, touched, validating, visited, } = field;
const value = (0, getIn_1.default)(values, name);
let error = (0, getIn_1.default)(errors, name);
if (error && error[constants_1.ARRAY_ERROR]) {
error = error[constants_1.ARRAY_ERROR];
const value = getIn(values, name);
let error = getIn(errors, name);
if (error && error[ARRAY_ERROR]) {
error = error[ARRAY_ERROR];
}
const submitError = submitErrors && (0, getIn_1.default)(submitErrors, name);
const initial = initialValues && (0, getIn_1.default)(initialValues, name);
const submitError = submitErrors && getIn(submitErrors, name);
const initial = initialValues && getIn(initialValues, name);
const pristine = field.isEqual(initial, value);
const dirtySinceLastSubmit = !!(lastSubmittedValues &&
!field.isEqual((0, getIn_1.default)(lastSubmittedValues, name), value));
!field.isEqual(getIn(lastSubmittedValues, name), value));
const valid = !error && !submitError;

@@ -53,2 +48,2 @@ return {

}
exports.default = publishFieldState;
export default publishFieldState;

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

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const shallowEqual = (a, b) => {

@@ -24,2 +22,2 @@ if (a === b) {

};
exports.default = shallowEqual;
export default shallowEqual;

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

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const toPath_1 = __importDefault(require("./toPath"));
import toPath from "./toPath";
function getIn(state, complexKey) {
// Intentionally using iteration rather than recursion
const path = (0, toPath_1.default)(complexKey);
const path = toPath(complexKey);
let current = state;

@@ -25,2 +20,2 @@ for (let i = 0; i < path.length; i++) {

}
exports.default = getIn;
export default getIn;

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

"use strict";
var __rest = (this && this.__rest) || function (s, e) {

@@ -13,7 +12,3 @@ var t = {};

};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const toPath_1 = __importDefault(require("./toPath"));
import toPath from "./toPath";
const setInRecursor = (current, index, path, value, destroyArrays) => {

@@ -105,4 +100,4 @@ if (index >= path.length) {

// only deal with objects
return setInRecursor(state, 0, (0, toPath_1.default)(key), value, destroyArrays);
return setInRecursor(state, 0, toPath(key), value, destroyArrays);
}
exports.default = setIn;
export default setIn;

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

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const charCodeOfDot = ".".charCodeAt(0);

@@ -80,2 +78,2 @@ const reEscapeChar = /\\(\\)?/g;

};
exports.default = toPath;
export default toPath;

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

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const shallowEqual_1 = __importDefault(require("./shallowEqual"));
import shallowEqual from "./shallowEqual";
function subscriptionFilter(dest, src, previous, subscription, keys, shallowEqualKeys) {

@@ -14,3 +9,3 @@ let different = false;

(~shallowEqualKeys.indexOf(key)
? !(0, shallowEqual_1.default)(src[key], previous[key])
? !shallowEqual(src[key], previous[key])
: src[key] !== previous[key])) {

@@ -23,2 +18,2 @@ different = true;

}
exports.default = subscriptionFilter;
export default subscriptionFilter;

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

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
export {};
{
"name": "@deckstar/final-form",
"version": "1.0.3",
"version": "1.0.4",
"description": "🏁 Framework agnostic, high performance, subscription-based form state management",

@@ -35,3 +35,3 @@ "main": "dist/src",

},
"gitHead": "02a9986e9607c99cebbdb47325c7bfe91c142891"
"gitHead": "895075d667ee719aebe3992371956748e8c1059f"
}
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