<a name="ValenceTop"></a>
<img src="https://s3.amazonaws.com/cnx-valence-connect/Valence_logo_2018.png" alt="Valence Logo"/>
##### [CNX Corporation](https://www.cnxcorp.com)
Available for [Valence ^5.2](https://www.cnxcorp.com/valence/)

Use the valence-connect package when developing your Valence apps in Node.js. With valence-connect, your Node.js apps can participate in Valence role-based security, session management, logging and more. Writing Node.js apps for Valence using valence-connect also allows for maximum portability -- you can move your code between IBM i, Linux and Windows servers with little or no changes.

[Documentation](#ValenceConnect)&nbsp;&nbsp;&nbsp;&nbsp;[Examples](#Examples)&nbsp;&nbsp;&nbsp;&nbsp;[Tests](#Tests)&nbsp;&nbsp;&nbsp;&nbsp;[Versions](#Versions)

## Clean Install

```sh
mkdir acme
cd acme
npm init --yes
npm install valence-connect --save
```
After completing a clean installation start the new node server. You can find more information on starting the server below.
<p align="center">
  <img src="https://s3.amazonaws.com/cnx-valence-connect/install.gif" alt="Install Gif" width="520" />
</p>

### Starting the Node Server
#### Development
```sh
npm start
```
#### Debug
```sh
$ DEBUG=acme:* npm start
```
On Windows
```sh
> set DEBUG=acme:* & npm start
```
On Windows: PowerShell
```sh
PS > $env:DEBUG="acme:*" ; npm start
```
#### Production
When running in production mode the server will be clustered and compress files to improve performance.
```sh
npm run start:production
```
On Windows: PowerShell
```sh
PS > npm run start:production_ps
```
#### Clustering
By default the server will be clustered when running in production mode and create workers based on the available CPU's. You can override the number of workers produced by setting the WEB_CONCURRENCY environment variable. Set WEB_CONCURRENCY to "0" if you don't want clustering turned on.
```sh
$ WEB_CONCURRENCY=3 npm run start:production
```
On Windows
```sh
> set WEB_CONCURRENCY=3 & npm run start:production
```
On Windows: PowerShell
```sh
PS > $env:WEB_CONCURRENCY="3" ; npm run start:production_ps
```
<a name="Examples"></a>
### Examples

After performing a clean install and answering yes to "Automatically create application skeleton?" You will have one example application that displays a list of customers from our example table `DEMOCMAST`. Be sure the new server is running before attempting to launch the example application.

Try the example by creating a new Valence app in Portal Admin with an application type of "*Valence Application*". The `Path` will be the full URL consisting of this server and the route to the example.

http://YOUR_SERVER:PORT/apps/customers/index.html

Example :
```sh
http://acme.com:7152/apps/customers/index.html
```

### Structure after a clean install
```
acme
│
└───bin
│       www.js
│
└───node_modules
│       valence-connect
│       *other modules
│
└───public
│   │
│   └───apps
│   │   │
│   │   └───customers "example"
│   │
│   └───images
│   │       valence_logo.png
│   │
│   └───stylesheets
│           style.css
│
└───routes
│   │   index.js
│   │   valence.js
│   │
│   └───api
│           customers.js "example"
│
└───services
│       Readme.md
│       customers.js "example"
│
└───tests
│       Readme.md
│       services.js "example"
│
└───views
│       error.pug
│       index.pug
│       layout.pug
│
│   .gitignore
│   app.js
│   package.json
│   Readme.md
│   valence.json
```
### valence.json
```json
{
  "url": "http://acme.com:7052/service/connect?key=CD5678F68804D0123112TA0B8C93D1E58",
  "IBMi": true,
  "logging": false
}
```
<br>

| Property | Type | Description |
| --- | --- | --- |
| url | <code>string</code> | Valence Connect Web Service   URL "Located in Valence Portal Admin/Web Services" |
| IBMi | <code>boolean</code> | Running Valence for IBM i.   Pass false if connecting to Valence Universal on Windows, Linux or OS X.   Defaults to true if not passed. |
| logging | <code>boolean</code> | When `true`   will capture statistical information which can be viewed in Portal Admin-->Logs. |

[Valence Connect init](#ValenceConnect+init)
### routes/valence.js
```js
/**
 * Valence Router
 */
const express        = require('express'),
      cors           = require('cors'),
      corsWhiteList  = ['http://acme.com:7052'],
      corsOptions    = {
          origin : (origin, callback) => {
              if (typeof origin === 'undefined'
                  || corsWhiteList.indexOf(origin) !== -1) {
                  callback(null, true);
              } else {
                  callback(new Error('Not allowed by CORS'));
              }
          }
      },
      router         = express.Router(),
      valenceConnect = require('valence-connect'),
      customers      = require(global.__services + 'customers/customers');

// Initialize Valence Connect
//
valenceConnect.init();

// Allow Cross Origin
//
router.all('*', cors(corsOptions));

/**
 * Check if the request session is authenticated
 * @param {IncomingMessage} req http request
 * @param {ServerResponse} res http response
 * @param {callback} next continue
*/
let valenceCheck = (req, res, next) => {
    valenceConnect.isAuthenticated(req, res)
        .then(() => {
            next();
        });
};

// Always check before proceeding that the session is valid for all Valence requests
//
router.use(valenceCheck);

// Routes
//

// Example Valence Route "query customers"
//
router.all('/customers/queryAll', customers.queryAll.bind(customers));

module.exports = router;
```
<a name="Tests"></a>
### Tests
After performing a clean install and answering yes to "Automatically create application skeleton?" you will have an example test for the customer service using [node-tap](https://www.npmjs.com/package/tap).
<br>

To run the example services test issue the below command passing a valid session id. You can get a valid session id by logging into the Valence Portal and launching developer tools. Once developer tools is launched go to the console and run `Valence.util.Helper.getSid()`. That will return your current session id.

```sh
$ session=CURRENTSESSIONID npm test
```
On Windows
```sh
> set session=CURRENTSESSIONID & npm test
```
On Windows: PowerShell
```sh
PS > $env:session="CURRENTSESSIONID" ; npm test
```
## Classes

<dl>
<dt><a href="#ValenceConnect">ValenceConnect</a></dt>
<dd><p>Documentation: Security, session management, logging and utilities</p>
</dd>
</dl>

## Functions

<dl>
<dt><a href="#getSessionStorage">getSessionStorage(key)</a> ⇒ <code>Promise.&lt;*&gt;</code></dt>
<dd><p>get session storage</p>
</dd>
<dt><a href="#setSessionStorage">setSessionStorage(key, info)</a> ⇒ <code>Promise.&lt;void&gt;</code></dt>
<dd><p>set the session storage</p>
</dd>
</dl>

<a name="ValenceConnect"></a>

## ValenceConnect
Documentation: Security, session management, logging and utilities

**Kind**: global class  

* [ValenceConnect](#ValenceConnect)
    * [new ValenceConnect()](#new_ValenceConnect_new)
    * [.baseInit()](#ValenceConnect+baseInit) ⇒ <code>Promise.&lt;void&gt;</code>
    * [.init([options])](#ValenceConnect+init) ⇒ <code>InitPromise</code>
    * [.dbQuery(req, [res], statement)](#ValenceConnect+dbQuery) ⇒ <code>DbQueryPromise</code>
    * [.decodeUTF16(inStr)](#ValenceConnect+decodeUTF16) ⇒ <code>string</code>
    * [.getParams(req, [param])](#ValenceConnect+getParams) ⇒ <code>Object</code> \| <code>string</code> \| <code>number</code> \| <code>date</code> \| <code>array</code> \| <code>boolean</code> \| <code>\*</code>
    * [.getSessionInformation(sid)](#ValenceConnect+getSessionInformation) ⇒ <code>SessionInformationPromise</code>
    * [.getSettings(sid, [names], [cacheBuster])](#ValenceConnect+getSettings) ⇒ <code>SettingsPromise</code>
    * [.getUserInformation(sid, [cacheBuster])](#ValenceConnect+getUserInformation) ⇒ <code>UserInformationPromise</code>
    * [.isAuthenticated(req, res)](#ValenceConnect+isAuthenticated) ⇒ <code>IsAuthenticatedPromise</code>
    * [.isEmpty(value)](#ValenceConnect+isEmpty) ⇒ <code>boolean</code>

<a name="new_ValenceConnect_new"></a>

### new ValenceConnect()
Constructor

**Example**  
```js
const valenceConnect = require('valence-connect');
```
<a name="ValenceConnect+baseInit"></a>

### valenceConnect.baseInit() ⇒ <code>Promise.&lt;void&gt;</code>
init session storage

**Kind**: instance method of [<code>ValenceConnect</code>](#ValenceConnect)  
<a name="ValenceConnect+init"></a>

### valenceConnect.init([options]) ⇒ <code>InitPromise</code>
Initialize valence connect for communication with
  Valence for IBM i or Valence Universal. By default, valenceConnect.init
  will look for a valence.json configuration file at the root of the
  project for the required properties. You may override those
  properties by passing in an options object.

**Kind**: instance method of [<code>ValenceConnect</code>](#ValenceConnect)  

| Param | Type | Description |
| --- | --- | --- |
| [options] | <code>object</code> | Configuration Options |
| options.url | <code>string</code> | Valence Connect Web Service   URL "Located in Valence Portal Admin/Web Services" |
| options.IBMi | <code>boolean</code> | Running Valence for IBM i.   Pass false if connecting to Valence Universal on Windows, Linux or OS X.   Defaults to true if not passed. |
| options.logging | <code>boolean</code> | When `true`   will capture statistical information which can be viewed in Portal Admin-->Logs. |

**Example**  
```js
// Using valence.json
//
valenceConnect.init();
```
**Example**  
```js
// Passing options
//
valenceConnect.init({
    url     : 'http://acme.com:7052/service/connect?key=AZE678F68804D0123112TD0B8D93C1E38',
    IBMi    : true,
    logging : false,
});
```
<a name="ValenceConnect+dbQuery"></a>

### valenceConnect.dbQuery(req, [res], statement) ⇒ <code>DbQueryPromise</code>
Run an SQL `SELECT` statement and get the results.

**Kind**: instance method of [<code>ValenceConnect</code>](#ValenceConnect)  
**Returns**: <code>DbQueryPromise</code> - when fulfilled will contain an object with the results.  

| Param | Type | Description |
| --- | --- | --- |
| req | <code>IncomingMessage</code> \| <code>object</code> | http request or object containing parameters  to send off to process the query. Parameters: `rootName`, `maxResults`, `startFrom`. |
| [res] | <code>ServerResponse</code> | http response |
| statement | <code>string</code> | SQL statement to run. Only SELECT statements are allowed |

**Example**  
```js
router.all('/customers', (req, res) => {
    let statement     = 'select cusno as NUMBER, cname as NAME,' +
        ' ccity as CITY, cstate as STATE from DEMOCMAST',
        queryResponse = (response) => {
            res.json(response);
        },
        queryError    = (err) => {
            res.json(err);
        };

    valenceConnect.dbQuery(req, res, statement)
        .then(queryResponse)
        .catch(queryError);
});
```
<a name="ValenceConnect+decodeUTF16"></a>

### valenceConnect.decodeUTF16(inStr) ⇒ <code>string</code>
Decode UTF16 hex-encoded strings

**Kind**: instance method of [<code>ValenceConnect</code>](#ValenceConnect)  
**Returns**: <code>string</code> - decoded string  

| Param | Type | Description |
| --- | --- | --- |
| inStr | <code>string</code> | string to decode |

**Example**  
```js
let decodedValue = valenceConnect.decodeUTF16(encodedValue);
```
<a name="ValenceConnect+getParams"></a>

### valenceConnect.getParams(req, [param]) ⇒ <code>Object</code> \| <code>string</code> \| <code>number</code> \| <code>date</code> \| <code>array</code> \| <code>boolean</code> \| <code>\*</code>
Get a single request parameter or all request parameters from both the body and query string.

**Kind**: instance method of [<code>ValenceConnect</code>](#ValenceConnect)  

| Param | Type | Description |
| --- | --- | --- |
| req | <code>IncomingMessage</code> | http request |
| [param] | <code>string</code> | parameter id |

**Example**  
```js
// All Parameters
// The variable params would be an object containing all the query string
//   and body parameters combined.
//
router.all('/processInventory', (req, res) => {
    let params = valenceConnect.getParams(req);

    if (params.inventoryId) {
      // process inventory
      //
    }
});
```
**Example**  
```js
// Single Parameter
// The inventoryId variable would be a number since the front-end passed a numeric
//   value.
//
router.all('/processInventory', (req, res) => {
    let inventoryId = valenceConnect.getParams(req, 'inventoryId');

    if (inventoryId) {
      // process inventory
      //
    }
});
```
<a name="ValenceConnect+getSessionInformation"></a>

### valenceConnect.getSessionInformation(sid) ⇒ <code>SessionInformationPromise</code>
Get the session information from the passed in session id

**Kind**: instance method of [<code>ValenceConnect</code>](#ValenceConnect)  
**Returns**: <code>SessionInformationPromise</code> - when fulfilled will contain the session
  information. Environment Id, Mode, Session Variables, etc.  

| Param | Type | Description |
| --- | --- | --- |
| sid | <code>string</code> | session id |

**Example**  
```js
router.all('/transferOrder', (req, res) => {
    let sessionId       = valenceConnect.getParams(req, 'sid'),
        sessionError    = (err) => {
            res.json(err);
        },
        sessionResponse = (info) => {
            if (info.envId === 1) {
                // process default
                //
            } else {
                //process other environment
                //
            }
        };

    valenceConnect.getSessionInformation(sessionId)
        .then(sessionResponse)
        .catch(sessionError);
});
```
<a name="ValenceConnect+getSettings"></a>

### valenceConnect.getSettings(sid, [names], [cacheBuster]) ⇒ <code>SettingsPromise</code>
Get Valence Settings

**Kind**: instance method of [<code>ValenceConnect</code>](#ValenceConnect)  
**Returns**: <code>SettingsPromise</code> - when fulfilled will be a name/value array of Valence settings  

| Param | Type | Description |
| --- | --- | --- |
| sid | <code>string</code> | session id |
| [names] | <code>array</code> | optional array of setting names to get |
| [cacheBuster] | <code>boolean</code> | If `true` force pull of latest settings   from Valence. |

**Example**  
```js
router.all('/settings', (req, res) => {
    let sessionId        = valenceConnect.getParams(req, 'sid'),
        settingsError    = (err) => {
            res.json(err);
        },
        settingsResponse = (settings) => {
            res.json({
                settings : settings
            });
        };

    valenceConnect.getSettings(sessionId)
        .then(settingsResponse)
        .catch(settingsError);
});
```
<a name="ValenceConnect+getUserInformation"></a>

### valenceConnect.getUserInformation(sid, [cacheBuster]) ⇒ <code>UserInformationPromise</code>
Get the current user information from the passed in session id

**Kind**: instance method of [<code>ValenceConnect</code>](#ValenceConnect)  
**Returns**: <code>UserInformationPromise</code> - when fulfilled will contain the user
  information. Id, First, Last Name, Email, etc.  

| Param | Type | Description |
| --- | --- | --- |
| sid | <code>string</code> | session id |
| [cacheBuster] | <code>boolean</code> | If `true` force pull of latest users   information from Valence. |

**Example**  
```js
router.all('/userInformation', (req, res) => {
    let sessionId    = valenceConnect.getParams(req, 'sid'),
        userError    = (err) => {
            res.json(err);
        },
        userResponse = (info) => {
            res.json({
                user : info
            });
        };

    valenceConnect.getUserInformation(sessionId)
        .then(userResponse)
        .catch(userError);
});
```
<a name="ValenceConnect+isAuthenticated"></a>

### valenceConnect.isAuthenticated(req, res) ⇒ <code>IsAuthenticatedPromise</code>
Is the session authenticated based off the current session id on
  the request object.

**Kind**: instance method of [<code>ValenceConnect</code>](#ValenceConnect)  

| Param | Type | Description |
| --- | --- | --- |
| req | <code>IncomingMessage</code> | http request |
| res | <code>ServerResponse</code> | http response |

**Example**  
```js
valenceConnect.isAuthenticated(req, res)
    .then(() => {
        // authenticated so continue...
        //
        next();
    });
```
<a name="ValenceConnect+isEmpty"></a>

### valenceConnect.isEmpty(value) ⇒ <code>boolean</code>
Check to see if a value is empty

**Kind**: instance method of [<code>ValenceConnect</code>](#ValenceConnect)  

| Param | Type | Description |
| --- | --- | --- |
| value | <code>\*</code> \| <code>string</code> | value to test if empty |

**Example**  
```js
if (valenceConnect.isEmpty(value)) {
    //value is empty
    //
} else {
    //value is not empty
    //
}
```
<a name="getSessionStorage"></a>

## getSessionStorage(key) ⇒ <code>Promise.&lt;\*&gt;</code>
get session storage

**Kind**: global function  

| Param | Type |
| --- | --- |
| key | <code>string</code> | 

<a name="setSessionStorage"></a>

## setSessionStorage(key, info) ⇒ <code>Promise.&lt;void&gt;</code>
set the session storage

**Kind**: global function  

| Param | Type |
| --- | --- |
| key | <code>string</code> | 
| info | <code>string</code> | 

[Back To Top](#ValenceTop)

## Community
[Forums](http://forums.cnxcorp.com/node/12178)

<a name="Versions"></a>
## Versions

### Prior to 1.1.1
- beta

### 1.1.1 - 2018-05-18
- General Availability

### 1.1.2 - 2018-09-12
- When calling getParams with a specific parameter value return null if not found instead of an empty object.

### 1.1.3 - 2018-12-27
- Update the required package `url-parse` minimum version to 1.4.3.

### 1.1.4 - 2020-12-21
- Update package dependencies to the latest ver
- Update core to handle dependency changes
