Skip to content

Latest commit

 

History

History
192 lines (150 loc) · 12 KB

api-reference.md

File metadata and controls

192 lines (150 loc) · 12 KB

API Reference 📖

Full type definitions live in /types.js: a single root-level file of JSDoc @typedefs (no .d.ts, no build step, no type-checking pipeline). This document is a human-readable tour of the same surface. Every core/plugin/event file references it via @typedef {import('#types').X} / @param {import('#types').X}, so your editor gives you hover info and autocomplete from the same source.

Import aliases

Module resolution uses Node's native package.json#imports field, no jsconfig.json, no bundler:

"imports": {
  "#types": "./types.js",
  "#config": "./config/config.js",
  "#core/*.js": "./src/core/*.js",
  "#events/*.js": "./src/events/*.js",
  "#plugins/*.js": "./src/plugins/*.js",
  "#utils/*.js": "./src/utils/*.js"
}
import { Bot } from '#core/Bot.js';
import { parseMessage } from '#utils/parseMessage.js';
import config from '#config';

These resolve identically regardless of which file imports them: no more counting ../../ segments.

Bot API

core/Bot.js, the framework entry point.

import { Bot } from '#core/Bot.js';
import config from '#config';

const bot = new Bot(config);

bot.use(async (ctx, next) => {
   /* middleware */ await next();
});
await bot.start(); // autoloads events, autoloads plugins, connects to WhatsApp
await bot.stop(); // graceful disconnect (keeps credentials)
Member Signature Notes
new Bot(config) (config: BotConfig) => Bot Constructs every core manager and the zapo client wrapper. Does not connect yet.
bot.use(middleware) (mw: Middleware) => void Shorthand for bot.middleware.use(mw).
bot.buildContext() () => BotContext Returns the memoized shared context (same object every call).
bot.start() () => Promise<void> Autoloads src/events/*.js, autoloads src/plugins/**/*.js, connects.
bot.stop() () => Promise<void> Disconnects without clearing stored credentials.
bot.config / bot.logger / bot.events / bot.commands / bot.plugins / bot.wa n/a Direct access to each core manager, same instances exposed on ctx.

Context API

BotContext (see plugin-development.md for the member table) is the object passed to every plugin's init, every event module's register, and every middleware. It is built once by Bot.buildContext() and reused: mutating something reachable from ctx (e.g. ctx.config.set(...)) is visible everywhere immediately.

MessageContext / CommandContext

Built by utils/parseMessage.js for every inbound message, before prefix detection: this is the piece that makes pulling text, isMedia, isType, isGroup, quoted, mentions, etc. off a message a one-liner instead of re-inspecting the raw protobuf:

{
  raw,          // the original zapo WaIncomingMessageEvent
  ctx,          // the shared BotContext
  key,          // WaMessageKey
  id,           // stanza id
  chatJid,      // conversation JID
  senderJid,    // participant in groups, remoteJid in 1:1
  isGroup,      // boolean
  fromMe,       // boolean
  pushName,     // string | undefined
  text,         // extracted text, trimmed
  type,         // 'text' | 'image' | 'video' | 'gif' | 'audio' | 'ptt' | 'document' | 'sticker' | 'poll' | 'location' | 'contact' | 'unknown'
  isMedia,      // boolean
  isType(kind), // (kind) => boolean (shorthand for `type === kind`)
  mimetype,     // string | undefined
  seconds,      // number | undefined (video/audio duration)
  quoted,       // { message, type } | undefined
  mentions,     // string[]
  send(content, options?),   // send into the originating chat
  reply(content, options?)   // reply (quoting this message) into the originating chat
}

CommandContext is the same object with prefix, command, args added once a message matches a registered command.

Parsing notes (per zapo's docs, read before relying on these fields):

  • chatJid/senderJid prefer event.key.remoteJidAlt/participantAlt over remoteJid/participant. zapo surfaces both PN (phone-number) and LID addressing on a message; using the alt form keeps the same contact resolving to the same JID string regardless of which addressing mode WhatsApp used for that particular stanza. If you persist JIDs yourself, normalize them the same way before comparing.
  • text only reads conversation, extendedTextMessage.text, and the current content type's caption (utils/media.js#extractText): polls, locations, contacts, and reactions have no plain-text body and yield ''. Always check type/isType() before trusting text on non-text messages.
  • event.message can be undefined (e.g. protocol/unavailable messages): parseMessage handles that defensively (type: 'unknown', text: ''), but a plugin reading raw.message.* directly must guard for it too.
  • quoted/mentions are read from the message's contextInfo, which only exists on content-bearing kinds (text, media, poll, event...): expect undefined/[] on reactions, receipts, and protocol messages.

MediaContext

Built by events/media.js for any message carrying an attachment:

{
   (raw,
      ctx,
      type, // 'image' | 'video' | 'gif' | 'audio' | 'sticker' | 'document'
      mimetype, // string | undefined
      seconds, // number | undefined
      caption, // string | undefined
      downloadToFile(filePath), // stream to disk
      downloadBytes()); // buffer in memory (small media only)
}

Plugin API

See plugin-development.md. The contract (import('#types').BotPlugin):

{
  name: string,
  type: 'command' | 'event',
  commands: string[] | undefined,   // required when type === 'command'
  description: string | undefined,
  enabled: boolean | undefined,     // defaults to true
  init(ctx) { /* ... */ },
  async execute(command) { /* ... */ }  // required when type === 'command'
}

Utility API

ctx.utils groups the pure-function helper modules, none of them touch the network or hold state.

utils/parseMessage.js

Function Signature
parseMessage(event, ctx) (WaIncomingMessageEvent, BotContext) => MessageContext, also exposed directly as ctx.utils.parseMessage.

utils/helper.js

Function Signature
sleep(ms) (number) => Promise<void>
formatBytes(bytes, decimals?) (number, number?) => string
formatDuration(ms) (number) => string
parseCommand(text, prefix) (string, string) => { command: string, args: string[] }
matchPrefix(text, prefixes) (string, string[]) => string | undefined
safeJsonParse(input, fallback?) (string, unknown?) => unknown
truncate(text, maxLength) (string, number) => string

utils/media.js

Function Signature
extractText(message) (Proto.IMessage?) => string
getMessageKind(message) (Proto.IMessage?) => MessageKind
hasMedia(message) (Proto.IMessage?) => boolean
getMediaDurationSeconds(message) (Proto.IMessage?) => number | undefined
getMediaMimetype(message) (Proto.IMessage?) => string | undefined
isAnimatedSticker(message) (Proto.IMessage?) => boolean
getContextInfo(message) (Proto.IMessage?) => Proto.IContextInfo | undefined
getQuotedMessage(message) (Proto.IMessage?) => Proto.IMessage | undefined
getMentionedJids(message) (Proto.IMessage?) => string[]

utils/sticker.js

Function Signature
createSticker(buffer, options?) (Buffer, StickerOptions?) => Promise<Buffer>, WebP-encoded sticker bytes, via wa-sticker-formatter.

utils/loader.js

The shared engine behind both autoloaders (core/PluginManager.js and events/index.js's loadEvents):

Function Signature
findJsFiles(directory, options?) (string, { exclude?: string[] }?) => Promise<string[]>, recursively collects .js file paths, sorted.
loadDefaultExports(directory, options?) (string, { exclude?: string[] }?) => Promise<{ filePath, module }[]>, dynamically imports each file found and returns its default export.

Core managers (advanced / internal)

Reach for these directly only when ctx's convenience surface doesn't cover what you need, normal plugins should not need to import core/* files.

Class File Responsibility
ConfigManager core/ConfigManager.js Dot-path config get/set + "change" events.
Logger core/Logger.js Implements zapo's Logger interface; also usable standalone.
EventManager core/EventManager.js The internal event bus (extends EventEmitter).
MiddlewareManager core/MiddlewareManager.js Koa-style onion middleware stack.
CommandManager core/CommandManager.js Command name → plugin Map, dispatch.
PluginManager core/PluginManager.js Recursive filesystem plugin autoloader (category folders, no metadata file).
ClientWrapper core/ClientWrapper.js Owns the zapo WaClient, store, pairing, reconnect.
Bot core/Bot.js Wires everything above together; the only file src/index.js imports.