Skip to content

Commit

Permalink
feat: add cerebral-storage module
Browse files Browse the repository at this point in the history
  • Loading branch information
fmal committed Oct 14, 2019
1 parent 86110d9 commit 1f70300
Show file tree
Hide file tree
Showing 17 changed files with 725 additions and 1 deletion.
140 changes: 140 additions & 0 deletions packages/@fmal/cerebral-storage/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# @fmal/cerebral-storage

[![npm](https://img.shields.io/npm/v/@fmal/cerebral-storage.svg?style=flat-square)](https://www.npmjs.com/package/@fmal/cerebral-storage)

Originally `@cerebral/storage`

## Install

`npm install @fmal/cerebral-storage`

## Description

This module exposes local storage or session storage as a provider,
where it by default parses and serializes to JSON.

## Instantiate

```js
import App from 'cerebral';
import StorageModule from '@fmal/cerebral-storage';

const storage = StorageModule({
// instance of storage, can be window.localStorage / localStorage,
// window.sessionStorage / sessionStorage, or asyncStorage on
// react native. Async storage API is automatically managed
target: localStorage,
// Serializes and parses to JSON by default
json: true,
// Synchronize state when it changes
sync: {
someStorageKey: 'some.state.path'
},
// Set prefix for storagekey "somePrefix.someStorageKey"
prefix: 'somePrefix'
});

const main = {
modules: { storage }
});

const app = App(main);
```

## error

### StorageProviderError

```js
import { StorageProviderError } from '@fmal/cerebral-storage'

// Error structure
{
name: 'StorageProviderError',
message: 'Some storage error'
stack: '...'
}
```

## get

Get data from storage.

_action_

```javascript
function someAction({ storage }) {
// sync
const value = storage.get('someKey');
// async
return storage.get('someKey').then(value => ({ value }));
}
```

_operator_

```javascript
import { getStorage } from '@fmal/cerebral-storage/factories';

export default [
// sync and async
getStorage('someKey'),
function someAction({ props }) {
props.value; // Whatever was on "someKey"
}
];
```

## remove

Remove data from storage.

_action_

```javascript
function someAction({ storage }) {
// sync
storage.remove('someKey');
// async
return storage.remove('someKey');
}
```

_operator_

```javascript
import { state } from 'cerebral';
import { removeStorage } from '@fmal/cerebral-storage/factories';

export default [
// sync and async
removeStorage(state`currentStorageKey`)
];
```

## set

Write data to storage.

_action_

```javascript
function someAction({ storage }) {
// sync
storage.set('someKey', { foo: 'bar' });
// async
return storage.set('someKey', { foo: 'bar' });
}
```

_operator_

```javascript
import { state, props } from 'cerebral';
import { setStorage } from '@fmal/cerebral-storage/factories';

export default [
// sync and async
setStorage(state`currentStorageKey`, props`someData`)
];
```
7 changes: 7 additions & 0 deletions packages/@fmal/cerebral-storage/factories/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "@fmal/cerebral-storage/factories",
"private": true,
"main": "../dist/cjs/factories/index.js",
"module": "../dist/esm/factories/index.js",
"types": "../dist/ts/factories/index.d.ts"
}
13 changes: 13 additions & 0 deletions packages/@fmal/cerebral-storage/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
'use strict'; // eslint-disable-line strict

// eslint-disable-next-line import/no-commonjs
const baseConfig = require('../../../jest.config.base');
// eslint-disable-next-line import/no-commonjs
const pkg = require('./package.json');

// eslint-disable-next-line import/no-commonjs
module.exports = {
...baseConfig,
displayName: pkg.name,
rootDir: __dirname
};
64 changes: 64 additions & 0 deletions packages/@fmal/cerebral-storage/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"name": "@fmal/cerebral-storage",
"version": "0.0.0",
"description": "Storage provider for Cerebral",
"license": "UNLICENSED",
"keywords": [
"cerebral",
"cerebraljs",
"storage",
"localStorage"
],
"author": "Christian Alfoni <christianalfoni@gmail.com>",
"contributors": [
"Filip Malinowski <filip@fmal.me>"
],
"bugs": {
"url": "https://github.com/fmal/monorepo/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/fmal/monorepo.git",
"directory": "packages/@fmal/cerebral-storage"
},
"publishConfig": {
"access": "public"
},
"types": "dist/ts",
"main": "dist/cjs/index.js",
"module": "dist/es/index.js",
"files": [
"dist",
"src",
"/factories",
"!**/__tests__"
],
"scripts": {
"test": "jest",
"test:coverage": "npm test -- --coverage",
"typecheck": "tsc",
"lint": "eslint . --cache --fix --ext \".js,.ts\" --ignore-path ../../.prettierignore",
"clean": "rimraf dist coverage ../../node_modules/@fmal/cerebral-storage",
"_babel": "babel src -x \".js,.ts\" --root-mode upward",
"prebuild": "npm run clean",
"postbuild": "cpy package.json ../../node_modules/@fmal/cerebral-storage",
"build:types": "tsc -p tsconfig.gentypes.json",
"build:cjs": "cross-env BABEL_ENV=cjs npm run _babel -- -d ../../node_modules/@fmal/cerebral-storage/dist/cjs",
"build:es": "cross-env BABEL_ENV=es npm run _babel -- -d ../../node_modules/@fmal/cerebral-storage/dist/es",
"build": "cross-env NODE_ENV=production run-p build:*",
"prepublishOnly": "rimraf dist && cpy '@fmal/cerebral-storage/dist/**/*' .. --cwd=../../node_modules --parents"
},
"peerDependencies": {
"cerebral": "^5.0.0"
},
"devDependencies": {
"@babel/cli": "7.6.4",
"cerebral": "5.2.0",
"cross-env": "6.0.3",
"eslint": "6.5.1",
"jest": "24.9.0",
"npm-run-all": "4.1.5",
"rimraf": "3.0.0",
"typescript": "3.6.4"
}
}
78 changes: 78 additions & 0 deletions packages/@fmal/cerebral-storage/src/StorageProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import StorageProviderError from './StorageProviderError';

export type StorageItem = string | null;

export type AsyncStorage = {
setItem: (key: string, item: string) => Promise<void>;
getItem: (key: string) => Promise<StorageItem>;
removeItem: (key: string) => Promise<void>;
};

export type StorageType = Storage | AsyncStorage;

export type Options = {
prefix?: string;
target?: StorageType;
json?: boolean;
sync?: { [key: string]: string };
};

export type StorageProviderInstance = {
get(key: string): Promise<StorageItem> | StorageItem;
set(key: string, value: string): Promise<void> | undefined;
remove(key: string): Promise<void> | undefined;
};

export default function StorageProvider({
target = localStorage,
json = true,
prefix
}: Options = {}): StorageProviderInstance {
const finalPrefix = prefix ? prefix + '.' : '';

return {
get(key) {
const value = target.getItem(finalPrefix + key);

function resolveValue(value: string | null) {
if (json && value) {
return JSON.parse(value);
}

return value;
}

if (value instanceof Promise) {
return value.then(resolveValue).catch(error => {
throw new StorageProviderError(error);
});
}

return resolveValue(value);
},
set(key, value) {
const maybePromise =
value === undefined
? target.removeItem(finalPrefix + key)
: target.setItem(
finalPrefix + key,
json ? JSON.stringify(value) : value
);

if (maybePromise instanceof Promise) {
return maybePromise.catch(error => {
throw new StorageProviderError(error);
});
}
},
remove(key) {
const maybePromise = target.removeItem(finalPrefix + key);

if (maybePromise instanceof Promise) {
return maybePromise.catch(error => {
throw new StorageProviderError(error);
});
}
}
};
}
15 changes: 15 additions & 0 deletions packages/@fmal/cerebral-storage/src/StorageProviderError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export default class StorageProviderError extends Error {
constructor(error: Error) {
super(error.message);
this.name = 'StorageProviderError';
this.message = error.message;
}

toJSON() {
return {
name: this.name,
message: this.message,
stack: this.stack
};
}
}
3 changes: 3 additions & 0 deletions packages/@fmal/cerebral-storage/src/__tests__/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "fmal/jest"
}
Loading

0 comments on commit 1f70300

Please sign in to comment.