npm package: @nowina/nexu-client
Description: Client library for interacting with NexU on the browser
Author: Nowina Solutions
Latest version: 1.0.0

NexU Client
===========

Lightweight client library for interacting with [NexU](https://github.com/nowina-solutions/nexu) on the browser.

This library is intended to simplify all interactions with NexU. It provides following capabilities:
 - scanning of all provided ports to find the one on which NexU is deployed
 - comparing the provided version with the one of the installed NexU
 - handling all HTTP calls to NexU through the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)
 - catching and transforming all errors into a common interface to handle them easily
 - integrating with a callback channel to support WebViews on mobile devices 

This library does not require any additional dependency.

## Installation

This library can be installed by running:
```shell
npm install --save @nowina/nexu-client
```

It can be integrated as a ES6 module through an `import` statement, or also as a standard JS `<script>` tag on your page (`NexUClient` will be available on the `window` object).

## Usage

Once the `NexUClient` has been imported within your project, you can instantiate it with following parameters:
 - `bindingPorts`, the list of ports on which your NexU installations may be deployed
 - `latestVersion`, the version of the NexU in which you expect it has been installed

Once the client has been instantiated, you have to call the `init()` method first to initialize the client.
This method will scan the provided list of ports to find the one on which NexU is deployed, and if it is retrieve the version from it to compare it with the expected one.
The returned Promise will resolve successfully if and only if NexU is deployed on one of the provided ports and in the expected version.

### Example code

```js
import NexUClient from '@nowina/nexu-client';

// Defining the client parameters
const bindingPorts = [/* CUSTOM LIST OF PORTS */];
const latestVersion = '1.0'; /* CUSTOM NexU VERSION */

// Instantiating NexU Client
const nexUClient = new NexUClient(bindingPorts, latestVersion);

// Initializing the client
nexUClient.init().then(() => {
    console.log('NexU ready in version ', nexUClient.getRunningVersion());
    // From now on you can call all operations to perform on NexU
}).catch((error) => {
    console.error('NexU initialization failed', error);
});
```

## API Reference

Here is a description of all available methods on the `NexUClient`.

### Instantiating the client

The `NexUClient` constructor takes following arguments as input:

| Parameter       | Type                | Description                                                       |
| --------------- | ------------------- | ----------------------------------------------------------------- |
| `bindingPorts`  | `number[]`          | **Required** The list of possible ports on which NexU is deployed |
| `latestVersion` | `string`            | **Required** The expected version of the installed NexU           |
| `options`       | `NexUClientOptions` | Additional configuration options. See below for defaults.         |

The additional `NexUClientOptions` argument is optional and can be defined as follows:

| Attribute                     | Type       | Description                                                                  |
| ----------------------------- | ---------- | ---------------------------------------------------------------------------- |
| `defaultScheme`               | `string`   | The default scheme to use. By default: `http`.                               |
| `hostname`                    | `string`   | The hostname to query. By default: `localhost`.                              |
| `safariAdapterEnabled`        | `boolean`  | If the scheme should be switched to `https` for Safari. By default: `false`. |
| `safariBindingPorts`          | `number[]` | The alternative ports to use on Safari. Empty by default.                    |
| `webViewBridgeAdapterEnabled` | `boolean`  | If the WebView bridge should be used ii available. By default: `false`.      |
| `webViewBridgePrefix`         | `string`   | The prefix of the WebView bridge to use. By default: `undefined`.            |

Currently, when enabling the `safariAdapterEnabled`, the scheme will be switched to `https` when the browser is detected as Safari, and the `safariBindingPorts` will be used for the port scanning. This in order to support Safari browsers despite following known limitation: [Bug 171934](https://bugs.webkit.org/show_bug.cgi?id=171934).

### Initializing the client: `init()`

Before being able to use the `NexUClient`, it has to be initialized. This in order to find the port on which NexU is deployed and check that the expected version is installed.

The `init()` method takes following argument as input:

| Parameter         | Type                  | Description                                                            |
| ----------------- | --------------------- | ---------------------------------------------------------------------- |
| `progressTracker` | `NexUProgressTracker` | A callback that allows to be notified regarding the scanning progress. |

The `NexUProgressTracker` is optional and expects no return value, it should take as input following arguments:

| Parameter          | Type                | Description                                                |
| ------------------ | ------------------- | ---------------------------------------------------------- |
| `currentIndex`     | `number`            | The current index of the scanning progress. Starts at `1`. |
| `total`            | `number`            | The total number of ports to scan.                         |
| `NexUProgressType` | `BEFORE` or `AFTER` | One event is sent before checking a port, and one after.   |

The `AFTER` event is only sent if the port did not give any response. If a port gave a successful response, the Promise is resolved immediately, without emitting any additional event.

### NexU operations

Once the `NexUClient` has been successfully initialized, you can interact with NexU with following operations:
 - `getIdentityInfo()`, requests the identity information from NexU
 - `getCertificates()`, requests the list of certificates from NexU
 - `authenticate()`, requests a authentication operation from NexU
 - `sign()`, requests a signature operation from NexU

All these operations are taking as argument a `NexURequest` parameter and return a `NexUResponse` (as a Promise). Both of these objects are described in the NexU documentation.

### Helper methods

Following helper methods may provide you some information regarding the current status of the `NexUClient`:
 - `getRunningScheme()`, provides the current running scheme: `http` or `https` (or `web-view-bridge`)
 - `getRunningHostname()`, provides the current hostname
 - `getRunningPort()`, provides the current running port (if NexU has been detected)
 - `getRunningVersion()`, provides the current running version (independently if it is outdated or not)
 - `isInstalled()`, provides the information (once initialized) if NexU is installed
 - `isInitialized()`, provides the information if the client is initialized (`true` even if the installed version is outdated)
 - `isLatestVersion()`, checks that the version of the installed NexU matches the expected one

### Errors

All returned promises may be rejected with a common error `NexUError`, defined as follows:

| Attribute | Type       | Description                                                                 |
| --------- | ---------- | --------------------------------------------------------------------------- |
| `type`    | `string`   | The type of the error (described below).                                    |
| `message` | `string`   | The error message.                                                          |
| `details` | `string`   | The error details, as returned by NexU (not always provided).               |

Following error types are defined:
 - `NOT_INSTALLED`, returned on `init()` when no installation has been detected
 - `LOAD_FAILED`, returned on `init()` when no proper version could be extracted
 - `OLD_VERSION`, returned on `init()` when the version of NexU does not match the expected one
 - `NOT_INITIALIZED`, returned when trying to interact with NexU before the client has been initialized
 - `OPERATION_FAILED`, returned when the invoked operation failed

## Mobile integration

This client also supports an integration with a mobile app that complies with the NexU API.

If the `webViewBridgeAdapterEnabled` option key is passed as `true`, the `NexUClient` will try to communicate with the app through a callback defined with the `webViewBridgePrefix` option key.

The WebView should inject a function on the `window` object with the following name: `${options.webViewBridgePrefix}_request`. If such a method is defined, the `NexUClient` will invoke it instead of performing an HTTP call.

Symmetrically, the `NexUClient` defines a function on the `window` object with the following name: `${options.webViewBridgePrefix}_response`. This method must be invoked by the mobile app to _respond_ to the incoming call.

Each invocation is performed with an object defined as follows:

| Attribute       | Type       | Description                                                                 |
| --------------- | ---------- | --------------------------------------------------------------------------- |
| `action`        | `string`   | The type of action to perform: `identityInfo`, `sign`, etc.                 |
| `correlationId` | `string`   | An id that allows to correlate each response to the initial request.        |
| `payload`       | `string`   | The actual serialized JSON payload.                                         |

The _response_ must have the same structure and must provide the same `action` and `correlationId` than the _request_.