@crysnovax/baileys
v2.5.0
Published
Premium Baileys fork — Meta compositing, bot planning replay, welcome flow, rich messages (code, table, LaTeX, reels), interactive messages, albums, and more.
Maintainers
Readme
const crysnova = {
name: "CRYSNOVA AI",
location: "🌍 Global",
role: "Full Stack Developer & Bot Creator",
stack: ["JavaScript", "Node.js", "Cloudflare Workers", "WhatsApp Bot Development"],
interests: ["AI", "Automation", "Open Source", "Building Cool Stuff"],
currentFocus: "Building the most powerful WhatsApp bot ecosystem 🚀",
funFact: "My code runs 24/7 on Cloudflare's edge network ⚡"
};| 🚀 Project | ⭐ Stars | 📝 Description |
|-----------|---------|---------------|
| CRYSNOVA AI | | 250+ Command WhatsApp Bot with AI Integration |
| API Gateway |
| Nexray Endpoints Unified API Gateway |
| Economy Engine |
| Realistic Virtual Economy with Banking System |
Basic setup — drop it in and it works:
import { createWelcomeFlow } from '@crysnovax/bailey'
const welcome = createWelcomeFlow(sock, {
greeting: '👋 Welcome! How can I help you today?',
footer: 'Powered by MyBot',
buttonText: '📋 Choose an option',
sectionTitle: 'How can we help?',
faqs: [
{ id: 'order', title: '📦 Track my order', description: 'Check order status' },
{ id: 'billing', title: '💳 Billing & payments', description: 'Payment issues & invoices' },
{ id: 'support', title: '🛠️ Technical support', description: 'Get help with a problem' },
{ id: 'human', title: '📞 Talk to a human', description: 'Connect with support staff' },
]
})
welcome.listen() // startHandle FAQ replies + greet callback:
const welcome = createWelcomeFlow(sock, {
greeting: '👋 Hi there! What brings you here today?',
faqs: [
{ id: 'pricing', title: '💰 Pricing', description: 'Plans and costs' },
{ id: 'demo', title: '🎥 Request demo', description: 'See it in action' },
{ id: 'support', title: '🛠️ Support', description: 'Get help' },
],
// Fires after greeting is sent
onGreet: async (jid, message) => {
console.log(`Greeted new contact: ${jid}`)
},
// Fires when user picks a FAQ option
onFaqReply: async (jid, faqId, message) => {
switch (faqId) {
case 'pricing':
await sock.sendMessage(jid, { text: '💰 Our plans start at $9/month...' })
break
case 'demo':
await sock.sendMessage(jid, { text: '🎥 Book a demo here: https://...' })
break
case 'support':
await sock.sendMessage(jid, { text: '🛠️ Describe your issue and we\'ll help!' })
break
}
}
})
welcome.listen()Persist seen contacts across restarts:
const welcome = createWelcomeFlow(sock, {
greeting: '👋 Welcome!',
faqs: [...],
persistPath: './data/greeted-contacts.json' // saves + loads automatically
})Control methods:
welcome.listen() // start listening
welcome.stop() // stop listening
welcome.reset(jid) // force re-greet one contact next message
welcome.resetAll() // clear all seen contacts
welcome.hasGreeted(jid) // check if contact was already greeted → booleanFull config reference:
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| greeting | string | '👋 Welcome!...' | Body text of the welcome message |
| footer | string | 'Powered by @crysnovax/bailey' | Footer text |
| buttonText | string | '📋 Choose an option' | List button label |
| sectionTitle | string | 'How can we help?' | Section header in the list |
| faqs | Array | 4 default items | { id, title, description } objects |
| typingDelayMs | number | 1200 | Typing indicator duration before greeting |
| persistPath | string\|null | null | JSON file path to persist seen JIDs |
| ignoreGroups | boolean | true | Skip group chats |
| ignoreNewsletter | boolean | true | Skip newsletter messages |
| ignoreBroadcast | boolean | true | Skip broadcast messages |
| onGreet | async fn | null | Called after greeting is sent |
| onFaqReply | async fn | null | Called when user selects a FAQ option |
replayPlanning — full live flow: all steps IN_PROGRESS → each flips DONE → delete → final message.
import { replayPlanning, mixedSteps } from '@crysnovax/bailey'
await replayPlanning(
sock, jid,
// Steps — status is managed automatically, don't pass it
mixedSteps([
{ title: 'Understanding your question…', type: 'reasoning' },
{ title: 'Searching for data…', type: 'search' },
{ title: 'Writing the answer…' }
]),
// Final rich message — any richResponse content
{ code: 'const answer = 42', language: 'javascript' },
// Options
{
description: 'Thinking…', // label on the bubble
stepDelayMs: 900, // ms between each step completing
finalPauseMs: 600, // ms to hold after all steps done
}
)Step type helpers — each renders a different visual in the Meta bubble.
import {
buildReasoningSteps, // isReasoning: true — "thinking" visual
buildSearchSteps, // isEnhancedSearch: true — "searching" visual
mixedSteps, // mix any combination
buildSteps // plain steps (from meta-compositing)
} from '@crysnovax/bailey'
// All reasoning
buildReasoningSteps(['Analyzing the problem…', 'Checking edge cases…'])
// All search
buildSearchSteps(['Searching the web…', 'Reading top results…'])
// Mixed — most realistic Meta AI look
mixedSteps([
{ title: 'Reading your message…', type: 'reasoning' },
{ title: 'Searching sources…', type: 'search' },
{ title: 'Composing response…' }
])replayPlanningOnly — run the animation without sending a final message. You control what comes next.
import { replayPlanningOnly, buildSearchSteps } from '@crysnovax/bailey'
await replayPlanningOnly(sock, jid,
buildSearchSteps(['Looking up prices…', 'Comparing results…']),
{ stepDelayMs: 1200 }
)
// Send whatever you want after — no badge, no trace
await sock.sendMessage(jid, { text: 'Here are the results!' })Options reference
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| description | string | 'Thinking…' | Top label on the indicator bubble |
| placeholderText | string | '' | Body text shown in bubble while steps run |
| stepDelayMs | number | 900 | Ms between each step flipping to DONE |
| finalPauseMs | number | 600 | Ms to hold after all steps complete before cleanup |
| abortOnDisconnect | boolean | true | Stops the loop cleanly if socket closes mid-replay |
| sendOptions | object | {} | Extra options passed to the final sendMessage call |
metaTyping — show the thinking indicator only. You control what happens next.
import { metaTyping, buildSteps, PlanningStepStatus } from '@crysnovax/bailey'
const placeholder = await metaTyping(sock, jid, {
description: 'Thinking…',
steps: buildSteps(['Reading your message…', 'Writing response…'])
})
// Delete it yourself whenever ready
await sock.sendMessage(jid, { delete: placeholder.key })sendMetaComposited — full flow: indicator → auto-delete → clean final message.
Works with every rich content type: code, table, text, expressions (LaTeX), items (reels carousel), or the full richResponse array.
import { sendMetaComposited, PlanningStepStatus } from '@crysnovax/bailey'
// With a code block
await sendMetaComposited(sock, jid,
{ code: 'const x = 1 + 1', language: 'javascript' },
{
thinkingMs: 3000,
description: 'Analyzing…',
steps: [
{ title: 'Reading context…', status: PlanningStepStatus.DONE },
{ title: 'Writing code…', status: PlanningStepStatus.IN_PROGRESS }
]
}
)
// With a table
await sendMetaComposited(sock, jid,
{
title: 'Comparison',
table: [
['Feature', 'Baileys', 'Crysnovax'],
['Rich Messages', '❌', '✅'],
['Meta Compositing', '❌', '✅'],
['Code Blocks', '❌', '✅']
]
},
{ thinkingMs: 2500, description: 'Building table…' }
)
// With plain richResponse array (mixed content)
await sendMetaComposited(sock, jid,
{
richResponse: [
{ text: 'Here is your result:' },
{ code: 'console.log("hello")', language: 'javascript' },
{ text: 'Run it with `node index.js`' }
]
},
{ thinkingMs: 2000 }
)Options reference
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| thinkingMs | number | 2000 | How long the indicator shows before auto-delete |
| description | string | 'Thinking…' | Top-level label on the indicator bubble |
| steps | Array | [] | Planning steps — use buildSteps() for quick setup |
| placeholderText | string | '' | Optional body text shown while loading |
| sendOptions | object | {} | Extra options passed to the final sendMessage call |
buildSteps helper — turn plain strings into a steps array instantly.
import { buildSteps, PlanningStepStatus } from '@crysnovax/bailey'
buildSteps(['Searching…', 'Reading sources…', 'Writing response…'])
// all IN_PROGRESS by default
buildSteps(['Done step'], PlanningStepStatus.DONE)