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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@gamastudio/sendwave-provider

v1.0.5

Published

Official Sendwaves provider for BuilderBot. Multi-instance WhatsApp messaging library with intelligent message merging, media support, interactive buttons, lists, carousels, polls, and automatic queue flow.

Readme

📖 Sendwaves Provider

A dynamic library for integrating and managing Sendwave instances for WhatsApp bot development.

🚀 Installation

npm install @gamastudio/sendwave-provider

🔧 Basic Usage

Creating a Provider Instance

import { createSendWaveProvider } from "@gamastudio/sendwave-provider";

const provider = createSendWaveProvider({
  name: "MyBot",
  apiKey: "your-api-key-here",
  port: 3000,
});

// Initialize the provider
await provider.initAll(provider.globalVendorArgs.port);

Multi-Tenant: Multiple Instances with One Webhook

You can manage multiple Sendwave instances with a single provider. The webhook will route messages automatically based on instanceName in the payload.

import { createSendWaveProvider } from "@gamastudio/sendwave-provider";

const provider = createSendWaveProvider({
  port: 3000,
  url: "https://msg.sendwaves.cloud",
  instances: [
    { name: "bot-sales", apiKey: "api-key-sales" },
    { name: "bot-support", apiKey: "api-key-support" },
    { name: "bot-marketing", apiKey: "api-key-marketing" },
  ],
});

await provider.initAll(provider.globalVendorArgs.port);

// Send message to a specific instance
await provider.sendText(
  { from: "573123456789", text: "Hello from sales!" },
  { instance: "bot-sales" }
);

// Notify admin on another instance
await provider.sendText(
  { from: "573199999999", text: "Nuevo pedido recibido" },
  { instance: "bot-admin" }
);

// Or use the default (first instance)
await provider.sendText({
  from: "573123456789",
  text: "Hello!",
});

// List registered instances
console.log(provider.getInstances().map((i) => i.name));

Webhook routing: the provider reads instanceName from body.instanceName, body.inputs.instanceName, or body.instance.name. Point all your Sendwave webhooks to the same /webhook URL.

QR / State per instance:

  • /qr → default instance
  • /qr/bot-sales → specific instance
  • /state → default instance
  • /state/bot-sales → specific instance

⚙️ Configuration

const provider = createSendWaveProvider({
  name: "MyBot",
  apiKey: "your-api-key-here",
  url: "https://msg.sendwaves.cloud", // Optional
  port: 3000,
  host: "0.0.0.0",
  readMessages: true, // Auto-mark incoming messages as read
  message: {
    mergeMessage: true,        // Merge rapid messages from same user
    timeMergeMessage: 3,       // Base wait time in seconds
    maxWaitTime: 30,           // Maximum wait time in seconds
    shortMessageThreshold: 10, // Short messages merge faster
    adaptiveTimer: true,       // Smart timing based on message patterns
  },
  queueFlow: {
    enabled: true,
    warningTimeout: 30 * 60 * 1000, // 30 minutes
    endTimeout: 2 * 60 * 1000,      // 2 minutes after warning
  },
  payloadLimits: {
    json: "50mb",
    urlencoded: "50mb",
    text: "10mb",
    media: {
      image: "10mb",
      video: "100mb",
      audio: "50mb",
      document: "25mb",
    },
  },
});

📤 Sending Messages

Text Messages

await provider.sendText({
  from: "573123456789",
  text: "Hello! Welcome to our service.",
  delay: 2000, // Optional typing delay
});

// Send to a specific instance (multi-tenant)
await provider.sendText(
  { from: "573123456789", text: "Hello!" },
  { instance: "bot-sales" }
);

Presence Indicators

await provider.sendPresence({
  from: "573123456789",
  presence: "composing", // or "recording"
  delay: 2000,
});

Media Messages

// Image
await provider.sendImage({
  from: "573123456789",
  url: "https://example.com/image.jpg",
  text: "Optional caption",
});

// Video
await provider.sendVideo({
  from: "573123456789",
  url: "https://example.com/video.mp4",
  text: "Optional caption",
});

// Document/File
await provider.sendFile({
  from: "573123456789",
  url: "https://example.com/file.pdf",
  fileName: "document.pdf",
  text: "Optional caption",
});

// Audio
await provider.sendAudio({
  from: "573123456789",
  url: "https://example.com/audio.mp3",
});

// Voice message (PTT)
await provider.sendVoice({
  from: "573123456789",
  url: "https://example.com/voice.ogg",
});

Interactive Buttons

The provider accepts multiple formats for buttons.

// 1. Super Simple (Quick Replies)
await provider.sendButton({
  from: "573123456789",
  title: "Main Menu",
  body: "Select an option",
  footer: "Sendwaves Provider",
  buttons: ["🛒 Catalog", "🎁 Promotions", "📞 Support"]
});

// 2. Mixed Format (Text & Functional buttons)
await provider.sendButton({
  from: "573123456789",
  title: "Payment Options",
  body: "Select your preferred method",
  buttons: [
    { type: "reply", displayText: "Cash" },
    { type: "url", displayText: "Visit Web", url: "https://example.com" },
    { type: "call", displayText: "Call Us", phoneNumber: "+573123456789" },
    { type: "copy", displayText: "Copy Coupon", copyText: "SAVE20" },
    { type: "pix", displayText: "Pay with Pix", keyType: "email", key: "[email protected]" }
  ]
});

Supported Button Types:

  • reply: Standard quick reply button.
  • url: Opens a website.
  • call: Triggers a phone call.
  • copy: Copies text or code to clipboard.
  • pix: Brazilian payment system integration.

Carousel Messages

Send a scrollable carousel with multiple cards. Each card supports its own buttons.

await provider.sendCarousel({
  from: "573123456789",
  title: "Featured Products",
  description: "Swipe to see our best offers",
  footer: "Sendwaves Store",
  cards: [
    {
      text: "Premium Plan",
      thumbnailUrl: "https://example.com/plan1.jpg",
      footerText: "Best value",
      buttons: [
        { type: "reply", displayText: "Buy Now" },
        { type: "url", displayText: "More Info", url: "https://example.com/plan1" }
      ]
    },
    {
      text: "Basic Plan",
      thumbnailUrl: "https://example.com/plan2.jpg",
      footerText: "Affordable",
      buttons: [
        { type: "reply", displayText: "Buy Now" }
      ]
    }
  ],
  delay: 2000
});

Interactive Lists

// Simple List (Array of strings)
await provider.sendList({
  from: "573123456789",
  list: {
    title: "Select an option",
    button: "View Options",
    content: ["Option 1", "Option 2", "Option 3"],
  },
});

// Advanced List with sections
await provider.sendList({
  from: "573123456789",
  list: {
    title: "Product Categories",
    description: "Choose a category",
    button: "Select Category",
    footerText: "Sendwaves Provider",
    content: [
      {
        title: "Electronics",
        rows: [
          { title: "Smartphones", description: "Latest models" },
          { title: "Laptops", description: "Gaming and office" },
        ],
      },
    ],
  },
});

Polls

await provider.sendPoll({
  from: "573123456789",
  poll: {
    name: "¿Qué te parece el nuevo proveedor?",
    values: ["Excelente", "Bueno", "Mejorable"],
    selectableCount: 1 // Optional, default: 1
  }
});

Locations

await provider.sendLocation({
  from: "573123456789",
  name: "Our Office",
  address: "123 Main St, Bogotá",
  latitude: 4.711,
  longitude: -74.0721,
});

Reactions

await provider.sendReaction({
  key: {
    remoteJid: "[email protected]",
    fromMe: false,
    id: "MESSAGE_ID",
  },
  reaction: "👍",
});

Mark as Read

await provider.readMessages({
  from: "[email protected]",
  messageId: "MESSAGE_ID",
});

🧠 Intelligent Message Merging

When mergeMessage is enabled, rapid messages from the same user are merged into a single message.

const provider = createSendWaveProvider({
  message: {
    mergeMessage: true,
    timeMergeMessage: 4,
    maxWaitTime: 30,
    shortMessageThreshold: 10,
    adaptiveTimer: true,
  }
});

Example:

  • User sends "Hola" then "como estas"
  • Result: single message with body "Hola como estas"

🔄 Queue Flow System

Automatic session management for inactive users.

const provider = createSendWaveProvider({
  queueFlow: {
    enabled: true,
    warningTimeout: 30 * 60 * 1000, // 30 mins
    endTimeout: 2 * 60 * 1000,      // 2 mins after warning
    warningMessage: "⏳ You seem inactive. Still there?",
  },
});

// Listen to inactivity events
provider.onQueueFlowEvent("userInactive-573123456789", (data) => {
  console.log(data.isActive ? "User warned" : "Session ended");
});

🎯 Event System

provider.on("ready", (isReady) => console.log("Connected:", isReady));
provider.on("message", (ctx) => console.log(`From ${ctx.from}: ${ctx.body}`));
provider.on("user-message", (data) => console.log("User message:", data));
provider.on("flow-message", (data) => console.log("Flow message:", data));
provider.on("auth_failure", (payload) => console.error("Auth failed:", payload));
provider.on("notice", ({ title, instructions }) => console.log(title, instructions));

🏗️ Architecture

The project is organized in modular layers:

  • config/: Default values and constants.
  • domain/: Pure types and interfaces.
  • infrastructure/: HTTP client, API repository, media detection, message parser.
  • application/: Business logic: message strategies, buffer merging, connection polling, queue flow.
  • presentation/: Provider and core classes, HTML pages.
  • shared/: Common utilities and exceptions.

Adding a New Message Type

  1. Create a strategy in src/application/messaging/strategies/.
  2. Implement the SendStrategy<T> interface.
  3. Register it in MessageSenderService.
  4. Add the public method to SendWaveProvider.
  5. Add the type to ProviderInterface and message.types.ts.

📜 License

ISC License © 2026 - Ameth Galarcio