Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

ls-proxy

Package Overview
Dependencies
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ls-proxy - npm Package Compare versions

Comparing version 0.1.0 to 0.2.0

lib/types.d.ts

36

lib/index.d.ts

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

export { default as Validations } from './validations';
/** Configuration for storeObject */
export interface StoreObjectConfig<Object extends Record<string, any>> {
export interface StoreObjectConfig<O extends Record<string, any>> {
/**

@@ -9,12 +10,27 @@ * Whether or not to check localStorage when an object key is retrieved

/**
* Whether the stored object only contains/stores *some* of the keys on the serialized object.
* This is useful if you want an object to look at only some keys of a localStorage object
* without overwriting the other ones.
*
* It's important to note that passing this option effectively enables a key validation of sorts;
* any keys that were not passed are ignored and not passed to validate or modify (if these methods are defined)
* @default false
*/
partial?: boolean;
/**
* Validate an object before setting it in localStorage or reading it.
* Can confirm/deny if the object is valid, or modify the object before passing it on.
* See validation examples in the examples/ directory or in the documentation for `storeObject`
* Can confirm/deny if the object is valid, along with an optional error message if it is not
*
* @returns A boolean to confirm validity, false and an Error instance to deny validity,
* or return true alongside an object to pass on instead of the original
* @default () => true
*/
validate?: (value: any) => Object | boolean | readonly [boolean] | readonly [false, Error];
validate?(value: Readonly<any>): boolean | readonly [boolean] | readonly [false, Error];
/**
* Modify an object before setting it in localStorage or reading it.
* Called after validate. Any valiation should be done in validate and not here
*
* @returns A potentially modified version of the object originally passed
*/
modify?(value: O): O;
/**
* Function to parse object. Defaults to `JSON.parse`.

@@ -62,2 +78,4 @@ * Any validation should **NOT** be done here, but in the validate method

* // Validating that the expected keys exist and are the correct type
* import { storeObject, validateKeys } from 'ls-proxy'
*
* const myObj = storeObject(

@@ -71,2 +89,3 @@ * 'myObj',

* validate(value) {
* if (!validateKeys(value, ['someString', 'someNumber'])) return false
* if (typeof value.someString !== 'string') return false

@@ -82,4 +101,5 @@ * if (typeof value.someNumber !== 'number') return false

* ```typescript
* // Validation to automatically change a key based on another
* // Automatically change a key based on another
* import { storeObject } from 'ls-proxy'
*
* interface Person {

@@ -117,3 +137,3 @@ * name: string

*/
export declare function storeObject<Keys extends string = string, Object extends Record<Keys, any> = Record<Keys, any>>(lsKey: string, defaults: Readonly<Object>, configuration?: StoreObjectConfig<Object>): Object;
export declare function storeObject<O extends Record<string, any> = Record<string, any>>(lsKey: string, defaults: O, configuration?: StoreObjectConfig<O>): O;
/** Configuration for storeSeparate */

@@ -151,4 +171,4 @@ export interface StoreSeparateConfig {

*/
export declare function storeSeparate<Keys extends string = string, Object extends Record<Keys, string> = Record<Keys, string>>(defaults: Readonly<Object>, configuration?: StoreSeparateConfig): Object;
export declare function storeSeparate<O extends Record<string, string> = Record<string, string>>(defaults: O, configuration?: StoreSeparateConfig): O;
export as namespace LSProxy;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.storeSeparate = exports.storeObject = void 0;
const defaultStoreObjectConfig = ({ checkGets, validate, parse, stringify, }) => {
exports.storeSeparate = exports.storeObject = exports.Validations = void 0;
var validations_1 = require("./validations");
Object.defineProperty(exports, "Validations", { enumerable: true, get: function () { return validations_1.default; } });
const defaultStoreObjectConfig = ({ checkGets, partial, validate, modify, parse, stringify, }) => {
return {
checkGets: checkGets !== null && checkGets !== void 0 ? checkGets : true,
partial: partial !== null && partial !== void 0 ? partial : false,
validate: validate !== null && validate !== void 0 ? validate : (() => true),
modify: modify !== null && modify !== void 0 ? modify : (value => value),
parse: parse !== null && parse !== void 0 ? parse : JSON.parse,

@@ -42,2 +46,4 @@ stringify: stringify !== null && stringify !== void 0 ? stringify : JSON.stringify,

* // Validating that the expected keys exist and are the correct type
* import { storeObject, validateKeys } from 'ls-proxy'
*
* const myObj = storeObject(

@@ -51,2 +57,3 @@ * 'myObj',

* validate(value) {
* if (!validateKeys(value, ['someString', 'someNumber'])) return false
* if (typeof value.someString !== 'string') return false

@@ -62,4 +69,5 @@ * if (typeof value.someNumber !== 'number') return false

* ```typescript
* // Validation to automatically change a key based on another
* // Automatically change a key based on another
* import { storeObject } from 'ls-proxy'
*
* interface Person {

@@ -98,20 +106,48 @@ * name: string

function storeObject(lsKey, defaults, configuration = {}) {
const { checkGets, validate, parse, stringify } = defaultStoreObjectConfig(configuration);
const { checkGets, partial, validate, modify, parse, stringify } = defaultStoreObjectConfig(configuration);
/** Call validOrThrow with relevant parameters by default */
const vot = (value, action = 'set') => validOrThrow(validate, modify, value, action, lsKey);
const checkParse = (value) => {
const parsed = parse(value);
const valid = validOrThrow(validate(parsed), parsed, 'get', lsKey);
const valid = vot(parsed, 'get');
return valid;
};
const checkStringify = (value) => stringify(validOrThrow(validate(value), value, 'set', lsKey));
const checkStringify = (value) => stringify(vot(value));
const filterWanted = (obj, defaultIfUndefined = true) => {
let desiredObject = {};
Object.keys(defaults).forEach(
// Set to value found in localStorage if it exists, otherwise use provided default
key => {
var _a;
return (desiredObject[key] = defaultIfUndefined
? // Use default if defaultInDefined
(_a = obj[key]) !== null && _a !== void 0 ? _a : defaults[key]
: // Use given value even if undefined
obj[key]);
});
return desiredObject;
};
let object = Object.assign({}, defaults);
// Update localStorage value
// Update localStorage value or read existing values
if (!localStorage[lsKey]) {
localStorage[lsKey] = checkStringify(defaults);
}
else
else if (partial) {
const current = parse(localStorage[lsKey]);
object = filterWanted(current);
const validModified = vot(object);
localStorage[lsKey] = stringify(Object.assign(Object.assign({}, current), validModified));
}
else {
object = checkParse(localStorage[lsKey]);
}
return new Proxy(object, {
set(target, key, value, receiver) {
const setResult = Reflect.set(target, key, value, receiver);
localStorage[lsKey] = checkStringify(target);
if (partial) {
const validModified = vot(target);
localStorage[lsKey] = stringify(Object.assign(Object.assign({}, parse(localStorage[lsKey])), validModified));
}
else
localStorage[lsKey] = checkStringify(target);
return setResult;

@@ -121,4 +157,11 @@ },

var _a;
if (checkGets)
target[key] = (_a = checkParse(localStorage[lsKey])[key]) !== null && _a !== void 0 ? _a : defaults[key];
if (checkGets) {
if (partial) {
target[key] = vot(filterWanted(parse(localStorage[lsKey]), false), 'get')[key];
vot(target, 'get');
}
else {
target[key] = (_a = checkParse(localStorage[lsKey])[key]) !== null && _a !== void 0 ? _a : defaults[key];
}
}
return Reflect.get(target, key, receiver);

@@ -129,6 +172,17 @@ },

exports.storeObject = storeObject;
const validOrThrow = (valid, object, action, lsKey) => {
/**
* Validate and modify an object
*
* @param validate Return from the validate function
* @param modify Function to modify the object
* @param object The object to modify
* @param action Whether the object is being get or set
* @param lsKey The key in localStorage
* @returns The object if valid
*/
const validOrThrow = (validate, modify, object, action, lsKey) => {
const error = new TypeError(action === 'get'
? `Validation failed while parsing ${lsKey} from localStorage`
: `Validation failed while setting to ${lsKey} in localStorage`);
const valid = validate(object);
// Throw error on failure

@@ -149,7 +203,3 @@ if (typeof valid === 'boolean') {

}
else {
// Return is a new object
return valid;
}
return object;
return modify(object);
};

@@ -156,0 +206,0 @@ const defaultStoreSeparateConfig = ({ id, checkGets, }) => {

{
"$schema": "https://json.schemastore.org/package",
"name": "ls-proxy",
"version": "0.1.0",
"version": "0.2.0",
"description": "Wrapper around localStorage to easily store JSON objects",

@@ -20,2 +20,3 @@ "repository": "https://gitlab.com/MysteryBlokHed/ls-proxy",

"dev": "nodemon -w src -e ts --exec \"yarn build || exit 1\"",
"test": "jest",
"lint": "prettier \"**/*.{js,ts,json,md,yml}\"",

@@ -25,10 +26,16 @@ "doc": "typedoc",

},
"dependencies": {
"@types/greasemonkey": "^4.0.2"
"jest": {
"verbose": true,
"preset": "ts-jest",
"testEnvironment": "jsdom"
},
"devDependencies": {
"@types/greasemonkey": "^4.0.2",
"@types/jest": "^27.4.0",
"greasetools": "^0.2.0",
"jest": "^27.5.1",
"nodemon": "^2.0.13",
"prettier": "^2.4.1",
"terser-webpack-plugin": "^5.2.4",
"ts-jest": "^27.1.3",
"typedoc": "^0.22.11",

@@ -35,0 +42,0 @@ "typescript": "^4.4.4",

@@ -10,2 +10,36 @@ # ls-proxy [![Build Badge]](https://gitlab.com/MysteryBlokHed/ls-proxy/-/pipelines) [![NPM Badge]](https://www.npmjs.com/package/ls-proxy) [![License Badge]](#license)

## Why to use?
If you want to store client-side data for your website, the way to do it is with localStorage.
However, there is at least one siginificant downside: you can only store strings in localStorage keys.
The best way to get around this is by storing a stringified JSON object in a key,
but doing this manually or having to call a function that does it for you any time you change an object would be annoying.
This library solves these problems using JS proxies.
It also has great IDE support thanks to it being written in TypeScript.
You can also use it with vanilla JS with the Webpacked file (`ls-proxy.user.js`),
which is useful to test it in the browser or while writing UserScripts.
Here's all it takes to store a stringifed JSON object in localStorage and automatically change it:
```typescript
import { storeObject } from 'ls-proxy'
const someInfo = storeObject(
// The localStorage key to save data under
'someInfo',
// The object to store
{
aString: 'Hello, World!',
aNumber: 123,
aBoolean: true,
aList: [1, '2', 3],
},
)
someInfo.aNumber = 42 // Updates localStorage
console.log(someInfo.aList) // Reads from localStorage
```
## Documentation

@@ -16,3 +50,3 @@

Examples are located in [`examples/`](examples/).
Examples are located in [`examples`](https://gitlab.com/MysteryBlokHed/ls-proxy/-/tree/main/examples).

@@ -98,3 +132,3 @@ ## Use

### Building files
### Build

@@ -117,2 +151,12 @@ To build the project, run:

### Test
To test the project, run:
```sh
yarn test
```
This project uses Jest for tests.
## License

@@ -119,0 +163,0 @@

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