npm package: @mirai/data-sources
Description: > A naive isomorphic storage manager
Latest version: 0.2.15

# 💾 @mirai/data-sources

> A naive isomorphic storage manager

### 📦 Setup

Add the package in your project:

```
yarn add @mirai/data-sources
```

## request

This package provides several methods for `request` data from the internet. Lets check them out:

### request()

This method will help you make promisified http requests, you can use these parameters with it:

- `endpoint` as the url we want to request
- `headers` as the configuration for the http headers, by default it is configured as an `application/json`.
- `hostname` as the http/https host we want use in combination with `endpoint` parameter.
- `method` as the http method, by default will be `GET`.
- `payload` if you want get the server response as payload.
- `timeout` if we want setup a limit time for our request.
- `props` as the extra properties you want use with the request. If it is a `POST/PUT` request they will be consolidate in a body parameter.

Being a promisified object, it has certain rules for decide when return a `resolve` or a `reject`:

- If the request responses with an `http code 400`, a `reject` will be returned containing the request's `payload`.
- If the request has not been resolved and it is not possible obtain the type of error, a `500: Something wrong happened. Try again` will be returned.

Default headers are configured to be removable by passing them as undefined in `headers` object.

```js
import { request } from '@mirai/data-sources';

const json = await request({ endpoint: 'https://mirai.com' }).catch((error) => console.error(error));
```

### requestFile()

In the case you need request a file you can use this method, which can receive these parameters:

- `endpoint` as the url we want to request
- `hostname` as the http/https host we want use in combination with `endpoint` parameter.
- `props` as the extra properties you want use with the request.

Because this method wraps the standard object `fetch` you can extend it with the parameters you could need.

```js
import { requestFile } from '@mirai/data-sources';

const file = await requestFile({
  hostname: 'https://mirai.com',
  endpoint: '/file?id=1980',
}).catch((error) => console.error(error));
```

### setGlobalHostname()

In the case you need use the same `hostname` in most of your _requests_ you can use this method for define the common value. Internally it will be saved in the _storage_ of the device.

```js
import { setGlobalHostname, request , requestFile } from '@mirai/data-sources';

setGlobalHostname('https://mirai.com');

request({ endpoint: '/order?id=2020' })l
>> https://mirai.com/order?id=2020
requestFile({ endpoint: '/file?id=1980' })l
>> https://mirai.com//file?id=1980
```

### setProxy()

In the case you need a most advance solution for your requests, you can use our proxy policy, which follows the rules of common `devServer` solutions. Here you have an example:

```js
import { setProxy } from '@mirai/data-sources';

setProxy({
  '/endpoint': {
    changeOrigin: false,
    target: 'https://api.dev.mirai/',
  },
  '/lookandlike': {
    changeOrigin: true,
    target: 'https://lookandlike.dev.mirai.com/',
  },
});
```

With this configuration and in combination with our method `request` we can get something like this:

```js
request({ endpoint: '/endpoint?order=1980' });
>> https://api.dev.mirai/endpoint?order=1980

request({ endpoint: '/lookandlike?order=1980' });
>> https://lookandlike.dev.mirai.com/?order=1980
```

### Storage

The `storage` class allows you to store data in an isomorphic way and in different ways. You can choose one of the following adapters:

- `MemoryAdapter` uses a memory storage it will be wipe once the app restart.
- `CookieAdapter` uses the cookie system of web browsers.
- `LocalAdapter` uses the LocalStorage system of web browsers.
- `SessionAdapter` uses the SessionStorage system of web browsers.
- `DomainAdapter` uses the window object on web browsers and the global object

Here you have a complete CRUD example using the `LocalAdapter`:

```js
import { Storage,  LocalAdapter } from '@mirai/data-sources';

storage = new Storage({ adapter: LocalAdapter });

const key = 'soyjavi';
const value = { email: 'hello@soyjavi.com' };

if (!storage.has(key)) storage.set(key, value);

storage.get(key);
>> { email: 'hello@soyjavi.com' }

storage.remove(key)

storage.get(key);
>> undefined
```

#### How to encrypt your data

In the event that you need to secure your data, you can do it in a very simple way. `storage` has a `secret` property which activates the encryption / decryption process of your data. Let's see an example:

```js
import { Storage, LocalAdapter } from '@mirai/data-sources';

storage = new Storage({ adapter: LocalAdapter, secret: '93c6K@hdiCs$#SY3' });
...
```

### Store

The `Store` is a React component wrapping a Context Api and over-vitamin it. Provides a _context provider_ named `StoreProvider` which stores the state of our store.Instantiating it is very simple, just wrap your application as follows:

```js

const App = () => (
  <StoreProvider>
    <YourApp>
  </StoreProvider>
);
```

After that, you can use the second piece of `Store`, the _hook_ `useStore`. Within this hook you will find 4 properties:

- `history` contains all the mutations already happened in your state value.
- `set` this method helps you to set new values to the state value.
- `remove` this method helps you to clean all the state value.
- `value` the current state value.

Keeping this in mind, obtaining these properties is as simple as:

```js
const Component = () => {
  const { history, set, remove, value } = useStore();

  return <></>;
};
```

Now let's take an example where one of our components needs to be in sync with a certain `Store` state property.

```js
const Component = () => {
  const {
    value: { session },
  } = useStore();

  useEffect(() => {
    console.log('Session changed', session);
  }, [session]);

  return <></>;
};
```

Now let's set a new value inside store:

```js
const Component = () => {
  const {
    set,
    value: { session },
  } = useStore();

  return (
    <>
      <button onClick={() => set({ click: true })} />
    </>
  );
};
```

### Metrics

The `Metrics`provides a _context provider_ named `MetricsProvider` which swhich provides an abstraction layer of the third-party mixpanel service. Instantiating it is very simple, just wrap your application as follows:

```js

const App = () => (
  <MetricsProvider token={MIXPANEL_TOKEN}>
    <YourApp>
  </MetricsProvider>
);
```

After that, you can use the second piece of `Metrics`, the _hook_ `useMetrics`. Within this hook you will find just one property:

- `track` this method helps you to track any kind of event, value, wathever.
- `trackRender` same as `track` but in a non-blocker way, great for first render in components.

Keeping this in mind, obtaining and use this property is as simple as:

```js
const Component = () => {
  const { track, trackRender } = useMetrics();

  useLayoutEffect(() => {
    trackRender('RENDER', { component: 'Component' });
  }, []);

  useEffect(() => {
    track('SESSION', { component: 'Component', session });
  }, [session]);

  return <></>;
};
```

dummy //TODO delete