UNPKG

flowai-js

Version:

The flow.ai Javascript SDK

858 lines (624 loc) 23 kB
# 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](/media/unique-threadid.png) ### 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. ![Unique sessionIds](/media/unique-sessionid.png) ### 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. ![Unique sessions and threadids](/media/unique-sessionid-threadid.png) # 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.&lt;ReplyMessage&gt;</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.&lt;Response&gt;</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