Skip to main content
Deno 2 is finally here šŸŽ‰ļø
Learn more

abstract-bot-api

This library solves two problems:

  1. You want to switch between chat providers and not change your code.
  2. You have deep stacked code that needs to access the chat api (e.g. to send a loading message from some internal method), and you donā€™t want to carry around credentials as globals (because maybe you have two bots running in the same server).

The first problem is solved by making a simple common api for all the services, while the second is solved using https://github.com/uriva/context-inject.

This library provides a unified API over:

  1. telegram
  2. whatsapp
  3. green-api (unofficial whatsapp api)
  4. websocket (for web page chat) 1

Installation

node.js:

npm i abstract-bot-api

deno:

import abc from "https://deno.land/x/abstract_bot_api/src/index.ts";

API

The abstract api methods:

reply: (text: string) => Promise<string> - a simple reply that gets text and returns the sent message id.

messageId: () => string - the incoming message id

referenceId: () => string - if the message quoted another message

medium: () => string - which service was used (ā€˜whatsappā€™, ā€˜green-apiā€™ etcā€™)

userId: () => string - the user id who sent the current message

withSpinner: (text: string, f: Function) => Function - wraps an async function with logic that provides a waiting animation for users

progressBar: (text: string) => Promise<(percentage: number) => Promise<void>> - get a way to send progress updates that appear in a loading bar animation

The nice thing is you can call these methods from anywhere in your code, so you donā€™t need to pass through things to deeply nested functions. The library understands by the call stack the context the messages should go to (see example below).

example

Hereā€™s an example usage:

import {
    AbstractIncomingMessage,
    bouncerServer,
    makeTelegramHandler,
    setTelegramWebhook,
    withSpinner,
} from "../src/index.ts";

import { gamla } from "../deps.ts";
import { reply } from "../src/api.ts";
import {
    whatsappBusinessHandler,
    whatsappWebhookVerificationHandler,
} from "../src/whatsapp.ts";

const { coerce, sleep } = gamla;
const telegramToken = coerce(Deno.env.get("TELEGRAM_TOKEN"));
const botServerSuffix = "/bot-url-suffix";

const whatsappPath = "/whatsapp-url-suffix";

const handleMessage = async (task: AbstractIncomingMessage) => {
    console.log("got task", task);
    await withSpinner("waiting needlessly", sleep)(5000);
    return reply("hi there i got " + JSON.stringify(task));
};

const url = coerce(Deno.env.get("URL"));

await bouncerServer(
    url,
    coerce(Deno.env.get("PORT")),
    [
        makeTelegramHandler(telegramToken, botServerSuffix, handleMessage),
        whatsappBusinessHandler(
            coerce(Deno.env.get("WHATSAPP_ACCESS_TOKEN")),
            whatsappPath,
            handleMessage,
        ),
        whatsappWebhookVerificationHandler(
            coerce(Deno.env.get("WHATSAPP_VERIFICATION_TOKEN")),
            whatsappPath,
        ),
    ],
);
await setTelegramWebhook(telegramToken, url + botServerSuffix).then(
    console.log,
);