1 | # Mainframe JavaScript SDK for bots
|
2 |
|
3 | - [Installation](#installation)
|
4 | - [Example](#example)
|
5 | - [Data types](#types)
|
6 | - [API](#api)
|
7 | - [`createConfig`](#createconfig)
|
8 | - [`createContext`](#createcontext)
|
9 | - [`createRouter`](#createrouter)
|
10 | - [`createServer`](#createserver)
|
11 | - [`log`](#log)
|
12 | - [`startServer`](#startserver)
|
13 | - [Usage](#usage)
|
14 | - [Basic usage](#basic-usage) - the easiest way to get started
|
15 | - [With custom route handlers](#adding-custom-route-handlers) - when you need custom routes
|
16 | - [Using an existing Express server](#using-an-existing-express-server) - giving you the flexibility to implement what you need
|
17 | - [License](#license)
|
18 |
|
19 | ## Installation
|
20 |
|
21 | ```sh
|
22 | npm install @mainframe/bot-sdk # npm
|
23 | yarn add @mainframe/bot-sdk # Yarn
|
24 | ```
|
25 |
|
26 | ## Example
|
27 |
|
28 | ```js
|
29 | const { startServer } = require('@mainframe/bot-sdk')
|
30 |
|
31 | startServer(
|
32 | {
|
33 | conversation_added({ conversation_id }, { sendMessage }) {
|
34 | sendMessage({ conversation_id, message: 'Hello world' })
|
35 | },
|
36 | },
|
37 | {
|
38 | mainframe_secret: '<my bot secret>',
|
39 | port: 3000,
|
40 | },
|
41 | )
|
42 | ```
|
43 |
|
44 | ## Types
|
45 |
|
46 | The SDK uses the following [Flow types](https://flow.org/en/docs/types/):
|
47 |
|
48 | ```js
|
49 | type PartialConfig = {
|
50 | +mainframe_secret: string,
|
51 | +mainframe_url: string,
|
52 | +port: number,
|
53 | }
|
54 |
|
55 | type Config = {|
|
56 | +mainframe_secret: string,
|
57 | +mainframe_url: string,
|
58 | +port: number,
|
59 | |}
|
60 |
|
61 | type ClientContext = {|
|
62 | +user: {
|
63 | +id: string,
|
64 | +username: string,
|
65 | +name: string,
|
66 | },
|
67 | +conversation?: {
|
68 | +id: string,
|
69 | +subject: ?string,
|
70 | +type: 'bot' | 'direct' | 'default' | 'space',
|
71 | },
|
72 | +organization?: {
|
73 | +id: string,
|
74 | +username: string,
|
75 | +name: string,
|
76 | },
|
77 | +subscription_token?: string,
|
78 | |}
|
79 |
|
80 | type PostPayload = {|
|
81 | +user_id: string,
|
82 | +data: Object,
|
83 | +context: ClientContext,
|
84 | |}
|
85 |
|
86 | type BotContext = {|
|
87 | +config: Config,
|
88 | +callMainframe: (endpoint: string, data?: Object) => Promise<void | Object>,
|
89 | +sendMessage: (payload: {
|
90 | conversation_id: string,
|
91 | message?: string,
|
92 | data?: Object,
|
93 | }) => Promise<void>,
|
94 | +createSubscription: (payload: {
|
95 | subscription_token: string,
|
96 | label?: string,
|
97 | }) => Promise<{ subscription_id: string }>,
|
98 | +editSubscription: (payload: {
|
99 | subscription_token: string,
|
100 | label?: string,
|
101 | }) => Promise<{ subscription_id: string }>,
|
102 | |}
|
103 |
|
104 | type BotResponse = {|
|
105 | success: boolean,
|
106 | message?: string,
|
107 | data?: Object,
|
108 | |}
|
109 |
|
110 | type Handlers = {|
|
111 | enable?: (payload: { user_id: string }) => void,
|
112 | disable?: (payload: { user_id: string }) => void,
|
113 | conversation_added?: (payload: {
|
114 | user_id: string,
|
115 | conversation_id: string,
|
116 | }) => void,
|
117 | conversation_removed?: (payload: {
|
118 | user_id: string,
|
119 | conversation_id: string,
|
120 | }) => void,
|
121 | edit_subscription?: (payload: {
|
122 | user_id: string,
|
123 | conversation_id: string,
|
124 | subscription_id: string,
|
125 | }) => void,
|
126 | delete_subscription?: (payload: { subscription_id: string }) => void,
|
127 | post?: (payload: PostRequest) => BotResponse | Promise<BotResponse>,
|
128 | |}
|
129 | ```
|
130 |
|
131 | ## API
|
132 |
|
133 | ### createConfig
|
134 |
|
135 | `createConfig (parameters?: PartialConfig): Config`
|
136 |
|
137 | Creates the configuration using the provided parameters, environment variables or defaults.
|
138 |
|
139 | ### createContext
|
140 |
|
141 | `createContext (config: Config): BotContext`
|
142 |
|
143 | Creates a bot context provided to the handlers, notably to allow to communicate with Mainframe.
|
144 |
|
145 | ### createRouter
|
146 |
|
147 | `createRouter (handlers: Handlers, context: BotContext): express$Router`
|
148 |
|
149 | Creates an [Express Router](https://expressjs.com/en/4x/api.html#router) implementing HTTP endpoints for the provided handlers.
|
150 |
|
151 | ### createServer
|
152 |
|
153 | `createServer (handlers: Handlers, config: Config): express$Application`
|
154 |
|
155 | Creates an [Express Application](https://expressjs.com/en/4x/api.html#app) implementing HTTP endpoints for the provided handlers.
|
156 |
|
157 | ### log
|
158 |
|
159 | `log (...args: Array<mixed>): void`
|
160 |
|
161 | Logs using [debug](https://github.com/visionmedia/debug) with the `mainframe-bot` namespace.
|
162 |
|
163 | ### startServer
|
164 |
|
165 | `startServer (handlers: Handlers, parameters?: PartialConfig): void`
|
166 |
|
167 | Creates an [Express Application](https://expressjs.com/en/4x/api.html#app) implementing HTTP endpoints for the provided handlers and start listening using the `port` provided in `parameters`, defaulting to `4000`.
|
168 |
|
169 | ## Usage
|
170 |
|
171 | ### Basic usage
|
172 |
|
173 | This SDK uses the [Express framework](https://expressjs.com/) to handle routing the provided handlers to the corresponding [HTTP endpoints used by the Mainframe server](http://developer.mainframe.com/#bot-api).
|
174 | All of these handlers are optional by default and you'll only need to implement them according to the needs of your bot.
|
175 |
|
176 | The simplest way to get started it to call `startServer(handlers)`, for example:
|
177 | ```js
|
178 | const { startServer } = require('@mainframe/bot-sdk')
|
179 |
|
180 | startServer({
|
181 | conversation_added(payload, context) {
|
182 | context.sendMessage({
|
183 | conversation_id: payload.conversation_id,
|
184 | message: 'Hello world',
|
185 | })
|
186 | },
|
187 | })
|
188 | ```
|
189 |
|
190 | All handlers will be called with two arguments: an Object containing the request payload, and the [`BotContext`](types) notably allowing to make requests to Mainframe.
|
191 |
|
192 | `startServer()` also supports providing a configuration Object as second argument, used to create the context. When not provided, the configuration will use the environment variables `MAINFRAME_SECRET`, `MAINFRAME_URL` and `PORT`.
|
193 | The configuration will by default use `https://api.mainframe.com/bots/v1` as Mainframe's API URL and listen on port `4000`.
|
194 | Your bot's `secret` **must be** provided, either directly as `mainframe_secret` in the configuration object, or in the `MAINFRAME_SECRET` environment variable.
|
195 |
|
196 | ### Adding custom route handlers
|
197 |
|
198 | For more advanced use cases, you may want to create the Express server without listening right-away, this is possible using the `createServer(handlers, config)` function, that will return an [`Application Object`](https://expressjs.com/en/4x/api.html#app).
|
199 | This function expects a `config` Object providing all the configuration values. If you want to automatically use the environment variables or default configuration values, you can use `createConfig(optionalConfig)` that will use the values provided in `optionalConfig`, or default to the environment variables or predefined values.
|
200 |
|
201 | Example:
|
202 |
|
203 | ```js
|
204 | const { createConfig, createServer, log } = require('@mainframe/bot-sdk')
|
205 |
|
206 | const config = createConfig({ mainframe_secret: '<your bot secret>' })
|
207 | const server = createServer(
|
208 | {
|
209 | enable(payload) {
|
210 | log('enabled by user %s', payload.user_id)
|
211 | },
|
212 | },
|
213 | config,
|
214 | )
|
215 |
|
216 | server.get('/', (req, res) => {
|
217 | res.send('Hello')
|
218 | })
|
219 |
|
220 | server.listen(3000)
|
221 | ```
|
222 |
|
223 | ### Using an existing Express server
|
224 |
|
225 | If you are already using Express and want to integrate the bot API with even more control, you can do so by using the `createRouter(handlers, context)`, that will return a [`Router instance`](https://expressjs.com/en/4x/api.html#router).
|
226 | This function requires a [`BotContext`](#types) to be provided as the second argument, that will be injected to the handlers when called. You can provide a custom implementation of the `context` if you have specific needs, or use `createContext(config)` to create it.
|
227 |
|
228 | Example:
|
229 |
|
230 | ```js
|
231 | const { createConfig, createContext, createRouter, log } = require('@mainframe/bot-sdk')
|
232 | const express = require('express')
|
233 |
|
234 | const app = express()
|
235 |
|
236 | const config = createConfig() // Will use MAINFRAME_SECRET from the environment
|
237 | const context = createContext(config)
|
238 |
|
239 | const api = createRouter(
|
240 | {
|
241 | enable(payload) {
|
242 | log('enabled by user %s', payload.user_id)
|
243 | },
|
244 | },
|
245 | context,
|
246 | )
|
247 |
|
248 | app.use('/api', api)
|
249 |
|
250 | app.all('*', (req, res) => {
|
251 | res.status(404).send('use /api')
|
252 | })
|
253 |
|
254 | app.listen(3000)
|
255 | ```
|
256 |
|
257 | ## License
|
258 |
|
259 | MIT
|
260 | See [LICENSE file](LICENSE)
|