# JavaScript

## Getting Started

If still not registered, sign up and create an account at <https://koople.io>.

1\. Install and import package

```
npm i @pataflags/sdk-js
```

{% hint style="info" %}
Refer to the [NPM](https://www.npmjs.com/package/@pataflags/sdk-js) release page to identify the latest version.
{% endhint %}

2\. Initialize the SDK

```javascript
const user = { id: 'aUserId' }
const pfclient = PFClient.initialize('YOUR_API_KEY', user);
```

3\. Get your values

```javascript
pfclient.onReady(() => {
    const isEnabled = pfclient.isEnabled('myAwesomeFeature');
    if (isEnabled) {
        // Show the feature
    } else {
        // Hide the feature
    }
});
```

## Customize the SDK

You can set custom parameters to the client by creating a custom configuration object:

```javascript
const options = { timeout: 500 };
const pfclient = PFClient.initialize('YOUR_API_KEY', user, options);
```

| Parameter         | Description                                                                                                                                                                                         | Default   |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |
| `storage`         | Use `storage` to keep your [evaluation object](#evaluation-object) response in the cache. See [storage](#storage).                                                                                  | `none`    |
| `bootRun`         | Use `bootRun` to provide an initial [evaluation object](#evaluation-object) for the SDK. See [bootRun](#boot-run).                                                                                  | `network` |
| `fallback`        | Use `fallback` to provide a default evaluation object to the SDK. See [fallback](#fallback).                                                                                                        | `null`    |
| `timeout`         | The number of milliseconds the SDK waits for a response from the Koople servers before returning the [evaluation object](#evaluation-object) from the storage or fallback. See [timeout](#timeout). | `2000`    |
| `pollingInterval` | Interval in seconds with which the SDK makes requests to the server to update the settings. See [`pollingInterval`](#polling-interval).                                                             | `0`       |

### Storage

Use `storage` to keep your [evaluation object](#evaluation-object) response in the cache. When the request fails, the SDK try automatically to get the latest valid [evaluation object](#evaluation-object) from storage.

| Value        | Behaviour                                                                                 |
| ------------ | ----------------------------------------------------------------------------------------- |
| `none`       | Default value. The SDK will not store the [evaluation object](#evaluation-object).        |
| `session`    | The SDK will store the latest [evaluation object](#evaluation-object) between page loads. |
| `persistent` | The SDK will store the latest [evaluation object](#evaluation-object) between sessions.   |

```javascript
const pfclient = PFClient.initialize('YOUR_API_KEY', user, { 
    storage: 'persistent'
});
```

### Boot run

Use`bootRun` to provide an initial [evaluation object](#evaluation-object) for the SDK.&#x20;

| Value     | Behaviour                                                                                                                                                                                                                                                   |
| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `network` | The default value. The SDK will boot from the server response.                                                                                                                                                                                              |
| `storage` | The SDK will boot with the lastest stored response. Meanwhile, the request is loading in the background, and the [evaluation object](#evaluation-object) will be updated with the new server response. This mode allows loading the page without any delay. |

```javascript
const pfclient = PFClient.initialize('YOUR_API_KEY', user, {
    bootRun: 'storage' 
});
```

### Fallback

Use `fallback` to provide a default evaluation object for the SDK. When the request fails, and the storage is empty, the fallback will be returned. If the SDK has already initialized successfully, the fallback will not take effect.

```javascript
const pfclient = PFClient.initialize('YOUR_API_KEY', user, { 
    fallback: YOUR_EVALUATION_OBJECT
});
```

Alternatively, you can provide your fallback from `storage`. This means that in case of failure, the last valid server configuration will be returned.

### Timeout

The number of milliseconds the SDK waits for a response from the Koople servers before returning the [evaluation object](#evaluation-object) from the storage or fallback.

Timeout is more useful when combines with fallback. ~~The minimum value `timeout` is `50` milliseconds. If the value is less than `50` it will be ignored and automatically set to `50.` If you want less than 50 milliseconds, then see~~ [`bootRun`](#boot-run).

```javascript
const pfclient = PFClient.initialize('YOUR_API_KEY', user, {
    timeout: 50 
});
```

### Polling interval

You can configure your SDK to update the [evaluation object](#evaluation-object) every `pollingInterval` seconds automatically. You will receive the changes in the subscription to `onChanges`.

The minimum value is `1` second. If the value is less than `1` it will be ignored and automatically set to `1`.

```javascript
const pfclient = PFClient.initialize('YOUR_API_KEY', user, {
    pollingInterval: 60 
});
pfclient.onChanges(() => {
    // ...
});
```

## Events

### onReady

The SDK will raise the ready event when the SDK is initialized.

The initialization will depend on the SDK configuration. If you have configured the `bootRun` parameter as `storage`, the initialization will be immediate. Else it will take until the server responds.

You can subscribe to the ready event before or after the SDK initialization, in both cases, the callback will be executed.

```javascript
pfclient.onReady(() => { 
    const isEnabled = pfclient.releaseToggle('myAwesomeFeature');
    if (isEnabled) {
        // Show the feature
    } else {
        // Hide the feature
    }
});
```

### onIdentified

The SDK will raise the identified event when you call to [`identify`](#identify) method.&#x20;

```javascript
pfclient.onIdentified(() => { 
    // ...
});
```

### onChanges

While the ready and identified events are fired only once, changes will be fired every time the [evaluation object](#evaluation-object) is updated, including the times ready and identified events are fired.

Changes event can cause that, if the [evaluation object](#evaluation-object) changes, the page will be repainted or cause UI flickering.

In some cases, you can use changes event as a mechanism to ask the user if wants to apply changes or reload the page.

```javascript
pfclient.onChanges(() => { 
    if (confirm('There is a more updated version of the page.' +
        'Do you want to reload the page?')) {
        // apply changes or reload page
    }
});
```

## Methods

### releaseToggles

The `releaseToggles` method will return a map of release toggles with its settings.

```javascript
pfclient.releaseToggles();
```

### isEnabled

The `isEnabled` method will return a boolean indicating whether a release toggle is enabled or disabled.

| Name               | Type     |          |
| ------------------ | -------- | -------- |
| `releaseToggleKey` | `string` | required |

```javascript
pfclient.isEnabled('myAwesomeFeature');
```

### remoteConfigs

The `remoteConfigs` method will return a map of remote configs with its settings.

```javascript
pfclient.remoteConfigs();
```

### valueOf

The valueOf method will return a value for a remote config. You can pass an optional second parameter used as a fallback if there is no value.

| Name              | Type     |          |
| ----------------- | -------- | -------- |
| `remoteConfigKey` | `string` | required |
| `fallback`        | `string` | optional |

```javascript
pfclient.valueOf('theme', 'light');
```

### evaluation

The `evaluation` method will return an [evaluation object](#evaluation-object).

```javascript
pfclient.evaluation();
```

### &#x20;identify

The identify method provides a mechanism to update your [evaluation object](#evaluation-object) when the user has changed. It's the typical login scenario when a user goes from being anonymous to an authenticated user.

Changes will be listened from `onIdentified` and `onChanges`.

| Name   | Type                          |          |
| ------ | ----------------------------- | -------- |
| `user` | [`User object`](#user-object) | required |

```javascript
client.onIdentified(() => { /* UPDATED SETTINGS */ });
client.onChanges(() => { /* UPDATED SETTINGS */ });

client.identify({ id: 'logged-user' });
```

### refresh

The refresh method provides a mechanism to update your [evaluation object](#evaluation-object) manually. It is manual polling.

Changes can be listened from `onChanges`.

```javascript
client.onChanges(() => { /* UPDATED SETTINGS */ });

client.refresh();
```

## User object

// TODO ...

## Evaluation object

Each request to the server will have an evaluation object as a response. Also, [`fallback`](#fallback) parameter is an evaluation object. You can retrieve the current evaluation object using [`evaluation`](#evaluation) method.

### Anatomy

A valid evaluation object should contain these fields:

| Name           | Description                                                                                                                                                                                                                                             |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| releaseToggles | <p>Is a map of key values.</p><ul><li>The keys represent the key of your release toggle and should be a <code>string</code>.</li><li>The values indicate if your release toggle is enabled or disabled and should be a <code>boolean</code>. </li></ul> |
| remoteConfigs  | <p>Is a map of key values.</p><ul><li>The keys represent the key of your remote config and should be a <code>string</code>.</li><li>The values indicate a value of your remote config and should be a <code>boolean</code>. </li></ul>                  |

### Example

```javascript
const evaluationObject = {
    releaseToggles: {
        myAwesomeFeature: true,
        mySuperFeature: true
    },
    remoteConfigs: {
        theme: 'dark',
        permissions: 'ADMIN'
    }
};
```
