flowai-js
Version:
The flow.ai Javascript SDK
858 lines (624 loc) • 23 kB
Markdown
# The flow.ai Javascript SDK
Access the [flow.ai](https://flow.ai) platform from your Node.js or javascript app. This library lets you build on the flow.ai Webclient API.
## What can you do?
* A simple way to connect with [flow.ai](https://flow.ai)
* Auto reconnect and event binding
* Send and receive messages
* Trigger actions and interact with AI bots
## Usage
### Installation
Run `npm install --save flowai-js`
### Simple Node.js example
```js
const {
LiveClient,
Message,
Originator
} = require("flowai-js")
// Create a new live client
const client = new LiveClient({
clientId: 'YOUR CLIENT ID HERE',
origin: 'https://my.site'
})
// Fired whenever the client connects
client.on(LiveClient.CONNECTED, () => {
console.log('--> Connected')
// Create the originator of the message
const originator = new Originator({
name: "Boss"
})
// Create a Message
const message = new Message({
// Thread Id limits the message just to John
threadId: 'john',
// The text to send
speech: "Behold, I'm pure awesomeness!",
// Person or system sending the message
originator
})
// Send
client.send(message)
})
// Start the connection
client.start()
```
### Advanced Node.js example
In this example you'll notice all events that are available
```js
const {
LiveClient,
Message,
Originator
} = require("flowai-js")
// Create a new live client
const client = new LiveClient({
// Unique clientId copy & paste from Flow.ai dashboard
clientId: 'YOUR CLIENT ID HERE',
// When limiting to whitelisted domains, specify this
origin: 'https://my.site'
})
client.on(LiveClient.CONNECTED, () => {
const originator = new Originator({
name: "Boss"
})
const message = new Message({
// Thread Id limits the message just to John
threadId: 'john',
// Use the traceId to identify message
// being marked as delivered
traceId: 1,
speech: "Behold, I'm pure awesomeness!",
originator
})
client.send(message)
})
client.on(LiveClient.MESSAGE_DELIVERED, message => {
// The message we have send has been delivered
// check the traceId to see what message has been
// delivered since it's an async method
})
client.on(LiveClient.REPLY_RECEIVED, message => {
// Called when a bot or human operator
// sends a message or reply
if(message.threadId === 'john') {
// Incoming message for John
} else {
// Incoming message for another user
}
})
client.on(LiveClient.ERROR, err => {
// This handler will be fired whenever an error
// occurs during the connection
console.error('Something bad happened', err)
})
client.on(LiveClient.DISCONNECTED, () => {
// The client has been disconnected
})
client.on(LiveClient.MESSAGE_SEND, message => {
// Called whenever the client sends a message
})
client.on(LiveClient.RECONNECTING, () => {
// Called when the client tries to reconnect
})
client.start()
```
### Simple browser example
Using the library within the browser is pretty much the same as the Node.js examples.
There is one notable difference, all classes live inside a `Flowai` object.
#### Include the script
```html
<script src="flowai-js.min.js"></script>
```
#### Usage
```js
var client = new Flowai.LiveClient('YOUR CLIENT ID HERE');
client.on(LiveClient.CONNECTED, function(){
var originator = new Flowai.Originator({ fullName: "John Doo" });
var message = new Flowai.Message({
threadId: 'john',
traceId: 1,
speech: "Behold, I'm pure awesomeness!",
originator
});
client.send(message);
})
client.start();
```
### Notes on using with webpack
The library can be easily used with webpack. You'll probably receive an error though involving `fs`.
Add the following to your webpack config file:
```
node: {
fs: 'empty'
},
```
## Identifying messages
The SDK is pretty flexible with regard to how messages are delivered and grouped. To do this we use two unique keys: sessionId and threadId.

### threadId
A threadId is a unique key representing a channel, room, or user. If you have a single connection running for multiple clients, all using the same threadId, they will all receive the same messages.

### sessionId
The sessionId is used to identify connections from different devices like browsers or Node.js servers. Each connection is partly identified on our end using this key.

# Full API Reference
## Classes
<dl>
<dt><a href="#EventAttachment">EventAttachment</a></dt>
<dd><p>Trigger events</p>
</dd>
<dt><a href="#Exception">Exception</a></dt>
<dd><p>Exception</p>
</dd>
<dt><a href="#FileAttachment">FileAttachment</a></dt>
<dd><p>Send a file as attachment</p>
</dd>
<dt><a href="#LiveClient">LiveClient</a></dt>
<dd><p>Live streaming websocket client extends EventEmitter</p>
</dd>
<dt><a href="#Message">Message</a></dt>
<dd><p>Message you send to Flow.ai</p>
</dd>
<dt><a href="#Metadata">Metadata</a></dt>
<dd><p>Additional Message data</p>
</dd>
<dt><a href="#OpeningAttachment">OpeningAttachment</a></dt>
<dd><p>Trigger opening events</p>
</dd>
<dt><a href="#Originator">Originator</a></dt>
<dd><p>Originator of a Message</p>
</dd>
<dt><a href="#Reply">Reply</a></dt>
<dd><p>Reply you receive from Flow.ai</p>
</dd>
</dl>
<a name="EventAttachment"></a>
## EventAttachment
Trigger events
<a name="new_EventAttachment_new"></a>
### new EventAttachment(name, [label])
| Param | Type | Description |
| --- | --- | --- |
| name | <code>string</code> | Name of the event to trigger |
| [label] | <code>string</code> | Optional human readable label for the triggered event |
Constructor
**Example**
```js
// Event without any label
const message = new Message({
attachment: new EventAttachment('BUY')
})
```
**Example**
```js
// Event with label to display user
const message = new Message({
attachment: new EventAttachment('BUY', 'Buy dress')
})
```
<a name="Exception"></a>
## Exception
**Properties**
| Name | Type | Description |
| --- | --- | --- |
| message | <code>string</code> | Human friendly message |
| type | <code>string</code> | Kind of error |
| innerException | [<code>Exception</code>](#Exception) | Inner exception |
| isFinal | <code>boolean</code> | Prevent further execution |
Exception
<a name="new_Exception_new"></a>
### new Exception(message, type, innerException, isFinal)
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| message | <code>string</code> | | message - Human friendly message |
| type | <code>string</code> | | Kind of error |
| innerException | [<code>Exception</code>](#Exception) | | Optional inner exception |
| isFinal | <code>boolean</code> | <code>false</code> | Indicates if this exception prevents further execution |
Constructor
<a name="FileAttachment"></a>
## FileAttachment
Send a file as attachment
<a name="new_FileAttachment_new"></a>
### new FileAttachment(data)
| Param | Type | Description |
| --- | --- | --- |
| data | <code>File</code> \| <code>ReadStream</code> | File or Blob in the browser, ReadStream in Nodejs |
Constructor
**Example**
```js
// Web example
var originator = new Originator({
name: 'Jane'
})
var file = fileInputElement.files[0]
const message = new Message({
attachment: new FileAttachment(file)
})
client.send(message)
```
**Example**
```js
// Nodejs example
import { createReadStream } from 'fs'
const originator = new Originator({
name: 'Jane'
})
// Load ReadStream from file on disk
const data = fs.createReadStream('/foo/bar.jpg')
const message = new Message({
attachment: new FileAttachment(data)
})
client.send(message)
```
<a name="LiveClient"></a>
## LiveClient
Live streaming websocket client extends EventEmitter
* [LiveClient](#LiveClient)
* [new LiveClient(opts)](#new_LiveClient_new)
* _instance_
* [.sessionId](#LiveClient+sessionId)
* [.threadId](#LiveClient+threadId)
* [.threadId](#LiveClient+threadId)
* [.isConnected](#LiveClient+isConnected)
* [.sessionId()](#LiveClient+sessionId)
* [.start(threadId, sessionId)](#LiveClient+start)
* [.stop()](#LiveClient+stop)
* [.destroy()](#LiveClient+destroy)
* [.send(message)](#LiveClient+send)
* [.merger(mergerKey, threadId, sessionId)](#LiveClient+merger)
* [.history(threadId)](#LiveClient+history)
* [.noticed(threadId, instantly)](#LiveClient+noticed)
* [.checkUnnoticed(threadId)](#LiveClient+checkUnnoticed)
* _static_
* [.ERROR](#LiveClient.ERROR)
* [.CONNECTED](#LiveClient.CONNECTED)
* [.RECONNECTING](#LiveClient.RECONNECTING)
* [.DISCONNECTED](#LiveClient.DISCONNECTED)
* [.REPLY_RECEIVED](#LiveClient.REPLY_RECEIVED)
* [.MESSAGE_SEND](#LiveClient.MESSAGE_SEND)
* [.MESSAGE_DELIVERED](#LiveClient.MESSAGE_DELIVERED)
* [.REQUESTING_HISTORY](#LiveClient.REQUESTING_HISTORY)
* [.NO_HISTORY](#LiveClient.NO_HISTORY)
* [.RECEIVED_HISTORY](#LiveClient.RECEIVED_HISTORY)
* [.CHECKED_UNNOTICED_MESSAGES](#LiveClient.CHECKED_UNNOTICED_MESSAGES)
<a name="new_LiveClient_new"></a>
### new LiveClient(opts)
| Param | Type | Description |
| --- | --- | --- |
| opts | <code>object</code> \| <code>string</code> | Configuration options or shorthand for just clientId |
| opts.clientId | <code>string</code> | Mandatory Client token |
| opts.storage | <code>string</code> | Optional, 'session' for using sessionStorage, 'local' for localStorage or `memory` for a simple memory store |
| opts.endpoint | <code>string</code> | Optional, only for testing purposes |
| opts.origin | <code>string</code> | When running on Nodejs you MUST set the origin |
Constructor
**Example**
```js
// Node.js
const client = new LiveClient({
clientId: 'MY CLIENT ID',
origin: 'https://my.website'
})
// Web
const client = new LiveClient({
clientId: 'MY CLIENT ID',
storage: 'session'
})
// Lambda function
const client = new LiveClient({
clientId: 'MY CLIENT ID',
storage: 'memory'
})
```
<a name="LiveClient+sessionId"></a>
### *liveClient*.sessionId
| Param | Type | Description |
| --- | --- | --- |
| value | <code>string</code> | Change the session ID |
Session Id of the connection
<a name="LiveClient+threadId"></a>
### *liveClient*.threadId
Default Thread Id to be used for any messages being send
**Returns**: <code>string</code> - Null if no connection is active
<a name="LiveClient+threadId"></a>
### *liveClient*.threadId
| Param | Type | Description |
| --- | --- | --- |
| value | <code>string</code> | Change the thread ID |
Session Id of the connection
<a name="LiveClient+isConnected"></a>
### *liveClient*.isConnected
Check if the connection is active
**Returns**: <code>boolean</code> - True if the connection is active
**Example**
```js
if(client.isConnected) {
// Do something awesome
}
```
<a name="LiveClient+sessionId"></a>
### *liveClient*.sessionId()
Session Id of the connection
**Returns**: <code>string</code> - Null if no connection is active
<a name="LiveClient+start"></a>
### *liveClient*.start(threadId, sessionId)
| Param | Type | Description |
| --- | --- | --- |
| threadId | <code>string</code> | Optional. When assigned, this is the default threadId for all messages that are send |
| sessionId | <code>string</code> | Optional. Must be unique for every connection |
Start the client
**Example**
```js
// Start, will generate thread and sessionId
client.start()
```
**Example**
```js
// Start with your own custom threadId
client.start('UNIQUE THREADID FOR USER')
```
<a name="LiveClient+stop"></a>
### *liveClient*.stop()
Use this method to temp disconnect a client
**Example**
```js
// Close the connection
client.stop()
```
<a name="LiveClient+destroy"></a>
### *liveClient*.destroy()
Close the connection and completely reset the client
**Example**
```js
// Close the connection and reset the client
client.destroy()
```
<a name="LiveClient+send"></a>
### *liveClient*.send(message)
| Param | Type | Description |
| --- | --- | --- |
| message | <code>object</code> | Message you want to send |
This method triggers a `LiveClient.MESSAGE_SEND` event
**Returns**: <code>object</code> - Message that was send
**Example**
```js
const originator = new Originator({
name: "Jane"
})
const message = new Message({
speech: "Hi!",
originator
})
client.send(message)
```
<a name="LiveClient+merger"></a>
### *liveClient*.merger(mergerKey, threadId, sessionId)
| Param | Type | Description |
| --- | --- | --- |
| mergerKey | <code>string</code> | Unique token representing merge Request |
| threadId | <code>string</code> | Optional. The threadId to merge |
| sessionId | <code>string</code> | Optional. The sessionId to assign to the thread |
Merge two threads from different channels.
This methods is not yet publicy supported since we don't have a way yet to provide a mergerKey.
<a name="LiveClient+history"></a>
### *liveClient*.history(threadId)
| Param | Type | Description |
| --- | --- | --- |
| threadId | <code>string</code> | Optional. Specify the threadId to retreive historic messages |
Request historic messages
**Example**
```js
// Load any messages if there is a threadId
// usefull when using with JS in the browser
client.history()
// Load messages using a custom threadId
client.history('MY CUSTOM THREAD ID')
```
<a name="LiveClient+noticed"></a>
### *liveClient*.noticed(threadId, instantly)
| Param | Type | Description |
| --- | --- | --- |
| threadId | <code>string</code> | Optional. Specify the thread that is noticed |
| instantly | <code>boolean</code> | Optional. Instantly send notice. Default is false |
Call to mark a thread as noticed.
The library automatically throttles the number of calls
**Example**
```js
// Call that the client has seen all messages for the auto clientId
client.noticed()
// Mark messages based on a custom threadId
client.noticed('MY CUSTOM THREAD ID')
```
<a name="LiveClient+checkUnnoticed"></a>
### *liveClient*.checkUnnoticed(threadId)
| Param | Type | Description |
| --- | --- | --- |
| threadId | <code>string</code> | Optional. Specify the thread to check unnoticed messags for |
Did we miss any messages?
<a name="LiveClient.ERROR"></a>
### *LiveClient*.ERROR
Event that triggers when an error is received from the flow.ai platform
<a name="LiveClient.CONNECTED"></a>
### *LiveClient*.CONNECTED
Event that triggers when client is connected with platform
<a name="LiveClient.RECONNECTING"></a>
### *LiveClient*.RECONNECTING
Event that triggers when client tries to reconnect
<a name="LiveClient.DISCONNECTED"></a>
### *LiveClient*.DISCONNECTED
Event that triggers when the client gets disconnected
<a name="LiveClient.REPLY_RECEIVED"></a>
### *LiveClient*.REPLY_RECEIVED
Event that triggers when a new message is received from the platform
<a name="LiveClient.MESSAGE_SEND"></a>
### *LiveClient*.MESSAGE_SEND
Event that triggers when the client is sending a message to the platform
<a name="LiveClient.MESSAGE_DELIVERED"></a>
### *LiveClient*.MESSAGE_DELIVERED
Event that triggers when the send message has been received by the platform
<a name="LiveClient.REQUESTING_HISTORY"></a>
### *LiveClient*.REQUESTING_HISTORY
Event that triggers when a request is made to load historic messages
<a name="LiveClient.NO_HISTORY"></a>
### *LiveClient*.NO_HISTORY
Event that triggers when a request is made to load historic messages
<a name="LiveClient.RECEIVED_HISTORY"></a>
### *LiveClient*.RECEIVED_HISTORY
Event that triggers when historic messages are received
<a name="LiveClient.CHECKED_UNNOTICED_MESSAGES"></a>
### *LiveClient*.CHECKED_UNNOTICED_MESSAGES
Event that triggers when there are unnoticed messages
<a name="Message"></a>
## Message
**Properties**
| Name | Type | Description |
| --- | --- | --- |
| speech | <code>string</code> | Text representing the Message |
| originator | [<code>Originator</code>](#Originator) | Originator |
| meta | [<code>Metadata</code>](#Metadata) | Meta data |
| attachment | [<code>Attachment</code>](#new_Attachment_new) | Optional attachment |
Message you send to Flow.ai
* [Message](#Message)
* [new Message(opts)](#new_Message_new)
* [.build(opts)](#Message.build)
<a name="new_Message_new"></a>
### new Message(opts)
| Param | Type | Description |
| --- | --- | --- |
| opts | <code>Object</code> | |
| opts.traceId | <code>number</code> | Optional unique integer you can match messages with |
| opts.threadId | <code>string</code> | Optional unique id specific to this chat |
| opts.speech | <code>string</code> | Text representing the Message |
| opts.originator | [<code>Originator</code>](#Originator) | Originator |
| opts.metadata | [<code>Metadata</code>](#Metadata) | Meta data |
| opts.attachment | [<code>Attachment</code>](#new_Attachment_new) | Attachment (optional) |
Constructor
<a name="Message.build"></a>
### *Message*.build(opts)
| Param | Type |
| --- | --- |
| opts | <code>object</code> |
| opts.threadId | <code>string</code> |
| opts.traceId | <code>string</code> |
| opts.speech | <code>string</code> |
| opts.originator | <code>object</code> |
| opts.metadata | <code>object</code> |
| opts.attachment | <code>object</code> |
Factory method
<a name="Metadata"></a>
## Metadata
**Properties**
| Name | Type | Description |
| --- | --- | --- |
| language | <code>string</code> | Language the message is ib |
| timezone | <code>number</code> | UTC time offset in hours |
| params | <code>Object</code> | Parameters to send with the message |
| domain | <code>Object</code> | Browser or server environment variables like origin |
Additional Message data
* [Metadata](#Metadata)
* [new Metadata(language, timezone, params)](#new_Metadata_new)
* _instance_
* ~~[.addContext()](#Metadata+addContext)
~~
* _static_
* [.build(metadata)](#Metadata.build)
<a name="new_Metadata_new"></a>
### new Metadata(language, timezone, params)
| Param | Type | Description |
| --- | --- | --- |
| language | <code>string</code> | Specify the language of the message |
| timezone | <code>number</code> | Specify the timezone of the message |
| params | <code>Object</code> | Additional data to be send |
Constructor
<a name="Metadata+addContext"></a>
### ~~*metadata*.addContext()~~
***Deprecated***
<a name="Metadata.build"></a>
### *Metadata*.build(metadata)
| Param | Type |
| --- | --- |
| metadata | <code>Object</code> |
Create a Metadata object from raw data
<a name="OpeningAttachment"></a>
## OpeningAttachment
Trigger opening events
<a name="new_OpeningAttachment_new"></a>
### new OpeningAttachment(name, [label])
| Param | Type | Description |
| --- | --- | --- |
| name | <code>string</code> | Name of the event to trigger |
| [label] | <code>string</code> | Optional human readable label for the triggered event |
Constructor
**Example**
```js
// Opening event without any label
const message = new Message({
attachment: new OpeningAttachment('BUY')
})
```
**Example**
```js
// Opening event with label to display user
const message = new Message({
attachment: new OpeningAttachment('BUY', 'Buy dress')
})
```
<a name="Originator"></a>
## Originator
**Properties**
| Name | Type | Description |
| --- | --- | --- |
| name | <code>string</code> | Name of a person or system originating the Message, default is Anonymous |
| role | <code>string</code> | The role of the person. You cannot set this, default is external |
| profile | <code>Object</code> | Contains profile info |
| profile.fullName | <code>string</code> | First and surname combined |
| profile.firstName | <code>string</code> | First name of the person |
| profile.lastName | <code>string</code> | Last name of the person |
| profile.email | <code>string</code> | E-mail address |
| profile.description | <code>string</code> | Description of this user |
| profile.picture | <code>string</code> | Profile picture (url) |
| profile.locale | <code>string</code> | ISO code describing language and country (en-US) |
| profile.timezone | <code>number</code> | Hours from GMT |
| profile.location | <code>string</code> | Location of the user |
| profile.gender | <code>string</code> | M for male, F for female or U for unknown / other |
| metadata | <code>object</code> | Optional object with custom metadata |
Originator of a Message
<a name="new_Originator_new"></a>
### new Originator(opts)
| Param | Type | Description |
| --- | --- | --- |
| opts | <code>Object</code> | |
| opts.name | <code>string</code> | Name of a person or system originating the Message, default is Anonymous |
| opts.role | <code>string</code> | The role of the person. You cannot set this, default is external |
| opts.profile | <code>Object</code> | Contains profile info |
| opts.profile.fullName | <code>string</code> | First and surname combined |
| opts.profile.firstName | <code>string</code> | First name of the person |
| opts.profile.lastName | <code>string</code> | Last name of the person |
| opts.profile.email | <code>string</code> | E-mail address |
| opts.profile.description | <code>string</code> | Description of this user |
| opts.profile.picture | <code>string</code> | Profile picture (url) |
| opts.profile.locale | <code>string</code> | ISO code describing language and country (en-US) |
| opts.profile.timezone | <code>number</code> | Hours from GMT |
| opts.profile.location | <code>string</code> | Location of the user |
| opts.profile.gender | <code>string</code> | M for male, F for female or U for unknown / other |
| opts.metadata | <code>object</code> | Optional object with custom metadata |
<a name="Reply"></a>
## Reply
**Properties**
| Name | Type | Description |
| --- | --- | --- |
| threadId | <code>string</code> | Unique id specific to this chat |
| originator | [<code>Originator</code>](#Originator) | Originator |
| messages | <code>Array.<ReplyMessage></code> | List of messages |
| messages[].fallback | <code>string</code> | Textual representation of any responses |
| messages[].replyTo | <code>string</code> | Optional replying to query |
| messages[].contexts | <code>array</code> | Optional List of context names |
| messages[].params | <code>array</code> | Optional key value pair of parameters |
| messages[].intents | <code>array</code> | Optional list of intent names determined |
| messages[].responses | <code>Array.<Response></code> | List of response templates |
| messages[].responses[].type | <code>string</code> | Template type |
| messages[].responses[].payload | <code>Object</code> | Template payload |
| messages[].responses[].delay | <code>Number</code> | Number of seconds the response is delayed |
Reply you receive from Flow.ai
<a name="new_Reply_new"></a>
### new Reply()
Constructor