botkit-middleware-watson
Advanced tools
Comparing version 1.8.4 to 2.0.0
@@ -5,3 +5,2 @@ { | ||
"packages": [ | ||
"examples/multi-bot/package.json", | ||
"examples/simple-bot/package.json", | ||
@@ -8,0 +7,0 @@ "package.json" |
{ | ||
"name": "botkit-middleware-watson", | ||
"version": "1.8.4", | ||
"version": "2.0.0", | ||
"description": "A middleware for using Watson Assistant in a Botkit-powered bot.", | ||
"main": "lib/middleware/index.js", | ||
"types": "lib/middleware/index.d.ts", | ||
"main": "lib/index.js", | ||
"types": "lib/index.d.ts", | ||
"scripts": { | ||
"start": "node lib/middleware/index.js", | ||
"test": "mocha test", | ||
"lint": "eslint ." | ||
"build": "node ./node_modules/typescript/bin/tsc", | ||
"pretest": "npm run build", | ||
"test": "jest test --coverage --forceExit", | ||
"lint": "npm run build && eslint '*/**/*.ts' --quiet --fix", | ||
"version": "npm run build && git add -A lib", | ||
"precommit": "lint-staged" | ||
}, | ||
@@ -27,17 +30,45 @@ "repository": { | ||
"devDependencies": { | ||
"assert": "^1.4.1", | ||
"botkit": "^0.7.2", | ||
"@types/jest": "^24.0.12", | ||
"@types/nock": "^10.0.1", | ||
"@types/sinon": "^7.0.11", | ||
"@typescript-eslint/eslint-plugin": "^1.7.0", | ||
"@typescript-eslint/parser": "^1.7.0", | ||
"botbuilder-adapter-web": "^1.0.1", | ||
"botkit": "^4.0.1", | ||
"clone": "^2.1.2", | ||
"eslint": "^5.9.0", | ||
"mocha": "^6.0.0", | ||
"nock": "^10.0.2", | ||
"sinon": "^7.1.1" | ||
"codecov": "^3.3.0", | ||
"eslint": "^5.16.0", | ||
"eslint-config-prettier": "^4.2.0", | ||
"eslint-plugin-prettier": "^3.0.1", | ||
"husky": "^2.2.0", | ||
"jest": "^24.8.0", | ||
"lint-staged": "^8.1.5", | ||
"nock": "^10.0.6", | ||
"prettier": "^1.17.0", | ||
"sinon": "^7.3.2", | ||
"ts-jest": "^24.0.2", | ||
"typescript": "^3.4.5" | ||
}, | ||
"prettier": { | ||
"printWidth": 80, | ||
"singleQuote": true, | ||
"trailingComma": "all" | ||
}, | ||
"dependencies": { | ||
"@types/bluebird": "^3.5.24", | ||
"bluebird": "^3.5.3", | ||
"debug": "^4.1.0", | ||
"debug": "^4.1.1", | ||
"deepmerge": "^3.2.0", | ||
"watson-developer-cloud": "^3.13.0" | ||
"ibm-watson": "^4.1.0" | ||
}, | ||
"lint-staged": { | ||
"src/**/*.ts": [ | ||
"npm run build", | ||
"npm run lint", | ||
"git add" | ||
] | ||
}, | ||
"husky": { | ||
"hooks": { | ||
"pre-commit": "lint-staged" | ||
} | ||
} | ||
} |
311
README.md
@@ -5,2 +5,27 @@ # Use IBM Watson's Assistant service to chat with your Botkit-powered Bot! [](https://travis-ci.org/watson-developer-cloud/botkit-middleware) [](https://greenkeeper.io/) | ||
<details> | ||
<summary>Table of Contents</summary> | ||
* [Middleware Overview](#middleware-overview) | ||
* [Function Overview](#function-overview) | ||
* [Installation](#installation) | ||
* [Prerequisites](#prerequisites) | ||
+ [Acquire channel credentials](#acquire-channel-credentials) | ||
+ [Bot setup](#bot-setup) | ||
* [Features](#features) | ||
+ [Message filtering](#message-filtering) | ||
- [Using interpret function instead of registering middleware](#using-interpret-function-instead-of-registering-middleware) | ||
- [Using middleware wrapper](#using-middleware-wrapper) | ||
+ [Minimum Confidence](#minimum-confidence) | ||
- [Use it manually in your self-defined controller.hears() function(s)](#use-it-manually-in-your-self-defined-controllerhears-functions) | ||
- [Use the middleware's hear() function](#use-the-middlewares-hear-function) | ||
+ [Implementing app actions](#implementing-app-actions) | ||
+ [Using sendToWatson to update context](#using-sendtowatson-to-update-context) | ||
* [Implementing event handlers](#implementing-event-handlers) | ||
+ [Intent matching](#intent-matching) | ||
- [`before` and `after`](#before-and-after) | ||
- [Dynamic workspace](#dynamic-workspace) | ||
</details> | ||
## Middleware Overview | ||
@@ -29,3 +54,3 @@ | ||
```sh | ||
$ npm install botkit-middleware-watson --save | ||
$ npm install botkit-middleware-watson | ||
``` | ||
@@ -35,5 +60,5 @@ | ||
1. Sign up for an [IBM Cloud account](https://console.bluemix.net/registration/). | ||
1. Sign up for an [IBM Cloud account](https://cloud.ibm.com/registration/). | ||
1. Create an instance of the Watson Assistant service and get your credentials: | ||
- Go to the [Watson Assistant](https://console.bluemix.net/catalog/services/conversation) page in the IBM Cloud Catalog. | ||
- Go to the [Watson Assistant](https://cloud.ibm.com/catalog/services/conversation) page in the IBM Cloud Catalog. | ||
- Log in to your IBM Cloud account. | ||
@@ -44,13 +69,8 @@ - Click **Create**. | ||
1. Create a workspace using the Watson Assistant service and copy the `workspace_id`. If you don't know how to create a workspace follow the [Getting Started tutorial](https://console.bluemix.net/docs/services/conversation/getting-started.html). | ||
1. Create a workspace using the Watson Assistant service and copy the `workspace_id`. If you don't know how to create a workspace follow the [Getting Started tutorial](https://cloud.ibm.com/docs/services/conversation/getting-started.html). | ||
### Acquire channel credentials | ||
This document shows code snippets for using a Slack bot with the middleware. (If you want examples for the other channels, see the [examples/multi-bot](/examples/multi-bot) folder. | ||
The multi-bot example app shows how to connect to Slack, Facebook, and Twilio IPM bots running on a single Express server.) | ||
This document shows code snippets for using a Slack bot with the middleware. You need a _Slack token_ for your Slack bot to talk to Watson Assistant. If you have an existing Slack bot, then copy the Slack token from your Slack settings page. | ||
You need a _Slack token_ for your Slack bot to talk to Watson Assistant. | ||
If you have an existing Slack bot, then copy the Slack token from your Slack settings page. | ||
Otherwise, follow [Botkit's instructions](https://botkit.ai/docs/provisioning/slack-events-api.html) to create your Slack bot from scratch. When your bot is ready, you are provided with a Slack token. | ||
@@ -64,12 +84,19 @@ | ||
```js | ||
const slackController = Botkit.slackbot({ clientSigningSecret: YOUR_SLACK_SIGNING_SECRET }); | ||
``` | ||
import { WatsonMiddleware } from 'botkit-middleware-watson'; | ||
import Botkit = require('botkit'); | ||
const { SlackAdapter } = require('botbuilder-adapter-slack'); | ||
Spawn a Slack bot using the controller: | ||
```js | ||
const slackBot = slackController.spawn({ | ||
token: YOUR_SLACK_TOKEN | ||
const adapter = new SlackAdapter({ | ||
clientSigningSecret: process.env.SLACK_SECRET, | ||
botToken: process.env.SLACK_TOKEN | ||
}); | ||
const controller = new Botkit({ | ||
adapter, | ||
// ...other options | ||
}); | ||
``` | ||
Create the middleware object which you'll use to connect to the Watson Assistant service. | ||
@@ -80,3 +107,3 @@ | ||
```js | ||
const watsonMiddleware = require('botkit-middleware-watson')({ | ||
const watsonMiddleware = new WatsonMiddleware({ | ||
username: YOUR_ASSISTANT_USERNAME, | ||
@@ -94,3 +121,3 @@ password: YOUR_ASSISTANT_PASSWORD, | ||
```js | ||
const watsonMiddleware = require('botkit-middleware-watson')({ | ||
const watsonMiddleware = new WatsonMiddleware({ | ||
iam_apikey: YOUR_API_KEY, | ||
@@ -106,4 +133,3 @@ url: YOUR_ASSISTANT_URL, | ||
```js | ||
slackController.middleware.receive.use(watsonMiddleware.receive); | ||
slackBot.startRTM(); | ||
controller.middleware.receive.use(watsonMiddleware.receive.bind(watsonMiddleware)); | ||
``` | ||
@@ -113,7 +139,7 @@ | ||
```js | ||
slackController.hears(['.*'], ['direct_message', 'direct_mention', 'mention'], function(bot, message) { | ||
controller.hears(['.*'], ['direct_message', 'direct_mention', 'mention'], async function(bot, message) { | ||
if (message.watsonError) { | ||
bot.reply(message, "I'm sorry, but for technical reasons I can't respond to your message"); | ||
await bot.reply(message, "I'm sorry, but for technical reasons I can't respond to your message"); | ||
} else { | ||
bot.reply(message, message.watsonData.output.text.join('\n')); | ||
await bot.reply(message, message.watsonData.output.text.join('\n')); | ||
} | ||
@@ -137,10 +163,9 @@ }); | ||
```js | ||
slackController.hears(['.*'], ['direct_message'], function(bot, message) { | ||
middleware.interpret(bot, message, function() { | ||
if (message.watsonError) { | ||
bot.reply(message, "I'm sorry, but for technical reasons I can't respond to your message"); | ||
} else { | ||
bot.reply(message, message.watsonData.output.text.join('\n')); | ||
} | ||
}); | ||
slackController.hears(['.*'], ['direct_message'], async (bot, message) => { | ||
await middleware.interpret(bot, message) | ||
if (message.watsonError) { | ||
bot.reply(message, "I'm sorry, but for technical reasons I can't respond to your message"); | ||
} else { | ||
bot.reply(message, message.watsonData.output.text.join('\n')); | ||
} | ||
}); | ||
@@ -152,3 +177,3 @@ ``` | ||
```js | ||
const receiveMiddleware = function (bot, message, next) { | ||
const receiveMiddleware = (bot, message, next) => { | ||
if (message.type === 'direct_message') { | ||
@@ -172,12 +197,12 @@ watsonMiddleware.receive(bot, message, next); | ||
```js | ||
controller.hears(['.*'], ['direct_message', 'direct_mention', 'mention', 'message_received'], function(bot, message) { | ||
controller.hears(['.*'], ['direct_message', 'direct_mention', 'mention', 'message_received'], async (bot, message) => { | ||
if (message.watsonError) { | ||
bot.reply(message, "Sorry, there are technical problems."); // deal with watson error | ||
await bot.reply(message, "Sorry, there are technical problems."); // deal with watson error | ||
} else { | ||
if (message.watsonData.intents.length == 0) { | ||
bot.reply(message, "Sorry, I could not understand the message."); // was any intent recognized? | ||
await bot.reply(message, "Sorry, I could not understand the message."); // was any intent recognized? | ||
} else if (message.watsonData.intents[0].confidence < watsonMiddleware.minimum_confidence) { | ||
bot.reply(message, "Sorry, I am not sure what you have said."); // is the confidence high enough? | ||
await bot.reply(message, "Sorry, I am not sure what you have said."); // is the confidence high enough? | ||
} else { | ||
bot.reply(message, message.watsonData.output.text.join('\n')); // reply with Watson response | ||
await bot.reply(message, message.watsonData.output.text.join('\n')); // reply with Watson response | ||
} | ||
@@ -189,2 +214,3 @@ } | ||
#### Use the middleware's hear() function | ||
You can find the default implementation of this function [here](https://github.com/watson-developer-cloud/botkit-middleware/blob/e29b002f2a004f6df57ddf240a3fdf8cb28f95d0/lib/middleware/index.js#L40). If you want, you can redefine this function in the same way that watsonMiddleware.before and watsonMiddleware.after can be redefined. Refer to the [Botkit Middleware documentation](https://botkit.ai/docs/core.html#controllerhears) for an example. Then, to use this function instead of Botkit's default pattern matcher (that does not use minimum_confidence), plug it in using: | ||
@@ -199,3 +225,3 @@ ```js | ||
Watson Assistant side of app action is documented in [Developer Cloud](https://console.bluemix.net/docs/services/assistant/deploy-custom-app.html#deploy-custom-app) | ||
Watson Assistant side of app action is documented in [Developer Cloud](https://cloud.ibm.com/docs/services/assistant/deploy-custom-app.html#deploy-custom-app) | ||
A common scenario of processing actions is: | ||
@@ -209,8 +235,8 @@ | ||
### using sendToWatson to update context (possible since v1.5.0) | ||
### Using sendToWatson to update context | ||
Using sendToWatson to update context simplifies the bot code compared to solution using updateContext below. | ||
```js | ||
function checkBalance(context, callback) { | ||
const checkBalance = async (context) => { | ||
//do something real here | ||
@@ -221,14 +247,12 @@ const contextDelta = { | ||
}; | ||
callback(null, context); | ||
} | ||
return context; | ||
}); | ||
const checkBalanceAsync = Promise.promisify(checkBalance); | ||
const processWatsonResponse = function (bot, message) { | ||
const processWatsonResponse = async (bot, message) => { | ||
if (message.watsonError) { | ||
return bot.reply(message, "I'm sorry, but for technical reasons I can't respond to your message"); | ||
return await bot.reply(message, "I'm sorry, but for technical reasons I can't respond to your message"); | ||
} | ||
if (typeof message.watsonData.output !== 'undefined') { | ||
//send "Please wait" to users | ||
bot.reply(message, message.watsonData.output.text.join('\n')); | ||
await bot.reply(message, message.watsonData.output.text.join('\n')); | ||
@@ -239,9 +263,9 @@ if (message.watsonData.output.action === 'check_balance') { | ||
checkBalanceAsync(message.watsonData.context).then(function (contextDelta) { | ||
return watsonMiddleware.sendToWatsonAsync(bot, newMessage, contextDelta); | ||
}).catch(function (error) { | ||
try { | ||
const contextDelta = await checkBalance(message.watsonData.context); | ||
await watsonMiddleware.sendToWatson(bot, newMessage, contextDelta); | ||
} catch(error) { | ||
newMessage.watsonError = error; | ||
}).then(function () { | ||
return processWatsonResponse(bot, newMessage); | ||
}); | ||
} | ||
return await processWatsonResponse(bot, newMessage); | ||
} | ||
@@ -254,97 +278,2 @@ } | ||
#### Using updateContext in controller (available since v1.4.0) | ||
Since 1.4.0 it is possible to update context from controller code. | ||
```js | ||
function checkBalance(context, callback) { | ||
//this version of function updates only the context object | ||
context.validAccount = true; | ||
context.accountBalance = 95.33; | ||
callback(null, context); | ||
} | ||
const checkBalanceAsync = Promise.promisify(checkBalance); | ||
const processWatsonResponse = function (bot, message) { | ||
if (message.watsonError) { | ||
return bot.reply(message, "I'm sorry, but for technical reasons I can't respond to your message"); | ||
} | ||
if (typeof message.watsonData.output !== 'undefined') { | ||
//send "Please wait" to users | ||
bot.reply(message, message.watsonData.output.text.join('\n')); | ||
if (message.watsonData.output.action === 'check_balance') { | ||
const newMessage = clone(message); | ||
newMessage.text = 'balance result'; | ||
//check balance | ||
checkBalanceAsync(message.watsonData.context).then(function (context) { | ||
//update context in storage | ||
return watsonMiddleware.updateContextAsync(message.user, context); | ||
}).then(function () { | ||
//send message to watson (it reads updated context from storage) | ||
return watsonMiddleware.sendToWatsonAsync(bot, newMessage); | ||
}).catch(function (error) { | ||
newMessage.watsonError = error; | ||
}).then(function () { | ||
//send results to user | ||
return processWatsonResponse(bot, newMessage); | ||
}); | ||
} | ||
} | ||
}; | ||
controller.on('message_received', processWatsonResponse); | ||
``` | ||
#### Using middleware.after and controller | ||
Before v1.4.0 only middleware.after callback can update context, and only controller can send replies to user. | ||
The downside is that it is impossible to send "Please wait message". | ||
```js | ||
function checkBalance(watsonResponse, callback) { | ||
//middleware.after function must pass a complete Watson respose to callback | ||
watsonResponse.context.validAccount = true; | ||
watsonResponse.context.accountBalance = 95.33; | ||
callback(null, watsonResponse); | ||
} | ||
watsonMiddleware.after = function(message, watsonResponse, callback) { | ||
//real action happens in middleware.after | ||
if (typeof watsonResponse !== 'undefined' && typeof watsonResponse.output !== 'undefined') { | ||
if (watsonResponse.output.action === 'check_balance') { | ||
return checkBalance(watsonResponse, callback); | ||
} | ||
} | ||
callback(null, watsonResponse); | ||
}; | ||
const processWatsonResponse = function(bot, message) { | ||
if (message.watsonError) { | ||
return bot.reply(message, "I'm sorry, but for technical reasons I can't respond to your message"); | ||
} | ||
if (typeof message.watsonData.output !== 'undefined') { | ||
//send "Please wait" to users | ||
bot.reply(message, message.watsonData.output.text.join('\n')); | ||
if (message.watsonData.output.action === 'check_balance') { | ||
const newMessage = clone(message); | ||
newMessage.text = 'balance result'; | ||
//send to watson | ||
watsonMiddleware.interpret(bot, newMessage, function() { | ||
//send results to user | ||
processWatsonResponse(bot, newMessage); | ||
}); | ||
} | ||
} | ||
}; | ||
controller.on('message_received', processWatsonResponse); | ||
``` | ||
## Implementing event handlers | ||
@@ -354,30 +283,21 @@ | ||
[Example](https://github.com/howdyai/botkit/blob/master/examples/facebook_bot.js) of handler: | ||
[Example](https://github.com/howdyai/botkit/blob/master/packages/docs/reference/facebook.md#facebookeventtypemiddleware) of handler: | ||
```js | ||
controller.on('facebook_postback', function(bot, message) { | ||
bot.reply(message, 'Great Choice!!!! (' + message.payload + ')'); | ||
controller.on('facebook_postback', async (bot, message) => { | ||
await bot.reply(message, `Great Choice. (${message.payload})`); | ||
}); | ||
``` | ||
Since they usually have no text, events aren't processed by middleware and have no watsonData attribute. | ||
If event handler wants to make use of some data from context, it has to read it first. | ||
Example: | ||
```js | ||
controller.on('facebook_postback', function(bot, message) { | ||
watsonMiddleware.readContext(message.user, function(err, context) { | ||
if (!context) { | ||
context = {}; | ||
} | ||
controller.on('facebook_postback', async (bot, message) => { | ||
const context = watsonMiddleware.readContext(message.user); | ||
//do something useful here | ||
myFunction(context.field1, context.field2, function(err, result) { | ||
const newMessage = clone(message); | ||
newMessage.text = 'postback result'; | ||
watsonMiddleware.sendToWatson(bot, newMessage, {postbackResult: 'success'}, function(err) { | ||
if (err) { | ||
newMessage.watsonError = error; | ||
} | ||
processWatsonResponse(bot, newMessage); | ||
}); | ||
}); | ||
}); | ||
const result = await myFunction(context.field1, context.field2); | ||
const newMessage = {...message, text: 'postback result' }; | ||
await watsonMiddleware.sendToWatson(bot, newMessage, { postbackResult: 'success' }); | ||
}); | ||
@@ -399,4 +319,4 @@ ``` | ||
```js | ||
slackController.hears(['hello'], ['direct_message', 'direct_mention', 'mention'], watsonMiddleware.hear, function(bot, message) { | ||
bot.reply(message, message.watsonData.output.text.join('\n')); | ||
slackController.hears(['hello'], ['direct_message', 'direct_mention', 'mention'], watsonMiddleware.hear, async function(bot, message) { | ||
await bot.reply(message, message.watsonData.output.text.join('\n')); | ||
// now do something special related to the hello intent | ||
@@ -409,6 +329,6 @@ }); | ||
```js | ||
slackController.changeEars(watsonMiddleware.hear); | ||
slackController.changeEars(watsonMiddleware.hear.bind(watsonMiddleware)); | ||
slackController.hears(['hello'], ['direct_message', 'direct_mention', 'mention'], function(bot, message) { | ||
bot.reply(message, message.watsonData.output.text.join('\n')); | ||
slackController.hears(['hello'], ['direct_message', 'direct_mention', 'mention'], async (bot, message) => { | ||
await bot.reply(message, message.watsonData.output.text.join('\n')); | ||
// now do something special related to the hello intent | ||
@@ -420,3 +340,3 @@ }); | ||
The _before_ and _after_ callbacks can be used to perform some tasks _before_ and _after_ Assistant is called. One may use it to modify the request/response payloads, execute business logic like accessing a database or making calls to external services. | ||
The _before_ and _after_ async calls can be used to perform some tasks _before_ and _after_ Assistant is called. One may use it to modify the request/response payloads, execute business logic like accessing a database or making calls to external services. | ||
@@ -426,5 +346,5 @@ They can be customized as follows: | ||
```js | ||
middleware.before = function(message, assistantPayload, callback) { | ||
// Code here gets executed before making the call to Assistant. | ||
callback(null, customizedPayload); | ||
middleware.before = (message, assistantPayload) => async () => { | ||
// Code here gets executed before making the call to Assistant. | ||
return assistantPayload; | ||
} | ||
@@ -434,6 +354,6 @@ ``` | ||
```js | ||
middleware.after = function(message, assistantResponse, callback) { | ||
// Code here gets executed after the call to Assistant. | ||
callback(null, assistantResponse); | ||
} | ||
middleware.after = (message, assistantResponse) => async () => { | ||
// Code here gets executed after the call to Assistant. | ||
return assistantResponse; | ||
}); | ||
``` | ||
@@ -443,19 +363,20 @@ | ||
If you need to make use of multiple workspaces in a single bot, workspace_id can be changed dynamically by setting workspace_id property in context. | ||
If you need to make use of multiple workspaces in a single bot, `workspace_id` can be changed dynamically by setting `workspace_id` property in context. | ||
Example of setting workspace_id to id provided as a property of hello message: | ||
Example of setting `workspace_id` to id provided as a property of hello message: | ||
```js | ||
function handleHelloEvent(bot, message) { | ||
message.type = 'welcome'; | ||
const contextDelta = {}; | ||
async handleHelloEvent = (bot, message) => { | ||
message.type = 'welcome'; | ||
const contextDelta = {}; | ||
if (message.workspaceId) { | ||
contextDelta.workspace_id = message.workspaceId; | ||
} | ||
if (message.workspaceId) { | ||
contextDelta.workspace_id = message.workspaceId; | ||
} | ||
watsonMiddleware.sendToWatsonAsync(bot, message, contextDelta).catch(function (error) { | ||
message.watsonError = error; | ||
}).then(function () { | ||
bot.reply(message, message.watsonData.output.text.join('\n')); | ||
}); | ||
try { | ||
await watsonMiddleware.sendToWatson(bot, message, contextDelta); | ||
} catch(error) { | ||
message.watsonError = error; | ||
} | ||
await bot.reply(message, message.watsonData.output.text.join('\n')); | ||
} | ||
@@ -462,0 +383,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
156133
3
29
960
20
365
1
+ Addedibm-watson@^4.1.0
+ Added@types/node@11.15.54(transitive)
+ Addedaxios@0.18.1(transitive)
+ Addedbuffer-equal-constant-time@1.0.1(transitive)
+ Addedecdsa-sig-formatter@1.0.11(transitive)
+ Addedfollow-redirects@1.5.10(transitive)
+ Addedform-data@2.5.3(transitive)
+ Addedibm-cloud-sdk-core@0.3.7(transitive)
+ Addedibm-watson@4.5.4(transitive)
+ Addedis-buffer@2.0.5(transitive)
+ Addedjsonwebtoken@8.5.1(transitive)
+ Addedjwa@1.4.1(transitive)
+ Addedjws@3.2.2(transitive)
+ Addedlodash.includes@4.3.0(transitive)
+ Addedlodash.isboolean@3.0.3(transitive)
+ Addedlodash.isinteger@4.0.4(transitive)
+ Addedlodash.isnumber@3.0.3(transitive)
+ Addedlodash.isplainobject@4.0.6(transitive)
+ Addedlodash.isstring@4.0.1(transitive)
+ Addedlodash.once@4.1.1(transitive)
+ Addedsemver@6.3.1(transitive)
- Removed@types/bluebird@^3.5.24
- Removedbluebird@^3.5.3
- Removedwatson-developer-cloud@^3.13.0
- Removed@types/bluebird@3.5.42(transitive)
- Removed@types/caseless@0.12.5(transitive)
- Removed@types/csv-stringify@1.4.3(transitive)
- Removed@types/form-data@2.5.2(transitive)
- Removed@types/request@2.47.1(transitive)
- Removed@types/tough-cookie@4.0.5(transitive)
- Removedajv@5.5.2(transitive)
- Removedasn1@0.2.6(transitive)
- Removedassert-plus@1.0.0(transitive)
- Removedaws-sign2@0.7.0(transitive)
- Removedaws4@1.13.2(transitive)
- Removedbcrypt-pbkdf@1.0.2(transitive)
- Removedbluebird@3.7.2(transitive)
- Removedbuffer-from@1.1.2(transitive)
- Removedcaseless@0.12.0(transitive)
- Removedco@4.6.0(transitive)
- Removedcore-util-is@1.0.2(transitive)
- Removedcsv-stringify@1.0.4(transitive)
- Removeddashdash@1.14.1(transitive)
- Removeddotenv@2.0.0(transitive)
- Removedecc-jsbn@0.1.2(transitive)
- Removedextsprintf@1.3.0(transitive)
- Removedfast-deep-equal@1.1.0(transitive)
- Removedfast-json-stable-stringify@2.1.0(transitive)
- Removedforever-agent@0.6.1(transitive)
- Removedform-data@2.3.34.0.2(transitive)
- Removedgetpass@0.1.7(transitive)
- Removedhar-schema@2.0.0(transitive)
- Removedhar-validator@5.0.3(transitive)
- Removedhttp-signature@1.2.0(transitive)
- Removedibm-cloud-sdk-core@0.0.3(transitive)
- Removedjsbn@0.1.1(transitive)
- Removedjson-schema@0.4.0(transitive)
- Removedjson-schema-traverse@0.3.1(transitive)
- Removedjson-stringify-safe@5.0.1(transitive)
- Removedjsprim@1.4.2(transitive)
- Removedlodash.get@4.4.2(transitive)
- Removedoauth-sign@0.8.2(transitive)
- Removedperformance-now@2.1.0(transitive)
- Removedpunycode@1.4.1(transitive)
- Removedqs@6.5.3(transitive)
- Removedrequest@2.87.0(transitive)
- Removedsafer-buffer@2.1.2(transitive)
- Removedsshpk@1.18.0(transitive)
- Removedtough-cookie@2.3.4(transitive)
- Removedtunnel-agent@0.6.0(transitive)
- Removedtweetnacl@0.14.5(transitive)
- Removeduuid@3.4.0(transitive)
- Removedverror@1.10.0(transitive)
- Removedwatson-developer-cloud@3.18.4(transitive)
Updateddebug@^4.1.1