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

ngrx-store-localstorage

Package Overview
Dependencies
Maintainers
1
Versions
49
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ngrx-store-localstorage - npm Package Compare versions

Comparing version 0.1.7 to 0.1.8

5

dist/index.d.ts
export declare const dateReviver: (key: string, value: any) => any;
export declare const rehydrateApplicationState: (keys: any[], storage: Storage) => any;
export declare const syncStateUpdate: (state: any, keys: any[], storage: Storage, removeOnUndefined: boolean) => void;
export declare const rehydrateApplicationState: (keys: any[], storage: Storage, storageKeySerializer: (key: string) => string) => any;
export declare const syncStateUpdate: (state: any, keys: any[], storage: Storage, storageKeySerializer: (key: string) => string, removeOnUndefined: boolean) => void;
export declare const localStorageSync: (config: LocalStorageConfig) => (reducer: any) => (state: any, action: any) => any;

@@ -11,2 +11,3 @@ export declare const localStorageSyncAndClean: (keys: any[], rehydrate?: boolean, removeOnUndefined?: boolean) => (reducer: any) => any;

removeOnUndefined?: boolean;
storageKeySerializer?: (key: string) => string;
}

17

dist/index.js

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

};
exports.rehydrateApplicationState = function (keys, storage) {
exports.rehydrateApplicationState = function (keys, storage, storageKeySerializer) {
return keys.reduce(function (acc, curr) {

@@ -63,3 +63,3 @@ var key = curr;

}
var stateSlice = storage.getItem(key);
var stateSlice = storage.getItem(storageKeySerializer(key));
if (stateSlice) {

@@ -77,3 +77,3 @@ // Use provided decrypt function

};
exports.syncStateUpdate = function (state, keys, storage, removeOnUndefined) {
exports.syncStateUpdate = function (state, keys, storage, storageKeySerializer, removeOnUndefined) {
keys.forEach(function (key) {

@@ -132,3 +132,3 @@ var stateSlice = state[key];

}
storage.setItem(key, typeof stateSlice === 'string' ? stateSlice : JSON.stringify(stateSlice, replacer, space));
storage.setItem(storageKeySerializer(key), typeof stateSlice === 'string' ? stateSlice : JSON.stringify(stateSlice, replacer, space));
}

@@ -141,3 +141,3 @@ catch (e) {

try {
storage.removeItem(key);
storage.removeItem(storageKeySerializer(key));
}

@@ -154,4 +154,7 @@ catch (e) {

}
if (config.storageKeySerializer === undefined) {
config.storageKeySerializer = function (key) { return key; };
}
var stateKeys = validateStateKeys(config.keys);
var rehydratedState = config.rehydrate ? exports.rehydrateApplicationState(stateKeys, config.storage) : undefined;
var rehydratedState = config.rehydrate ? exports.rehydrateApplicationState(stateKeys, config.storage, config.storageKeySerializer) : undefined;
return function (state, action) {

@@ -167,3 +170,3 @@ if (state === void 0) { state = rehydratedState; }

var nextState = reducer(state, action);
exports.syncStateUpdate(nextState, stateKeys, config.storage, config.removeOnUndefined);
exports.syncStateUpdate(nextState, stateKeys, config.storage, config.storageKeySerializer, config.removeOnUndefined);
return nextState;

@@ -170,0 +173,0 @@ };

{
"name": "ngrx-store-localstorage",
"version": "0.1.7",
"version": "0.1.8",
"description": "State and local storage syncing for @ngrx/store",

@@ -5,0 +5,0 @@ "main": "./dist/index.js",

@@ -13,3 +13,3 @@ # ngrx-store-localstorage

2. Invoke the `localStorageSync` function after `combineReducers`, this receives a `LocalStorageConfig` object and assigns the property `keys` the slices of state you would like to keep synced with local storage.
3. Optionally specify in the `LocalStorageConfig` whether to rehydrate this state from local storage as `initialState` on application bootstrap with the `rehydrateState` property.
3. Optionally specify in the `LocalStorageConfig` whether to rehydrate this state from local storage as `initialState` on application bootstrap with the `rehydrate` property.
4. Invoke composed function with application reducers as an argument to `StoreModule.provideStore`.

@@ -45,3 +45,3 @@ ```ts

### **LocalStorageConfig**
An interface that holds the needed configuration attributes to bootstrap `localStorageSync`. The following are properties which compose the `LocalStorageConfig`:
An interface defining the configuration attributes to bootstrap `localStorageSync`. The following are properties which compose `LocalStorageConfig`:
* `keys` (required) State keys to sync with local storage. The keys can be defined in two different formats:

@@ -70,5 +70,7 @@ * `string[]`: Array of strings representing the state (reducer) keys. Full state will be synced (e.g. `localStorageSync({keys: ['todos']})`).

* `rehydrateState` (optional) `boolean`: Pull initial state from local storage on startup, this will default to `false`.
* `rehydrate` (optional) `boolean`: Pull initial state from local storage on startup, this will default to `false`.
* `storage` (optional) `Storage`: Specify an object that conforms to the Storage interface to use, this will default to `localStorage`.
* `removeOnUndefined` (optional) `boolean`: Specify if the state is removed from the storage when the new value is undefined, this will default to `false`.
* `storageKeySerializer` (optional) `(key: string) => string`: Сustom serialize function for storage keys, used to avoid Storage conflicts.
Usage: `localStorageSync({keys: ['todos', 'visibilityFilter'], storageKeySerializer: (key) => 'cool_' + key, ... })`. In this example `Storage` will use keys `cool_todos` and `cool_visibilityFilter` keys to store `todos` and `visibilityFilter` slices of state). The key itself is used by default - `(key) => key`.

@@ -75,0 +77,0 @@ ---

declare var beforeEachProviders, it, describe, expect, inject;
require('es6-shim');
require('reflect-metadata');
import { syncStateUpdate, rehydrateApplicationState, dateReviver } from '../src/index';

@@ -8,3 +7,3 @@ import * as CryptoJS from 'crypto-js';

// Very simple classes to test serialization options. They cover string, number, date, and nested classes
// The top level class has static functions to help test reviver, replacer, serialize and deserialize
// The top level class has static functions to help test reviver, replacer, serialize and deserialize
class TypeB {

@@ -69,6 +68,6 @@ constructor(public afield: string) { }

public clear(): void { throw 'Not Implemented'; }
public getItem(key: string): any {
return this[key];
public getItem(key: string): string | null {
return this[key] ? this[key] : null;
}
key(index: number): string { throw 'Not Implemented'; }
key(index: number): string | null { throw 'Not Implemented'; }
removeItem(key: string): void { this[key] = undefined; }

@@ -82,2 +81,5 @@ setItem(key: string, data: string): void {

function mockStorageKeySerializer(key) { return key; }
describe('ngrxLocalStorage', () => {

@@ -113,7 +115,8 @@ let t1 = new TypeA(

// Since we're not specifiying anything for rehydration, the roundtrip
// loses type information...
// loses type information...
let s = new MockStorage();
let skr = mockStorageKeySerializer;
syncStateUpdate(initialState, ['state'], s, false);
syncStateUpdate(initialState, ['state'], s, skr, false);

@@ -123,3 +126,3 @@ let raw = s.getItem('state');

let finalState: any = rehydrateApplicationState(['state'], s);
let finalState: any = rehydrateApplicationState(['state'], s, skr);
expect(JSON.stringify(finalState)).toEqual(initialStateJson);

@@ -133,11 +136,12 @@

// Use the filter by field option to round-trip an object while
// filtering out the anumber and adate filed
// filtering out the anumber and adate filed
// Since we're not specifiying anything for rehydration, the roundtrip
// loses type information...
// loses type information...
let s = new MockStorage();
let skr = mockStorageKeySerializer;
let initialState = { state: t1 };
let keys = [{ state: ['astring', 'aclass'] }];
syncStateUpdate(initialState, keys, s, false);
syncStateUpdate(initialState, keys, s, skr, false);

@@ -147,3 +151,3 @@ let raw = s.getItem('state');

let finalState: any = rehydrateApplicationState(keys, s);
let finalState: any = rehydrateApplicationState(keys, s, skr);
expect(JSON.stringify(finalState)).toEqual(JSON.stringify({ state: t1Filtered }));

@@ -159,8 +163,9 @@

let s = new MockStorage();
let skr = mockStorageKeySerializer;
let initialState = { state: t1 };
let keys = [{ state: TypeA.reviver }];
syncStateUpdate(initialState, keys, s, false);
syncStateUpdate(initialState, keys, s, skr, false);
let finalState: any = rehydrateApplicationState(keys, s);
let finalState: any = rehydrateApplicationState(keys, s, skr);
expect(JSON.stringify(finalState)).toEqual(JSON.stringify(initialState));

@@ -175,8 +180,9 @@ expect(finalState.state instanceof TypeA).toBeTruthy();

let s = new MockStorage();
let skr = mockStorageKeySerializer;
let initialState = { state: t1 };
let keys = [{ state: { reviver: TypeA.reviver } }];
syncStateUpdate(initialState, keys, s, false);
syncStateUpdate(initialState, keys, s, skr, false);
let finalState: any = rehydrateApplicationState(keys, s);
let finalState: any = rehydrateApplicationState(keys, s, skr);
expect(JSON.stringify(finalState)).toEqual(JSON.stringify(initialState));

@@ -189,9 +195,10 @@ expect(finalState.state instanceof TypeA).toBeTruthy();

// Use the filter by field option to round-trip an object while
// filtering out the anumber and adate filed
// filtering out the anumber and adate filed
let s = new MockStorage();
let skr = mockStorageKeySerializer;
let initialState = { filtered: t1 };
let keys = [{ filtered: { filter: ['astring', 'aclass'] } }];
syncStateUpdate(initialState, keys, s, false);
syncStateUpdate(initialState, keys, s, skr, false);

@@ -201,3 +208,3 @@ let raw = s.getItem('filtered');

let finalState: any = rehydrateApplicationState(keys, s);
let finalState: any = rehydrateApplicationState(keys, s, skr);
expect(JSON.stringify(finalState)).toEqual(JSON.stringify({ filtered: t1Filtered }));

@@ -215,8 +222,9 @@

let s = new MockStorage();
let skr = mockStorageKeySerializer;
let initialState = { replacer: t1 };
let keys = [{ replacer: { reviver: TypeA.replacer } }];
syncStateUpdate(initialState, keys, s, false);
syncStateUpdate(initialState, keys, s, skr, false);
let finalState: any = rehydrateApplicationState(keys, s);
let finalState: any = rehydrateApplicationState(keys, s, skr);
expect(JSON.stringify(finalState)).toEqual(JSON.stringify({ replacer: t1Filtered }));

@@ -234,6 +242,7 @@

let s = new MockStorage();
let skr = mockStorageKeySerializer;
let initialState = { replacer: t1 };
let keys = [{ replacer: { replacer: ['astring', 'adate', 'anumber'], space: 2 } }];
syncStateUpdate(initialState, keys, s, false);
syncStateUpdate(initialState, keys, s, skr, false);

@@ -245,3 +254,3 @@ // We want to validate the space parameter, but don't want to trip up on OS specific newlines, so filter the newlines out and

let finalState: any = rehydrateApplicationState(keys, s);
let finalState: any = rehydrateApplicationState(keys, s, skr);

@@ -258,8 +267,9 @@ expect(JSON.stringify(finalState)).toEqual('{"replacer":{"astring":"Testing","adate":"1968-11-16T12:30:00.000Z","anumber":3.14159}}');

let s = new MockStorage();
let skr = mockStorageKeySerializer;
let initialState = { state: t1 };
let keys = [{ state: { serialize: TypeA.serialize, deserialize: TypeA.deserialize } }];
syncStateUpdate(initialState, keys, s, false);
syncStateUpdate(initialState, keys, s, skr, false);
let finalState: any = rehydrateApplicationState(keys, s);
let finalState: any = rehydrateApplicationState(keys, s, skr);
expect(JSON.stringify(finalState)).toEqual(initialStateJson);

@@ -273,3 +283,4 @@ expect(finalState.state instanceof TypeA).toBeTruthy();

let s = new MockStorage();
syncStateUpdate(initialState, ['state'], s, true);
let skr = mockStorageKeySerializer;
syncStateUpdate(initialState, ['state'], s, skr, true);

@@ -281,3 +292,3 @@ // do update

// ensure that it's erased
syncStateUpdate(undefinedState, ['state'], s, true);
syncStateUpdate(undefinedState, ['state'], s, skr, true);
raw = s.getItem('state');

@@ -290,3 +301,4 @@ expect(raw).toBeFalsy();

let s = new MockStorage();
syncStateUpdate(initialState, ['state'], s, false);
let skr = mockStorageKeySerializer;
syncStateUpdate(initialState, ['state'], s, skr, false);

@@ -298,3 +310,3 @@ // do update

// test update doesn't erase when it's undefined
syncStateUpdate(undefinedState, ['state'], s, false);
syncStateUpdate(undefinedState, ['state'], s, skr, false);
raw = s.getItem('state');

@@ -306,12 +318,13 @@ expect(raw).toEqual(t1Json);

let s = new MockStorage();
let skr = mockStorageKeySerializer;
let initialState = { state: t1 };
let keys = [{ state: { encrypt: TypeC.encrypt, decrypt: TypeC.decrypt } }];
syncStateUpdate(initialState, keys, s, false);
// Decript stored value and compare with the on-memory state
syncStateUpdate(initialState, keys, s, skr, false);
// Decript stored value and compare with the on-memory state
let raw = s.getItem('state');
expect(TypeC.decrypt(raw)).toEqual(JSON.stringify(initialState.state));
// Retrieve the stored state with the rehydrateApplicationState function and
let storedState = rehydrateApplicationState(keys, s);
// Retrieve the stored state with the rehydrateApplicationState function and
let storedState = rehydrateApplicationState(keys, s, skr);
expect(initialStateJson).toEqual(JSON.stringify(storedState));

@@ -322,2 +335,3 @@ });

let s = new MockStorage();
let skr = mockStorageKeySerializer;
let initialState = { state: t1 };

@@ -327,4 +341,4 @@ let keys;

syncStateUpdate(initialState, keys, s, false);
// Stored value must not be encripted due to decrypt function is not present, so must be equal to the on-memory state
syncStateUpdate(initialState, keys, s, skr, false);
// Stored value must not be encripted due to decrypt function is not present, so must be equal to the on-memory state
let raw = s.getItem('state');

@@ -335,6 +349,23 @@ expect(raw).toEqual(JSON.stringify(initialState.state));

keys = [{ state: { decrypt: TypeC.decrypt } }];
syncStateUpdate(initialState, keys, s, false);
syncStateUpdate(initialState, keys, s, skr, false);
raw = s.getItem('state');
expect(raw).toEqual(JSON.stringify(initialState.state));
});
it('storageKeySerializer', () => {
// This tests that storage key serializer are working.
let s = new MockStorage();
let skr = (key) => `this_key` + key;
console.log(skr('a'));
syncStateUpdate(initialState, ['state'], s, skr, false);
let raw = s.getItem('1232342');
expect(raw).toBeNull();
let finalState: any = rehydrateApplicationState(['state'], s, skr);
expect(JSON.stringify(finalState)).toEqual(initialStateJson);
expect(t1 instanceof TypeA).toBeTruthy();
expect(finalState.simple instanceof TypeA).toBeFalsy();
});
});

@@ -17,3 +17,3 @@ const INIT_ACTION = '@ngrx/store/init';

if (typeof key === 'object') {
attr = Object.keys(key)[0];
attr = Object.keys(key)[0];
}

@@ -31,3 +31,3 @@

export const rehydrateApplicationState = (keys: any[], storage: Storage) => {
export const rehydrateApplicationState = (keys: any[], storage: Storage, storageKeySerializer: (key: string) => string) => {
return keys.reduce((acc, curr) => {

@@ -40,32 +40,32 @@ let key = curr;

if (typeof key === 'object') {
key = Object.keys(key)[0];
// use the custom reviver function
if (typeof curr[key] === 'function') {
reviver = curr[key];
}
else {
// use custom reviver function if available
if (curr[key].reviver) {
reviver = curr[key].reviver;
}
// use custom serialize function if available
if (curr[key].deserialize) {
deserialize = curr[key].deserialize;
}
}
key = Object.keys(key)[0];
// use the custom reviver function
if (typeof curr[key] === 'function') {
reviver = curr[key];
}
else {
// use custom reviver function if available
if (curr[key].reviver) {
reviver = curr[key].reviver;
}
// use custom serialize function if available
if (curr[key].deserialize) {
deserialize = curr[key].deserialize;
}
}
// Ensure that encrypt and decrypt functions are both presents
if (curr[key].encrypt && curr[key].decrypt) {
if (typeof (curr[key].encrypt) === 'function' && typeof (curr[key].decrypt) === 'function') {
decrypt = curr[key].decrypt;
} else {
console.error(`Either encrypt or decrypt is not a function on '${curr[key]}' key object.`);
}
} else if (curr[key].encrypt || curr[key].decrypt) {
// Let know that one of the encryption functions is not provided
console.error(`Either encrypt or decrypt function is not present on '${curr[key]}' key object.`);
}
// Ensure that encrypt and decrypt functions are both presents
if (curr[key].encrypt && curr[key].decrypt) {
if (typeof (curr[key].encrypt) === 'function' && typeof (curr[key].decrypt) === 'function') {
decrypt = curr[key].decrypt;
} else {
console.error(`Either encrypt or decrypt is not a function on '${curr[key]}' key object.`);
}
} else if (curr[key].encrypt || curr[key].decrypt) {
// Let know that one of the encryption functions is not provided
console.error(`Either encrypt or decrypt function is not present on '${curr[key]}' key object.`);
}
}
let stateSlice = storage.getItem(key);
let stateSlice = storage.getItem(storageKeySerializer(key));
if (stateSlice) {

@@ -83,3 +83,3 @@ // Use provided decrypt function

export const syncStateUpdate = (state: any, keys: any[], storage: Storage, removeOnUndefined: boolean) => {
export const syncStateUpdate = (state: any, keys: any[], storage: Storage, storageKeySerializer: (key: string) => string, removeOnUndefined: boolean) => {
keys.forEach(key => {

@@ -139,3 +139,3 @@

if (typeof(stateSlice) !== 'undefined') {
if (typeof (stateSlice) !== 'undefined') {
try {

@@ -146,13 +146,13 @@ if (encrypt) {

}
storage.setItem(key, typeof stateSlice === 'string' ? stateSlice : JSON.stringify(stateSlice, replacer, space));
storage.setItem(storageKeySerializer(key), typeof stateSlice === 'string' ? stateSlice : JSON.stringify(stateSlice, replacer, space));
} catch (e) {
console.warn('Unable to save state to localStorage:', e);
}
} else if (typeof(stateSlice) === 'undefined' && removeOnUndefined) {
} else if (typeof (stateSlice) === 'undefined' && removeOnUndefined) {
try {
storage.removeItem(key);
storage.removeItem(storageKeySerializer(key));
} catch (e) {
console.warn(`Exception on removing/cleaning undefined '${key}' state`, e);
}
}
}
});

@@ -167,4 +167,8 @@ };

if (config.storageKeySerializer === undefined) {
config.storageKeySerializer = (key) => key;
}
const stateKeys = validateStateKeys(config.keys);
const rehydratedState = config.rehydrate ? rehydrateApplicationState(stateKeys, config.storage) : undefined;
const rehydratedState = config.rehydrate ? rehydrateApplicationState(stateKeys, config.storage, config.storageKeySerializer) : undefined;

@@ -180,3 +184,3 @@ return function (state = rehydratedState, action: any) {

const nextState = reducer(state, action);
syncStateUpdate(nextState, stateKeys, config.storage, config.removeOnUndefined);
syncStateUpdate(nextState, stateKeys, config.storage, config.storageKeySerializer, config.removeOnUndefined);
return nextState;

@@ -210,2 +214,3 @@ };

removeOnUndefined?: boolean;
storageKeySerializer?: (key: string) => string;
}

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