Package Exports
- @rizzclub/channels
- @rizzclub/channels/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@rizzclub/channels) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
@rizzclub/channels
Multi-channel messaging library with a grammy-compatible API for Telegram, Webchat, WhatsApp, and SMS.
Features
- 🎯 Grammy-compatible API - Drop-in replacement for grammy with the same interface
- 🔌 Multiple Channels - Telegram, Webchat, WhatsApp (coming soon), SMS (coming soon)
- 🚀 Cloudflare Workers - Optimized for serverless deployment
- 📦 TypeScript - Full type safety and autocompletion
- 🎨 Unified Interface - Write once, deploy to multiple channels
Installation
npm install @rizzclub/channelsQuick Start
Telegram Bot
import { Bot, TelegramAdapter } from '@rizzclub/channels';
const adapter = new TelegramAdapter({
token: process.env.TELEGRAM_TOKEN
});
const bot = new Bot(adapter);
bot.command('start', (ctx) => {
return ctx.reply('Hello! I am your bot.');
});
bot.on('message:text', (ctx) => {
return ctx.reply(`You said: ${ctx.text}`);
});
// Cloudflare Worker
export default {
async fetch(request: Request, env: Env) {
return bot.handleWebhook(request);
}
};Webchat Bot
import { Bot, WebchatAdapter } from '@rizzclub/channels';
const adapter = new WebchatAdapter({
webhookSecret: process.env.WEBHOOK_SECRET,
callbackUrl: 'https://your-app.com/api/messages'
});
const bot = new Bot(adapter);
bot.on('message:text', async (ctx) => {
await ctx.reply(`Echo: ${ctx.text}`);
});
bot.callbackQuery(/^button:/, async (ctx) => {
await ctx.answerAlert('Button clicked!');
});API Reference
Bot
The Bot class is the main entry point, providing a grammy-compatible API.
Methods
bot.command(command, handler)- Handle commands (e.g.,/start)bot.on(event, handler)- Handle events (e.g.,'message:text')bot.hears(trigger, handler)- Handle messages matching text/regexbot.callbackQuery(data, handler)- Handle inline button callbacksbot.use(middleware)- Add middlewarebot.filter(filter, handler)- Handle messages matching custom filterbot.handleWebhook(request)- Process incoming webhook requests
Events
'message'- Any message'message:text'- Text messages only'callback_query'- Inline button clicks'edited_message'- Message edits
Context
The Context object provides convenient access to update data and reply methods.
Properties
ctx.message- The message objectctx.chat- The chat objectctx.from- The user objectctx.text- Message textctx.callbackQuery- Callback query objectctx.callbackData- Callback query datactx.channel- Current channel type
Methods
ctx.reply(text, options?)- Reply to the messagectx.send(text, options?)- Send without replyingctx.editMessageText(text, options?)- Edit the messagectx.deleteMessage()- Delete the messagectx.answerCallbackQuery(options?)- Answer callback queryctx.answerAlert(text)- Answer with alert popupctx.hasCommand(command?)- Check if message is a command
Adapters
TelegramAdapter
Wraps grammy for Telegram integration.
import { TelegramAdapter } from '@rizzclub/channels';
const adapter = new TelegramAdapter({
token: 'YOUR_BOT_TOKEN'
});Options:
token- Telegram bot token from @BotFatherbot?- Optional grammy Bot instance for advanced usage
WebchatAdapter
Custom adapter for web-based chat interfaces.
import { WebchatAdapter, InMemoryMessageStore } from '@rizzclub/channels';
const adapter = new WebchatAdapter({
webhookSecret: 'your-secret',
callbackUrl: 'https://your-app.com/api/send',
callbackHeaders: {
'Authorization': 'Bearer token'
},
messageStore: new InMemoryMessageStore()
});Options:
webhookSecret?- Secret for validating webhook requestscallbackUrl?- URL to POST messages tocallbackHeaders?- Headers for callback requestsmessageStore?- Store for tracking messages
Webhook Payload Format:
{
type: 'message' | 'callback_query',
sessionId: string,
userId: string,
userName?: string,
timestamp: number,
message?: {
id: string,
text?: string
},
callbackQuery?: {
id: string,
data: string,
messageId: string
}
}WhatsAppAdapter (Coming Soon)
Placeholder for WhatsApp Business API integration.
SMSAdapter (Coming Soon)
Placeholder for SMS integration via Twilio/Vonage.
Multi-Channel Support
Option 1: Using Router (Recommended)
Handle multiple channels with shared bot logic using the built-in Router:
import {
createRouter,
TelegramAdapter,
WebchatAdapter
} from '@rizzclub/channels';
// Shared bot setup
function setupBot(bot) {
bot.command('start', (ctx) => {
return ctx.reply(`Welcome to ${ctx.channel}!`);
});
bot.on('message:text', (ctx) => {
return ctx.reply(`[${ctx.channel}] You said: ${ctx.text}`);
});
}
// Cloudflare Worker
export default {
async fetch(request: Request, env: Env) {
const router = createRouter()
.route('/telegram/webhook', new TelegramAdapter({ token: env.TELEGRAM_TOKEN }), setupBot)
.route('/webchat/webhook', new WebchatAdapter({ webhookSecret: env.WEBHOOK_SECRET }), setupBot);
return router.handleRequest(request);
}
};Option 2: Manual Routing
import {
Bot,
TelegramAdapter,
WebchatAdapter,
type ChannelAdapter
} from '@rizzclub/channels';
// Shared bot logic
function createBot(adapter: ChannelAdapter) {
const bot = new Bot(adapter);
bot.command('start', (ctx) => {
return ctx.reply(`Welcome to ${ctx.channel}!`);
});
bot.on('message:text', (ctx) => {
return ctx.reply(`[${ctx.channel}] You said: ${ctx.text}`);
});
return bot;
}
// Cloudflare Worker
export default {
async fetch(request: Request, env: Env) {
const url = new URL(request.url);
// Telegram webhook
if (url.pathname === '/telegram') {
const bot = createBot(
new TelegramAdapter({ token: env.TELEGRAM_TOKEN })
);
return bot.handleWebhook(request);
}
// Webchat webhook
if (url.pathname === '/webchat') {
const bot = createBot(
new WebchatAdapter({ webhookSecret: env.WEBHOOK_SECRET })
);
return bot.handleWebhook(request);
}
return new Response('Not Found', { status: 404 });
}
};Inline Keyboards
Create interactive inline keyboards:
bot.command('menu', (ctx) => {
return ctx.reply('Choose an option:', {
replyMarkup: {
inlineKeyboard: [
[
{ text: '✅ Option 1', callbackData: 'opt1' },
{ text: '❌ Option 2', callbackData: 'opt2' }
],
[
{ text: '🔗 Visit Website', url: 'https://rizz.club' }
]
]
}
});
});
bot.callbackQuery('opt1', async (ctx) => {
await ctx.answerAlert('You chose Option 1!');
await ctx.editMessageText('Option 1 selected ✅');
});Reply Keyboards
Create reply keyboards (Telegram):
bot.command('keyboard', (ctx) => {
return ctx.reply('Choose a category:', {
replyMarkup: {
keyboard: [
[{ text: '📱 Tech' }, { text: '🎮 Gaming' }],
[{ text: '🎨 Art' }, { text: '🎵 Music' }]
],
resizeKeyboard: true,
oneTimeKeyboard: true
}
});
});Middleware
Add custom middleware for logging, authentication, etc:
// Logging middleware
bot.use(async (ctx, next) => {
console.log(`Incoming from ${ctx.channel}: ${ctx.text}`);
await next();
});
// Auth middleware
bot.use(async (ctx, next) => {
const userId = ctx.from?.id;
if (!userId) return;
const isAuthorized = await checkAuth(userId);
if (!isAuthorized) {
return ctx.reply('Unauthorized');
}
await next();
});TypeScript
Full TypeScript support with type inference:
import { Bot, Context, TelegramAdapter } from '@rizzclub/channels';
const adapter = new TelegramAdapter({ token: 'token' });
const bot = new Bot(adapter);
bot.on('message:text', (ctx: Context) => {
// ctx.text is automatically typed as string | undefined
if (ctx.text) {
console.log(ctx.text.toUpperCase());
}
});Comparison with Grammy
@rizzclub/channels provides the same API as grammy while supporting multiple channels:
| Feature | Grammy | @rizzclub/channels |
|---|---|---|
| Telegram | ✅ | ✅ |
| Webchat | ❌ | ✅ |
| ❌ | 🚧 Coming soon | |
| SMS | ❌ | 🚧 Coming soon |
| API compatibility | - | 100% |
| TypeScript | ✅ | ✅ |
| Cloudflare Workers | ✅ | ✅ |
License
MIT
Contributing
Contributions welcome! Please open an issue or PR.