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 🙏

© 2025 – Pkg Stats / Ryan Hefner

abstract-bot-api

v129.0.0

Published

This library solves two problems:

Downloads

27

Readme

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