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,
);