WhatsApp bot powered by @baileys — Supports JS + TS, Bun + npm.
Just drop a .js or .ts file → auto-loaded. Commands work instantly.
SAZA (Smart Assistant with Zero-delay Answer) is a lightweight WhatsApp bot built on a persistent connection and multi-layer caching architecture. Once the initial connection is established, group metadata, identity resolution (LID → phone number), and plugins are cached in memory — so the first response is already fast, and subsequent messages are processed with almost no perceptible delay.
Fast Answer |
Meta AI Style |
This project runs on Bun and Node.js (npm) with zero code changes. The SQLite backend auto-detects the runtime.
| Bun | Node.js (npm) | |
|---|---|---|
| Command | bun --smol index.js |
node index.js |
| SQLite | bun:sqlite (built-in, no native addon) |
better-sqlite3 (C++ addon) |
| TS Plugins | ✅ Native — .ts works directly |
tsx |
| Base RAM | ~10-20MB lower (JSC vs V8) | Slightly higher |
| Startup | ~500ms | ~2-3 seconds |
| Hot reload | bun --watch index.js |
Use nodemon |
# Node.js (npm | recommended)
npm install
node index.js
node index.js --memlog # + RAM logging
# Bun
bun install
bun --smol index.js # --smol = more aggressive GC
bun --smol index.js --memlog # + RAM logging| Flag | Description |
|---|---|
--smol |
(Bun only) More aggressive GC, lower peak RAM |
--memlog |
Show RSS/heap/external memory at startup & after connect |
- Node.js 18+ (recommended) or Bun
- git (for cloning)
git clone <repo-url> sazabot
cd sazabot
npm install # or: bun install
nano config.json # fill in owner, bot number, name
node index.js # or: bun --smol index.jsThe bot auto-creates the db/ directory on first startup. Scan the QR code in the terminal (or use a pairing code).
# Bun → Node.js (npm)
rm bun.lock && npm install && npm start
# Node.js → Bun
rm package-lock.json && bun install && bun index.js| Document | Description |
|---|---|
docs/eng/creating-plugins.md |
Complete plugin guide — context reference, sending messages, target resolution, premium integration, before hooks, hot-reload |
docs/eng/airich-builder.md |
AIRich — Meta AI-style rich response builder. Text formatting, code blocks with syntax highlighting, tables, images, video, products, reels, suggestions, source citations. Fluent API. |
Edit config.json before the first run. All fields:
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Bot display name |
owner |
string | Yes | Your WhatsApp number — gets full access to owner commands. No +, no spaces (e.g. 6289876543210) |
bot |
string | For pairing | Bot phone number. Used for pairing code + owner detection. |
prefix |
string | No | Command prefix, default . |
status |
string | No | public (default) — all chats. ponly — private only. gonly — groups only. self — owner+bot only. |
autoread |
string | No | enable (default) — auto mark messages as read. disable — leave unread. |
loginMethod |
string | No | qr (default) — scan QR in terminal. pairs — 8-digit code in WhatsApp app. |
pairscode |
string | No | Custom code for pairing (default SAZA-SAZA). Only used when loginMethod = pairs. |
markdown |
boolean | No | true (default) — WhatsApp natively renders *bold* _italic_. |
Example:
{
"name": "MyBot",
"bot": "6281234567890",
"owner": "6289876543210",
"prefix": ".",
"status": "public",
"autoread": "enable",
"loginMethod": "qr",
"pairscode": "SAZA-SAZA",
"markdown": true
}QR Code (default):
[boot] scan the QR code below:
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
█ ▄▄▄▄▄ █ ▀▀▄ ██▄██ ▄▄▄▄▄ █
█ █ █ ███ ▄▄ ▄ █ █ █ █
█ █▄▄▄█ █ ▄▄ █▄▄███ █▄▄▄█ █
█▄▄▄▄▄▄▄█ █ ▀ █▄▀ █▄▄▄▄▄▄▄█
█ ██ ▄█ █▄▄█▀ ▄▄ ▄█▀ █
██▀▀▀██▄▄▄▀█▄▀█ ▄█▄ ▄▄ █▀▄█
██▄▀█▄▄▄ █ █ █▀ ▀ ▄█▄█▄ █
█▄▄ ▀ ▀▄▄▄▄▄ █▄ ▄ █ ▄█▄▀ █
█▄▄▄██▄▄▄▀▄█ ▀██ ▄▄▄ ▀ ▄█
█ ▄▄▄▄▄ █▀▄█▄█▄▀▀ █▄█ ▀▄▀ █
█ █ █ ██ ▀ ██▄▄▄▄ ▄▄ ██
█ █▄▄▄█ █ ▀▄ ▄ █▄▄█▀ █▄▄█
█▄▄▄▄▄▄▄█▄▄▄▄████▄▄▄██▄██▄█
...
WhatsApp → Settings → Linked Devices → Link a Device → scan.
Pairing Code:
[boot] pairing code: SAZA-SAZA
[boot] enter this code in WhatsApp → Linked Devices
| Command | Category | Description |
|---|---|---|
.ping |
utility | Speed, CPU, RAM |
.menu / .help |
info | Command list by category |
.profile |
info | Your premium status + credits |
.msgbuild / .airich |
info | Inspect message builder |
$ <command> |
owner | Execute terminal commands (owner only) |
.set <public|self|ponly|gonly> |
owner | Change status mode |
.setp <prefix> / .setprefix |
owner | Change command prefix |
.ban <target> [duration] |
owner | Ban user (d/h/m/days, default permanent) |
.unban <target> |
owner | Unban user |
.listban / .banlist |
owner | Show all banned users |
.addprem <target> [duration] |
owner | Add premium user |
.delprem <target> |
owner | Remove premium user |
.listprem |
owner | Show all premium users |
.hello / .hi |
info | TypeScript plugin demo |
Messages are tagged by type in the console:
| Tag | Message Type | Executes Command? |
|---|---|---|
[msg] |
Conversation / extended text | ✅ Yes |
[react] |
Reaction emoji (🍥) | ❌ Skipped |
[sticker] |
Sticker | ❌ Skipped |
[img] |
Image with caption | ✅ Yes (caption) |
[vid] |
Video with caption | ✅ Yes (caption) |
[audio] |
Voice note | ❌ Skipped |
[doc] |
Document with caption | ✅ Yes (caption) |
[self] |
Message from bot's own phone | ❌ No command execution |
SQLite-based with multi-alias matching (JID + LID + phone number). Expired bans auto-cleaned on read.
Commands: .ban @user [duration] | .unban @user | .listban
.ban @user 1h → ban for 1 hour
.ban @user 30m → ban for 30 minutes
.ban @user 7d → ban for 7 days
.ban @user → permanent ban
.unban @user → remove ban
Target via: reply to user's message, @user mention, or type their number directly.
SQLite-based with 10 credits/month. Credits auto-reset on first access after the monthly boundary (lazy reset — no cron). Multi-alias matching.
Commands: .addprem @user [duration] | .delprem @user | .listprem
.addprem @user 30d → premium 30 days, 10 credits
.addprem @user → permanent premium
.listprem → show all premium users with credits
- Session stored in
db/session/session.db(SQLite, single file) - On logout: auto-clear session, reconnect, show new QR
- Bad MAC recovery: If encryption keys are corrupted (Bad MAC error), the bot auto-clears the session & shows a new QR — no manual restart needed
- Exponential backoff: 3s → 6s → 12s → ... → max 60s
- Reconnect debounced: prevents duplicate reconnect loops
- WAL + SHM files auto-cleaned on session reset
Baileys (WhatsApp Web library) dominates memory at ~80-150MB regardless of runtime. Bun's advantages:
| Aspect | Savings |
|---|---|
| Baseline JSC vs V8 | ~10-20MB lower |
bun:sqlite vs better-sqlite3 |
No native addon overhead |
--smol flag |
More aggressive GC, lower peak |
generateHighQualityLinkPreview: false |
Avoids loading image processing deps |
For most bots, the RAM difference is marginal since Baileys' crypto state is the bottleneck. Bun's main advantages are startup speed (~500ms vs 2-3 seconds) and native TS support.
template-jsts-bun/
├── index.js # Entry point — connect, reconnect, message loop
├── handler.js # Message pipeline — command dispatch, ban check
├── config.json # Bot settings
├── package.json # Dual Bun + npm scripts
├── README.md
│
├── db/ # SQLite databases (auto-created)
│ ├── session/session.db # WhatsApp multi-device session
│ ├── banned/banned.db # Banned users list
│ └── premium/premium.db # Premium users
│
├── lib/
│ ├── sqlite.js # SQLite wrapper — auto-detect Bun/Node
│ ├── sqlite-auth.js # Baileys auth state via SQLite
│ ├── messages.js # Message parser + helpers (.reply/.react/.delete)
│ ├── messageBuilder.js # Interactive message builder
│ ├── pluginLoader.js # JS+TS scanner + chokidar hot-reload
│ ├── config.js # Config loader & saver
│ ├── banStore.js # Ban system (SQLite)
│ └── premiumStore.js # Premium system (SQLite)
│
└── plugins/
├── hello.ts # TypeScript plugin demo
├── utility-ping.js # .ping .stats .status
├── info-menu.js # .menu .help
├── info-profile.js # .profile
├── info-msgbuild.js # .msgbuild .airich
├── owner-ban.js # .ban .unban .listban
├── owner-premium.js # .addprem .delprem .listprem
├── owner-exec.js # $ (shell exec, owner only)
├── owner-set.js # .set (status mode)
├── owner-setprefix.js # .setp .setprefix
└── hidden-autorespon.js # Auto-react (before hook)
start()
├── loadAllPlugins() → scan plugins/*.js + plugins/*.ts
├── watchPlugins() → chokidar hot-reload (add/change/unlink)
└── connect()
├── fetchLatestBaileysVersion() → protocol version
├── useSQLiteAuthState() → session from db/session/
├── makeWASocket() → Baileys v7 WhatsApp Web socket
│ ├── makeCacheableSignalKeyStore() → Bun compat (async keys)
│ └── generateHighQualityLinkPreview: false → save RAM
└── sock.ev handler
├── connection.update → QR, loggedOut, reconnect
├── messages.upsert → Messages() → msgHandler()
├── messages.update → (internal)
└── call → auto-reject
Incoming message (messages.upsert, type: notify)
│
├── Skip if >60s old, status@broadcast, or no remoteJid
├── Unwrap ephemeral / viewOnce / documentWithCaption wrappers
└── Messages() wrapper
├── Resolve sender (participantAlt for groups, LID→phone)
├── Extract text / caption / reaction content
├── Build quoted message if present
└── Attach .reply() .react() .delete() helpers
│
▼
msgHandler()
├── Status filter (public / ponly / gonly / self)
├── LID → phone resolution (cached)
├── Owner detection (fromMe || number match)
├── Ban check (silent drop if banned)
├── Run all plugin before() hooks
├── Prefix detection (prefix or "$ " for owner)
├── Plugin lookup
├── AI concurrency guard (if category: ai)
└── Execute plugin.handler(message, ctx)
MIT — Free for personal & commercial use. Base built by @DranxX and with contribution @RizzyFuzz.
Powered by Baileys v7 · SQLite via bun:sqlite / better-sqlite3



