Extending ChipChat SDK

Mixins

Use the ChipChat.mixin() class method to augment bot instances with your own functions.

'use strict';

const ChipChat = require('../lib');

ChipChat.mixin({
    foo: c => c.say('Okidoki')
});

const bot = new ChipChat({
    token: process.env.TOKEN
});

bot.on('message.*.*.*', (m, c) => bot.foo(c));

bot.start();

bot.refreshToken();

Modules

Modules are simple functions that you can use to organize your code in different files and folders.

.module(factory)

The factory param is a function that gets called immediatly and receives the bot instance and an optional options object as its parameters. For example:

'use strict';

module.exports = (bot) => {
    bot.on('postback.*', (payload, chat) => {
        chat.say(`You clicked ${payload.text}`);
    });
    bot.on('message.create.*.*', (payload, chat) => {
        const buttons = [
            { type: 'postback', text: 'Settings', payload: 'HELP_SETTINGS' },
            { type: 'postback', text: 'Notifications', payload: 'HELP_NOTIFICATIONS' }
        ];
        chat.say({ text: 'Need help?', actions: buttons });
        chat.set('captured', true);
    });
};

modules/help.js

'use strict';

module.exports = (bot, options) => {
    bot.on('message.create.*.*', (payload, chat) => {
        const text = payload.text;
        if (options.onlyOnce && chat.get('captured')) { return; }
        chat.say(`Echo: ${text}`);
    });
};

modules/echo.js

'use strict';

const Bot = require('../lib/chipchat');
const echoModule = require('./modules/echo');
const helpModule = require('./modules/help');

const bot = new Bot({
    token: process.env.TOKEN
});

bot.module(echoModule, { onlyOnce: true });
bot.module(helpModule);

bot.start();

modules.js

You can find a good module example in how to store the access tokens in Google Secret Manager here

Middleware

Middlewares are functions that perform tasks before and after an operation (that call an API endpoint).

They can be used to modify parameters given to the operation, modify data received by the API, stop an operation call, cache data on the fly, batch requests, etc.

Add middleware

On instantiation:
const bot = new ChipChat({
    token: process.env.TOKEN,
    middleware: {
        send: [function (bot, message, next) {
            if (message.text) {
                message.text = `Middleware message mangling: ${message.text}`
            }
            next();
        }],
        receive: function (bot, payload, next) {
            console.log(payload.text);
            next();
        }
    }
});

Middelware Examples:

//Delay call
module.exports = function someMiddleware(bot, payload, next) {
    setTimeout(() => {
        next();
    }, 3000);
};

middleware/delay.js

module.exports = function someMiddleware(bot, payload, next) {
    console.log('error');
    next(new Error('nextErr'));
};

middleware/error.js

// Modify params given to the operation (before the call)
module.exports = function someMiddleware() {
    return next => function(params, callback, options) {
console.log('mungeparam');
        const newParams = {
            ...params,
            foo: 'bar',
        };
        next(newParams, callback, options);
    };
}

middleware/sendParams.js

//Stop operation call (and the next middlewares)
module.exports = function someMiddleware(bot, payload, next) {
    console.log('stop');
};

middleware/stop.js

And how you could use them:

'use strict';

const Bot = require('../lib/chipchat');
const sendware = require('./middleware/sendParams');
const delay = require('./middleware/delay');
const stop = require('./middleware/stop');

const mwareSend1 = (bot, message, next) => {
    console.log('mwaresend1', message.text, bot.auth.user);
    message.text = 'Hello MwareOverrideSent';
    next();
};
const mwareSend2 = (bot, message, next) => {
    console.log('mwaresend2', message.text, bot.auth.user);
    next();
};
const mwareSend3 = (bot, message, next) => {
    console.log('mwaresend3', message.text, bot.auth.user);
    next();
};
const mwareSend4 = (bot, message, next) => {
    console.log('mwaresend4', message.text, bot.auth.user);
    next();
};

const mwareRecv1 = (bot, payload, next) => {
    console.log('mwarerecv1', payload.event, payload.data.message.text);
    payload.data.message.text = 'MwareOverrideReceived';
    next();
};
const mwareRecv2 = (bot, payload, next) => {
    console.log('mwarerecv2', payload.event, payload.data.message.text);
    next();
};
const mwareRecv3 = (bot, payload, next) => {
    console.log('mwarerecv3', payload.event, bot.auth.user);
    next();
};

const bot = new Bot({
    token: process.env.TOKEN,
    ignoreSelf: false,
    ignoreBots: false,
    middleware: {
        send: sendware,
        // multiple mware gets stacked/run in reverse order
        receive: [mwareRecv1, mwareRecv2].reverse()
    }
});
//bot.middleware.send.use([mwareSend2], mwareSend3);
bot.middleware.send.use(mwareSend3, mwareSend2, mwareSend1);
bot.middleware.send.use(mwareSend4);

// middleware.receive
bot.use(delay);
//bot.use([stop]);
bot.use(mwareRecv3);

bot.on('error', (err) => {
    console.log('err', err);
});

bot.on('message', (m, c) => c.say('Trigger SendMW'));

bot.start();

bot.conversations.list(
    { sort: '-createdAt', limit: 1 },
    (err, convs) => {
        bot.send(
            convs[0].id, 'Hello Mware',
            (e, msg) => console.log('said', e && e.name, msg && msg.text) //msg.text)
        );
    }
);

.use()

Use the bot.use() function to add inbound (receive) middleware

bot.use((bot, payload, next) => {
    console.log(payload.text);
    payload.text = 'Mangled';
    next();
});