docs: function makeHumaniseWare ({
    apiKey,
    incomingWebhookUrl,
    logger,
    getHandoffFromUpdate
  }) {
    if (!apiKey || !incomingWebhookUrl) {
      throw new Error('botmaster-humanise-ware requires at least both of apiKey and incomingWebhookUrl parameters to be defined')
    }
    const HUMANISE_URL = incomingWebhookUrl
    if (!logger) {
      logger = {
        log: debug,
        debug: debug,
        info: debug,
        verbose: debug,
        warn: debug,
        error: debug
      }
    }
    logger.info(`sending updates to humanise on: ${HUMANISE_URL}`)
    const incoming = {
      type: 'incoming',
      name: 'humanise-wrapped-incoming-ware',
      controller: async (bot, update) => {
        bot.sendIsTypingMessageTo(update.sender.id, {ignoreMiddleware: true}).catch(err => logger.error(err))
  
        // a few refinements for messenger specific messages before sending to humanise
        // will be deprecated in the future
        if (bot.type === 'messenger') {
          convertPostbacks(bot, update)
          convertRefs(bot, update)
          convertMessengerThumbsup(bot, update)
        }
  
        // updates with no messages are currently not supported. Also,
        // not sending back messages that come from a potential humanise bot
        // as would just be re-sending to platform that just sent it
        if (!update.message || bot.type === 'humanise') {
          const debugMessage = !update.message
          ? 'Got an update with no message, not sending it to humanise'
          : 'Got a user update from humanise, not sending it back to them'
          logger.verbose(debugMessage)
          return
        }
  
        // humanise takes in only objects that would be accepted on the various platforms
        const userInfo = await bot.getUserInfo(update.sender.id)
        if (getHandoffFromUpdate) {
          const handoffReason = await getHandoffFromUpdate(update)
          if (handoffReason) {
            const handoffTag = `<handoff>${handoffReason}</handoff>`
            update.message.text
              ? update.message.text += handoffTag
              : update.message.text = handoffTag
          }
        }
        const objectToSend = {
          apiKey,
          update,
          senderType: 'user',
          userInfo
        }
  
        const requestOptions = {
          method: 'POST',
          uri: HUMANISE_URL,
          json: objectToSend
        }
  
        const debugMessage = 'About to send update to humanise'
        logger.debug(debugMessage)
        await request(requestOptions)
        update.senderUserInfo = userInfo
      }
    }
  
    const outgoing = {
      type: 'outgoing',
      name: 'humanise-wrapped-outgoing-ware',
      controller: async (bot, update, message) => {
        // skip if there is no message
        if (!message.message) {
          return
        }
  
        let userInfo
        if (update.sender.id === message.recipient.id) {
          userInfo = update.senderUserInfo
        } else {
          // this should never be the case if it is something like an
          // an automated answer from an AI
          userInfo = bot.getUserInfo(message.recipient.id)
        }
  
        const objectToSend = {
          apiKey,
          update: message,
          senderType: 'bot',
          userInfo
        }
  
        const requestOptions = {
          method: 'POST',
          uri: HUMANISE_URL,
          json: objectToSend
        }
  
        await request(requestOptions)
  
        // don't send anything. Your webhook should now be doing that
        return 'cancel'
      }
    }
  
    const humaniseWare = {
      incoming,
      outgoing
    }
  
    return humaniseWare
  }