npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

sbot-conversation

v1.5.3

Published

A conversation implement for Hubot

Downloads

8

Readme

sbot-conversation

A conversation implement for Hubot.

Build status Coverage NPM version NPM Download License

NPM

Features

  • Conversation for hubot
  • Conversation manager

Installation

npm install sbot-conversation

Example

const {initManager} = require('sbot-conversation');
const DYNAMIC_SCHEMA_MOCK = {
  onCompleteMessage: 'Create user successfully!! Thanks for reporting this.',
  type: 'dynamic',
  steps: [
    {
      question: 'Start create a user \nPlease enter your user name.',
      answer: {
        type: 'text',
        validation: {
          'description': 'full name',
          'type': 'string',
          'minLength': 8
        }
      },
      required: true
    },
    {
      question: 'Please enter your user email.',
      answer: {
        type: 'text',
        validation: {
          'description': 'email address',
          'type': 'string',
          'format': 'email',
          'maxLength': 64
        }
      },
      required: true
    },
    {
      question: 'Please enter gender enum[female, male, unspecified]',
      answer: {
        type: 'choice',
        options: [
          {
            match: 'unspecified'
          },
          {
            match: 'male'
          },
          {
            match: 'female'
          }
        ]
      },
      required: false
    }
  ]
};

const JSON_SCHEMA_MOCK = {
  'type': 'object',
  'required': [
    'name'
  ],
  'properties': {
    'name': {
      'description': 'full name',
      'type': 'string',
      'minLength': 8
    }
  }
};

module.exports = function(robot) {
  let switchBoard = initManager(robot);
  robot.respond(/dynamic create user/i, msg => {
    let schema = switchBoard.initSchema('User', DYNAMIC_SCHEMA_MOCK);
    switchBoard.start(msg, 'dynamic create user', schema);
  });

  robot.respond(/create user/i, msg => {
    let schema = switchBoard.initSchema('User', JSON_SCHEMA_MOCK);
    switchBoard.start(msg, 'create user', schema);
  });
};

Usage

Create a conversation manager instance

initManager(robot, type, callback, singleton)

Return a conversation manager instance.(singleton is recommended).

  • robot: Hubot.Robot
  • type: (optional) 'user' or 'room', default 'user'.It defines if this conversation is with the whole room or with a particular user only. If the message comes from a user (or a room) that we're having a conversation with, it will be processed as the next step in an ongoing Dialog.
  • callback: (optional) The callback should be return a Boolean, when the return value is true and there is a active conversation of the user (or the room), it will be processed as the next step in an ongoing Dialog.
  • singleton: Boolean,(optional) default true. Enable the singleton.

Example

let switchBoard = initManager(robot, 'room', function(msg) {
  let reg = new RegExp(`^@hubot (show conversation|cancel conversation|resume conversation)(.*)`, 'i');
  if (reg.test(msg.text)) {
    return false;
  }
  return true;
});

Create a conversation

There are there patterns to create a conversation.

First pattern: Init a json schema

Example

const JSON_SCHEMA_MOCK = {
  'type': 'object',
  'required': [
    'name',
    'email'
  ],
  'properties': {
    'name': {
      'description': 'full name',
      'type': 'string',
      'minLength': 8
    },
    'email': {
      'description': 'email address',
      'type': 'string',
      'format': 'email',
      'maxLength': 64
    },
    'employeeNum': {
      'description': 'employee Number',
      'type': 'integer',
      'minimum': 100,
      'maximum': 600
    },
    'gender': {
      'description': 'gender',
      'type': 'enum',
      'default': 'unspecified',
      'enum': [
        'unspecified',
        'male',
        'female'
      ]
    }
  }
};

module.exports = function(robot) {
  let switchBoard = initManager(robot);
  robot.respond(/create user/i, msg => {
    let schema = switchBoard.initSchema('User', JSON_SCHEMA_MOCK);
    switchBoard.start(msg, 'create user', schema);
  });
};

How to define a json schema, please referJSON Schema type is required and must be a string 'object'.

Second pattern: Init a dynamic message model

Example

const DYNAMIC_SCHEMA_MOCK = {
  onCompleteMessage: 'Create user successfully!! Thanks for reporting this.',
  type: 'dynamic',
  steps: [
    {
      question: 'Start create a user \nPlease enter your user name.',
      answer: {
        type: 'text',
        validation: {
          'description': 'full name',
          'type': 'string',
          'minLength': 8
        }
      },
      required: true
    },
    {
      question: 'Please enter your user email.',
      answer: {
        type: 'text',
        validation: {
          'description': 'email address',
          'type': 'string',
          'format': 'email',
          'maxLength': 64
        }
      },
      required: true
    },
    {
      question: 'Please enter employee Num.',
      answer: {
        type: 'text',
        validation: {
          'description': 'employee Number',
          'type': 'integer',
          'minimum': 100,
          'maximum': 600
        }
      },
      required: false
    },
    {
      question: 'Please enter gender enum[female, male, unspecified]',
      answer: {
        type: 'choice',
        options: [
          {
            match: 'unspecified'
          },
          {
            match: 'male'
          },
          {
            match: 'female'
          }
        ]
      },
      required: false
    }
  ]
};

module.exports = function(robot) {
  let switchBoard = initManager(robot);
  robot.respond(/dynamic create user/i, msg => {
    let schema = switchBoard.initSchema('User', DYNAMIC_SCHEMA_MOCK);
    switchBoard.start(msg, 'dynamic create user', schema);
  });
};

How to define a dynamic message model:

  • onCompleteMessage: String // reply sent to the user when the conversation is done (optional)
  • skipKeyword: String // default 'skip', a keyword that can be used to skip non-required questions (optional)
  • skipMessage: String // a message that can be appended to any non-required questions (optional)
  • type: "dynamic" // conversation schema type must be 'dynamic' (required)
  • steps: Array, define properties.
steps: [
    {
      question: String // question to ask the user (required)
      answer: {
        type: String // could be 'choice', 'text' (required)
        options: [ // add the options object if the `type` of answer is `choice`
          {
            match: String, // what robot should listen to - can be a regex
            validation: Object // validate input, refer json shcema (optional)
          }
        ]
      },
      required: Boolean
    }
  ]

Third pattern: custom

Example

let conversation = switchBoard.start(msg, 'create user(custom)')

const function1 = (message) => {
  conversation.updateAnswers('yes')
  message.reply('Please enter your user name.')
  conversation.updateQuestion('Please enter your user name.')
  conversation.addChoice(/.*/i, function2)
}

const function2 = (message) => {
  conversation.updateAnswers(message.message.text)
  message.reply("Please enter your user email.")
  conversation.updateQuestion("Please enter your user email.")
  conversation.addChoice(/.*/i, function3)
}

const function3 = (message) => {
  conversation.updateAnswers(message.message.text)
  message.reply("Please enter employee Num.")
  conversation.updateQuestion("Please enter employee Num.")
  conversation.addChoice(/.*/i, function4)
}

const function4 = (message) => {
  conversation.updateAnswers(message.message.text)
  message.reply('Create user successfully!! Thanks for reporting this.')
  conversation.close();
}

const function5 =  (message) => {
  conversation.close();
  message.reply('Bye bye!')
}

msg.reply("Start create a user \n [yes]or [no]?")
conversation.updateQuestion("Start create a user \n [yes]or [no]?")
conversation.addChoice(/yes/i, function1)
conversation.addChoice(/no/i, function5)

robot.receiveMiddleware integration

Example

const _ = require('lodash');
const {Dialog} = require('sbot-conversation');

module.exports = function conversationMiddleware(customListener) {
  if (!_.isFunction(customListener)) {
    customListener = () => true;
  }

  return function(context, next, done) {
    let msg = context.response;
    let robot = msg.robot;

    robot.logger.debug('Conversation middleware processing: ', msg.message.text);

    let dialog = new Dialog(robot);
    if (!customListener(msg.message)) {
      return next();
    }
    let existsConversation = dialog.existsConversation(msg.message);
    if (existsConversation) {
      let receiverUserId = dialog.getId(msg.message);
      let conversation = dialog.getCurrentConversation(receiverUserId);
      conversation.receiveMessage(msg);
    }
    return next();
  };
};


//call the robot.receiveMiddleware method to register a conversationMiddleware in your script
robot.receiveMiddleware(conversationMiddleware(customListener));

Conversation manage

Example

module.exports = function(robot) {
  let switchBoard = initManager(robot);
  let existsConversation = switchBoard.existsConversation(msg.message);
  if (!existsConversation) {
    return msg.send(`@${msg.message.user.name} There is no active conversation.`);
  }
  let userId = switchBoard.getId(msg.message);
  let currentConversation = switchBoard.getCurrentConversation(userId);
  let conversations = switchBoard.getConversations(userId);
};

More Conversation manage Examples.

API

Conversation Manager API

initManager()

initManager(robot, type, callback, singleton)

Return a conversation manager instance.(singleton is recommended).

  • robot: Hubot.Robot
  • type: (optional) 'user' or 'room', default 'user'.It defines if this conversation is with the whole room or with a particular user only. If the message comes from a user (or a room) that we're having a conversation with, it will be processed as the next step in an ongoing Dialog.
  • callback: (optional) The callback should be return a Boolean, when the return value is true and there is a active conversation of the user (or the room), it will be processed as the next step in an ongoing Dialog.
  • singleton: Boolean,(optional) default true. Enable the singleton.

initSchema()

initSchema(schemaName , schema)

Returns a new conversation schema object.

  • schemaName: instance of hubot's Robot.
  • schema: json schema or dynamic message model.

initSchema used for json schema pattern or dynamic message model pattern only.

start()

start(msg, conversationName, schema, expireTime)

Returns a new conversation object, with a default expire time 1m.

  • msg: An incoming message heard / responded to by the robot. eg:
robot.respond(/foo/, function(msg){
    let schema = switchBoard.initSchema('User', DYNAMIC_SCHEMA_MOCK);
    switchBoard.start(msg, 'dynamic create user', schema);
})
  • conversationName: conversation name.
  • schema: schema object (optional), used for json schema pattern or dynamic message model pattern only.
  • expireTime: Number, (optional) expire time (ms).
robot.respond(/foo/, function(msg){
    switchBoard.start(msg, 'dynamic create user', null, 120 * 1000);
})

More Conversation Manager API.

Conversation API

Conversation is an instance of an EventEmitter, It will emit an end event with conversation.allAnswers when the flow is done. It has two other events expire and close.

conversation.on('end', allAnswers => {
  this.robot.logger.info(`Conversation: ${conversation.id} end`);
  this.robot.logger.debug(allAnswers);
});

addChoice()

addChoice(regex, handler)

Adds a listener choice to this Dialog. If a message is received that matches the choice regex, the handler will be executed. only for custom pattern.

  • regex: a regular expresion that will be aplied to the incoming message from the receive function
  • handler: function(message), A function that is executed against a successfully matched message. The match property of the original

updateQuestion()

updateQuestion(value)

Update last question. only for custom pattern.

  • value: String - question

updateAnswers()

updateAnswers(value)

Update all answers. only for custom pattern.

  • value: String - answer

close()

close()

Emit an close event with all all answers, and close the current conversation. only for custom pattern.