π¨ MultiChannelAlert - Kien Nguyen Support
π― The Ultimate Multi-Channel Alert & Notification System
Send alerts to 15+ platforms simultaneously with zero dependencies!
π± Supported Platforms
A comprehensive MultiChannelAlert system and utilities package for logging, notifications, and webhook management with enhanced formatting and smart routing.
Installation
npm install kien-nguyen-supportπ Why MultiChannelAlert?
π BeforeMultiple libraries, complex setup
telegram-bot-api
|
β¨ AfterOne simple import, zero dependencies
const { MultiChannelAlert }
|
π¨ MultiChannelAlert - Core Features
π― ONE API β 15+ PLATFORMS
"Write once, alert everywhere!"
π Key Highlights
- π¨ MultiChannelAlert: Send alerts to 15+ platforms simultaneously (Telegram, Slack, Mattermost, Discord, Email, WhatsApp, Zalo, LINE, Viber, Skype, WeChat, RocketChat, Firebase, N8n, Messenger)
- π― Logger-Style API: Clean constructor pattern with
.error(),.info(),.warn(),.success()methods - π Smart ID Extraction: Automatically extract and display IDs in copyable code blocks
- π Enhanced Formatting: Rich formatting with emojis, proper JSON display, platform-specific markdown, and code blocks for curl commands
- βοΈ Conditional Channels: Initialize only channels with available configurations
- π Dynamic Management: Add/remove channels at runtime with graceful error handling
- ποΈ Individual StrictMode: Filter data per channel with
strictModeparameter for sensitive data protection - π Configuration Inheritance: Channel-specific settings override global configurations
- π¨ Cross-Platform Formatting: Consistent rich formatting across Telegram (Markdown), Mattermost (Markdown), Slack (Blocks), Discord (Embeds)
β‘ Performance & Optimization
- Zero Dependencies: No external runtime dependencies - uses only Node.js built-ins
- 85% Smaller Package: Reduced from ~585KB to ~85KB by replacing axios & moment.js
- Native HTTP Client: Custom implementation with axios-compatible API
- Custom DateTime Utils: Native Date formatting without external libraries
- Fast Installation: No dependency resolution or security vulnerabilities
- Production Ready: Lightweight, secure, and maintainable
π± Live Demo Screenshots
Demo with Telegram and Mattermost
Real-time alerts with rich formatting, ID extraction, and smart routing:
Live examples showing enhanced formatting, automatic ID extraction, and multi-channel broadcasting
π― 4 Core Features
- π¨ MultiChannelAlert System: Send notifications to 15+ platforms simultaneously - Telegram, Slack, Mattermost, Discord, Email, WhatsApp, Zalo, LINE, Viber, Skype, WeChat, RocketChat, Firebase, N8n, Messenger
- π Third-Party Log: Save HTTP request/response logs and curl commands with provider-specific formatting
- π Telegram Webhook: Production webhook management with fallback and auto-recovery
- π― Smart Routing: Automatic thread/channel routing based on service and environment using nested object access
β‘ 30-Second Demo
// π¨ ONE LINE β 15+ PLATFORMS
const multiAlert = new MultiChannelAlert({
channels: [
{ type: 'telegram', config: { /* telegram config */ } },
{ type: 'slack', config: { /* slack config */ } },
{ type: 'discord', config: { /* discord config */ } },
{ type: 'email', config: { /* email config */ } },
// ... add 11+ more platforms
]
})
// Send error alert to ALL channels simultaneously β‘
multiAlert.error('Payment system down!', {
userId: 'U123456',
amount: 999.99
})
// Result: 15+ notifications sent instantly! ππ₯ 15+ Platforms β’ Zero Dependencies β’ One Simple API π₯
ποΈ Advanced Data Filtering & Formatting
π StrictMode Data Filtering
Control exactly which data fields are sent to each platform:
const multiAlert = new MultiChannelAlert({
channels: [
{
type: 'telegram',
config: {
botToken: 'your-token',
chatId: 'your-chat-id',
strictMode: true // Enable filtering for this channel
}
},
{
type: 'mattermost',
config: {
apiUrl: 'your-api-url',
token: 'your-token',
channelId: 'your-channel-id'
// No strictMode - will send all data
}
}
],
specific: [
{ key: 'user', title: 'π€ User', markdown: true },
{ key: 'method', title: 'π¨ Method', markdown: true },
{ key: 'status', title: 'π Status', markdown: true },
{ key: 'error_code', title: 'π΄ Error Code', markdown: true },
{ key: 'curl', title: 'π» cURL Command', markdown: true }
],
strictMode: false // Global setting (can be overridden per channel)
})
// Full data object
const alertData = {
user: 'john_doe',
method: 'POST',
status: 500,
error_code: 'DB_CONNECTION_FAILED',
curl: 'curl -X POST https://api.example.com/users',
internal_debug: 'This sensitive data', // Won't be sent if strictMode=true
server_logs: 'Internal server information'
}
// Telegram will only receive: user, method, status, error_code, curl
// Mattermost will receive all fields (including internal_debug, server_logs)
await multiAlert.error(alertData)π¨ Enhanced Message Formatting
Rich formatting with platform-specific optimizations:
Telegram Output:
**π€ User:**john_doe
**π¨ Method:**POST
**π» cURL Command:**curl -X POST https://api.example.com/users
Mattermost Output:
------------------------
[From Mattermost Bot Alert]
π¨ Environment: PRODUCTION
**π€ User:** `john_doe`
**π¨ Method:** `POST`
**π» cURL Command:**
```bash
curl -X POST https://api.example.com/users
### π§ Individual Component StrictMode
Use individual alert components with their own filtering:
```javascript
// Individual components with their own strictMode
const telegramAlert = new TelegramAlert({
botToken: 'your-token',
chatId: 'your-chat-id',
strictMode: true // This component will filter data
})
const slackAlert = new SlackAlert({
webhookUrl: 'your-webhook-url'
// No strictMode - sends all data
})
// Same data, different filtering per component
const data = { user: 'john', secret: 'hidden', method: 'POST' }
const specific = [{ key: 'user', title: 'π€ User' }, { key: 'method', title: 'π¨ Method' }]
await telegramAlert.error(data) // Only sends: user, method (if specific is provided)
await slackAlert.error(data) // Sends all: user, secret, methodQuick Start
const {
MultiChannelAlert,
TelegramAlert,
SlackAlert,
saveProviderLog,
createTelegramWebhookClient
} = require('kien-nguyen-support')
// Feature 1: Multi-Channel Alerts (NEW in v2.0.0)
const multiAlert = new MultiChannelAlert({
channels: [
{
type: 'telegram',
config: {
botToken: process.env.TELEGRAM_BOT_TOKEN,
chatId: process.env.TELEGRAM_CHAT_ID,
service: 'hotel'
}
},
{
type: 'slack',
config: {
webhookUrl: process.env.SLACK_WEBHOOK_URL,
service: 'hotel'
}
}
],
environment: 'PRODUCTION'
})
// Send to all channels at once
await multiAlert.error({
user_id: '123',
booking_id: 'BK456',
error_code: 'PAYMENT_FAILED',
message: 'Payment processing failed'
})
// Feature 2: Individual Alert Channels
const telegram = new TelegramAlert({
botToken: process.env.TELEGRAM_BOT_TOKEN,
chatId: process.env.TELEGRAM_CHAT_ID,
service: 'hotel'
})
await telegram.error({ error_message: 'Hello from Telegram!' })
// Feature 3: Third-Party Logging
await saveProviderLog({
action: 'search',
req: requestData,
res: responseData,
code: 'EXPEDIA',
name: 'search-hotels'
})
// Feature 4: Telegram Webhook
const webhook = createTelegramWebhookClient({ /* config */ })
await webhook.setWebhook()Feature 1: Multi-Channel Alerts π
Send alerts to multiple platforms simultaneously with a single command.
MultiChannelAlert Class (NEW)
const { MultiChannelAlert } = require('kien-nguyen-support')
// Initialize with multiple channels
const multiAlert = new MultiChannelAlert({
channels: [
{
type: 'telegram',
config: {
botToken: 'your-bot-token',
chatId: 'your-chat-id',
service: 'hotel'
}
},
{
type: 'mattermost',
config: {
url: 'https://mattermost.example.com',
token: 'access-token',
chatId: 'channel-id',
service: 'hotel'
}
},
{
type: 'slack',
config: {
webhookUrl: 'https://hooks.slack.com/...',
service: 'hotel'
}
},
{
type: 'email',
config: {
host: 'smtp.gmail.com',
port: 587,
auth: {
user: 'alerts@company.com',
pass: 'app-password'
},
from: 'alerts@company.com',
to: 'team@company.com',
service: 'hotel'
}
}
],
service: 'hotel',
environment: 'PRODUCTION',
failSilently: true // Continue if some channels fail
})
// Send alerts using logger-style methods
await multiAlert.error({
user_id: '123',
booking_id: 'BK456',
error_code: 'PAYMENT_FAILED',
message: 'Payment processing failed',
amount: 150,
currency: 'USD'
})
await multiAlert.info({
deployment: 'v2.0.0',
status: 'success',
message: 'Deployment completed successfully'
})
await multiAlert.warn({
cpu_usage: '85%',
memory_usage: '78%',
message: 'High resource usage detected'
})
await multiAlert.success({
payment_id: 'PAY123',
amount: 150,
message: 'Payment processed successfully'
})π― Configuration Inheritance & Data Filtering (NEW)
MultiChannelAlert now supports advanced configuration inheritance and data filtering:
const multiAlert = new MultiChannelAlert({
// Global configuration
service: 'flight',
environment: 'PRODUCTION',
beauty: true,
specific: [
{ field: 'error', markdown: false },
{ field: 'message', markdown: true }
],
strictMode: true, // Enable data filtering
channels: [
{
type: 'telegram',
config: {
botToken: 'bot-token',
chatId: 'chat-id',
// Channel overrides: add timestamp field
specific: [
{ field: 'error', markdown: false },
{ field: 'message', markdown: true },
{ field: 'timestamp', markdown: false }
]
}
},
{
type: 'slack',
config: {
webhookUrl: 'webhook-url'
// Uses global specific: only error + message
}
}
]
})
// Test data with many fields
const alertData = {
error: 'Flight API timeout',
message: 'Booking system down',
timestamp: '2024-01-01T10:00:00Z',
userId: 'user123', // Will be filtered out
sessionId: 'session456', // Will be filtered out
metadata: { extra: 'info' } // Will be filtered out
}
await multiAlert.error(alertData)
// β
Telegram receives: error, message, timestamp (3 fields)
// β
Slack receives: error, message (2 fields)
// β Other fields filtered out due to strictMode: trueConfiguration Inheritance Rules:
- Channel config overrides Global config overrides Default values
strictMode: trueβ Only fields inspecific[]are sentstrictMode: falseβ All fields are sent regardless ofspecific[]- Channel-level
specific[]overrides globalspecific[]
Benefits:
- π― Selective Logging: Only log relevant fields per channel
- π Data Privacy: Filter sensitive fields from certain channels
- β‘ Performance: Reduce message size by filtering unnecessary data
- ποΈ Flexibility: Different field sets per channel type
Conditional Channel Initialization
Only initialize channels that have available configuration:
const channels = []
// Add Telegram if configured
if (process.env.TELEGRAM_BOT_TOKEN && process.env.TELEGRAM_CHAT_ID) {
channels.push({
type: 'telegram',
config: {
botToken: process.env.TELEGRAM_BOT_TOKEN,
chatId: process.env.TELEGRAM_CHAT_ID,
service: 'hotel'
}
})
}
// Add Slack if configured
if (process.env.SLACK_WEBHOOK_URL) {
channels.push({
type: 'slack',
config: {
webhookUrl: process.env.SLACK_WEBHOOK_URL,
service: 'hotel'
}
})
}
// Add Mattermost if configured
if (process.env.MATTERMOST_URL && process.env.MATTERMOST_TOKEN) {
channels.push({
type: 'mattermost',
config: {
url: process.env.MATTERMOST_URL,
token: process.env.MATTERMOST_TOKEN,
chatId: process.env.MATTERMOST_CHAT_ID,
service: 'hotel'
}
})
}
const multiAlert = new MultiChannelAlert({
channels,
service: 'hotel',
environment: 'PRODUCTION'
})
// This will only send to channels that were successfully initialized
const result = await multiAlert.error({ message: 'Test error' })
console.log(`Sent to ${result.summary.successful}/${result.summary.total} channels`)π― Individual Component StrictMode (NEW)
Each alert component now supports individual strictMode for data filtering:
const { TelegramAlert, SlackAlert, MattermostAlert } = require('kien-nguyen-support')
// TelegramAlert with strictMode
const telegramAlert = new TelegramAlert({
botToken: 'your-bot-token',
chatId: 'your-chat-id',
specific: [
{ field: 'error', markdown: false },
{ field: 'message', markdown: true }
],
strictMode: true // Enable data filtering
})
// SlackAlert with strictMode
const slackAlert = new SlackAlert({
webhookUrl: 'your-webhook-url',
specific: [
{ key: 'error', title: 'Error' },
{ key: 'user_id', title: 'User ID' }
],
strictMode: true // Enable data filtering
})
// MattermostAlert with strictMode
const mattermostAlert = new MattermostAlert({
apiUrl: 'your-mattermost-api-url',
token: 'your-token',
channelId: 'your-channel-id',
specific: [
{ field: 'error' },
{ field: 'message' },
{ field: 'user_id' }
],
strictMode: true // Enable data filtering
})
// Test data with many fields
const alertData = {
error: 'System failure',
message: 'Database error',
user_id: 'user_123',
session_id: 'session_456', // Will be filtered out
ip_address: '192.168.1.1', // Will be filtered out
metadata: { extra: 'info' } // Will be filtered out
}
await telegramAlert.error(alertData)
// β
Sends only: error, message
await slackAlert.error(alertData)
// β
Sends only: error, user_id
await mattermostAlert.error(alertData)
// β
Sends only: error, message, user_idBenefits of Individual StrictMode:
- π― Selective Data: Filter data without MultiChannelAlert
- π Privacy Control: Remove sensitive fields per component
- β‘ Performance: Reduce message payload size
- ποΈ Flexibility: Different filtering per alert type
Individual Alert Classes
You can also use individual alert classes directly:
1. TelegramAlert
Setup Requirements:
Create a Telegram Bot:
- Message @BotFather on Telegram
- Send
/newbotand follow instructions - Get your
botToken
Get Chat ID:
- Add your bot to a group/channel
- Send a message to the group
- Visit
https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getUpdates - Find
chat.idin the response
const { TelegramAlert } = require('kien-nguyen-support')
const telegram = new TelegramAlert({
botToken: 'your-bot-token', // From @BotFather
chatId: 'your-chat-id', // From getUpdates API
service: 'hotel', // For thread routing
environment: 'PRODUCTION', // Environment context
messageThreadIds: { // Optional: thread routing
'hotel.error.all': 30,
'hotel.info.all': 31,
general: 9
}
})
await telegram.error({ message: 'Error occurred' })2. SlackAlert
Setup Requirements:
Create a Slack App:
- Go to api.slack.com/apps
- Click "Create New App"
- Choose "From scratch"
Enable Incoming Webhooks:
- Go to "Incoming Webhooks" in your app settings
- Toggle "Activate Incoming Webhooks" to On
- Click "Add New Webhook to Workspace"
- Select channel and copy webhook URL
const { SlackAlert } = require('kien-nguyen-support')
const slack = new SlackAlert({
webhookUrl: 'https://hooks.slack.com/services/...', // From Slack App
service: 'hotel', // For channel routing
environment: 'PRODUCTION', // Environment context
channels: { // Optional: channel routing
'hotel.error.all': '#hotel-errors',
'hotel.info.all': '#hotel-info',
general: '#general'
}
})
await slack.error({ message: 'Error occurred' })3. MattermostAlert
Setup Requirements:
Create Personal Access Token:
- Go to Mattermost β Account Settings β Security
- Click "Create New Token"
- Give it a description and copy the token
Get Channel ID:
- Go to channel β View Info β Copy channel ID
- Or use channel name (e.g., "town-square")
const { MattermostAlert } = require('kien-nguyen-support')
const mattermost = new MattermostAlert({
url: 'https://your-mattermost.com', // Mattermost server URL
token: 'your-access-token', // Personal access token
chatId: 'channel-id-or-name', // Channel ID or name
service: 'hotel', // For channel routing
environment: 'PRODUCTION' // Environment context
})
await mattermost.error({ message: 'Error occurred' })4. EmailAlert
Setup Requirements:
- SMTP Configuration (Gmail example):
- Enable 2FA on Gmail
- Generate App Password: Account β Security β App passwords
- Use app password (not your regular password)
const { EmailAlert } = require('kien-nguyen-support')
const email = new EmailAlert({
host: 'smtp.gmail.com', // SMTP host
port: 587, // SMTP port
secure: false, // Use TLS
auth: {
user: 'your-email@gmail.com', // Your email
pass: 'your-app-password' // Gmail app password (not regular password)
},
from: 'alerts@company.com', // From address
to: 'team@company.com', // To address(es)
service: 'hotel', // For subject line
environment: 'PRODUCTION' // Environment context
})
await email.error({ message: 'Error occurred' })5. DiscordAlert
Setup Requirements:
- Create Discord Webhook:
- Go to Discord channel β Settings β Integrations
- Click "Create Webhook"
- Copy webhook URL
const { DiscordAlert } = require('kien-nguyen-support')
const discord = new DiscordAlert({
webhookUrl: 'https://discord.com/api/webhooks/...', // Discord webhook URL
service: 'hotel', // For embed title
environment: 'PRODUCTION' // Environment context
})
await discord.error({ message: 'Error occurred' })6. ZaloAlert
Setup Requirements:
Create Zalo OA (Official Account):
- Go to developers.zalo.me
- Create Official Account
- Get access token from OA settings
Get User ID:
- User must follow your OA
- Use Zalo API to get follower user IDs
const { ZaloAlert } = require('kien-nguyen-support')
const zalo = new ZaloAlert({
accessToken: 'your-oa-access-token', // OA access token
userId: 'user-id', // Zalo user ID
service: 'hotel', // For message context
environment: 'PRODUCTION' // Environment context
})
await zalo.error({ message: 'Error occurred' })7. MessengerAlert
Setup Requirements:
Create Facebook App:
- Go to developers.facebook.com
- Create new app β Business
- Add Messenger product
Get Page Access Token:
- Go to Messenger β Settings
- Generate page access token
- Get recipient PSID from webhook events
const { MessengerAlert } = require('kien-nguyen-support')
const messenger = new MessengerAlert({
pageAccessToken: 'your-page-access-token', // Facebook page access token
recipientId: 'user-psid', // User's PSID
service: 'hotel', // For message context
environment: 'PRODUCTION' // Environment context
})
await messenger.error({ message: 'Error occurred' })8. N8nAlert
Setup Requirements:
- Create N8n Webhook:
- In N8n workflow, add "Webhook" node
- Set HTTP Method to POST
- Copy the webhook URL
const { N8nAlert } = require('kien-nguyen-support')
const n8n = new N8nAlert({
webhookUrl: 'https://your-n8n.com/webhook/...', // N8n webhook URL
service: 'hotel', // For workflow context
environment: 'PRODUCTION' // Environment context
})
await n8n.error({ message: 'Error occurred' })Feature 2: Third-Party Log (HTTP Request Logging)
Save API request/response logs and curl commands to organized files:
const { saveProviderLog, saveProviderCurl } = require('kien-nguyen-support')
// Save request/response logs
await saveProviderLog({
action: 'search', // Action name
req: requestData, // Request object/string (JSON or XML)
res: responseData, // Response object/string (JSON or XML)
code: 'EXPEDIA', // Provider/supplier code
name: 'search-hotels' // Operation name
})
// Save curl command for debugging
await saveProviderCurl({
name: 'search-hotels', // Operation name
request: { // Request object
method: 'POST',
url: 'https://api.expedia.com/search',
headers: { 'Content-Type': 'application/json' },
body: { destination: 'Bangkok' }
},
code: 'EXPEDIA', // Provider code
action: 'search' // Action name (optional)
})Files are automatically saved to:
- Request/Response:
../logs/logs_YYYY-MM-DD/TIMESTAMP_CODE_NAME_ACTION_req.json - Curl commands:
../curl_logs/logs_YYYY-MM-DD/TIMESTAMP_CODE_NAME_ACTION_curl.txt
Feature 3: Telegram Bot (Legacy - Backward Compatibility)
TelegramClient Class (Recommended)
Pre-configured client with smart thread routing:
const { TelegramClient } = require('kien-nguyen-support')
/**
* Initialize TelegramClient
* Required config:
* - botToken: Telegram bot token
* - chatId: Chat ID to send messages to
*
* Optional config:
* - service: Default service type (hotel, flight, tour, transfer)
* - environment: Default environment (DEV, STAGING, PROD)
* - messageThreadIds: Thread routing configuration (nested object structure)
* - disableNotification: Disable notifications (default: false)
* - timeout: Request timeout in ms (default: 5000)
*/
const telegram = new TelegramClient({
botToken: process.env.TELEGRAM_BOT_TOKEN, // Required
chatId: process.env.TELEGRAM_CHAT_ID, // Required
service: 'hotel', // Optional
environment: 'PROD', // Optional
messageThreadIds: { // Optional - nested object structure
general: 17,
hotel: {
system: {
all: 17,
search: 19,
offer_search: 19,
prebook: 21,
book: 23,
cancel: 25
},
third_party: {
all: 28,
search: 30,
prebook: 32,
book: 34,
cancel: 36
}
},
flight: {
system: {
search: 5038,
'confirm-tax': 5039,
'generate-pnr': 5042
},
third_party: {
search: 3561,
'confirm-tax': 5050
}
},
flight: {
system: {
search: 5038,
'confirm-tax': 5039,
'generate-pnr': 5042
},
third_party: {
search: 3561,
'confirm-tax': 5050
}
}
},
disableNotification: false, // Optional
timeout: 10000 // Optional
})
/**
* Send message - options parameter structure
* Required: error_message
* Optional: All other fields for metadata and routing
*/
await telegram.sendMessage({
error_message: 'Hello World!' // Required - message text
})
/**
* Send error alert with auto thread routing and enhanced formatting
* Thread routing: service.type.metric β nested object access β general fallback
*
* β¨ NEW: Automatic ID extraction and rich formatting!
*/
await telegram.sendErrorAlert({
// Core error info
error_message: 'Failed to book hotel', // Required
error_code: 'BOOKING_FAILED', // Optional
// Routing (auto-detects thread using nested object access)
// Example: messageThreadIds.hotel.third_party.book = 34
type: 'third_party', // 'system' or 'third_party'
metric: 'book', // For thread routing
// Context (optional)
user_email: 'user@example.com',
supplier: {
code: 'EXPEDIA',
id: 123,
source_id: 'EXP001'
},
// π Enhanced request metadata with ID extraction
request_metadata: {
bookingId: 'ABC123',
search_id: 'd8e2048ba1974f568a807532752e452f', // Auto-extracted!
trace_id: 'trace-12345', // Auto-extracted!
log_id: '63b5c9faf56fc04fdf2509b3874cb6d4' // Auto-extracted!
},
error_stack: error.stack, // π Auto-truncated to 2 lines
metadata: { additional: 'data' } // Any extra metadata
})Factory Function (Alternative)
const { createTelegramClient } = require('kien-nguyen-support')
const telegramClient = createTelegramClient({
botToken: process.env.TELEGRAM_BOT_TOKEN,
chatId: process.env.TELEGRAM_CHAT_ID,
messageThreadIds: { /* thread config */ }
})
await telegramClient.sendMessage({ error_message: 'Hello!' })})
π― Smart Thread Routing (v2.2.0)
The new nested object structure provides better organization and type safety:
// Old underscore pattern (deprecated)
messageThreadIds: {
'hotel_system_search': 19,
'hotel_system_book': 23,
'hotel_third_party_search': 30
}
// New nested object structure (recommended)
messageThreadIds: {
general: 17, // Global fallback
hotel: {
system: {
all: 17, // Service-specific fallback
search: 19, // Specific metric
book: 23
},
third_party: {
all: 28,
search: 30,
book: 34
}
},
flight: {
system: { search: 5038 },
third_party: { search: 3561 }
}
}Routing Priority:
messageThreadIds.{service}.{type}.{metric}- Most specificmessageThreadIds.{service}.{type}.all- Service + type fallbackmessageThreadIds.{service}.{type}.general- Service + type generalmessageThreadIds.general- Global fallback
Example: service: 'hotel', type: 'system', metric: 'search'
β Looks for messageThreadIds.hotel.system.search = 19
Feature 4: Telegram Webhook (Production Setup)
Manage webhooks for production deployment:
const { createTelegramWebhookClient } = require('kien-nguyen-support')
/**
* Initialize webhook client
* Required config:
* - botToken: Telegram bot token
* - webhookUrl: URL for webhook endpoint
*
* Optional config:
* - secretToken: Secret token for verification
* - allowedUpdates: Array of update types to receive
* - maxConnections: Max simultaneous connections
* - timeout: Request timeout in ms
*/
const webhookClient = createTelegramWebhookClient({
botToken: process.env.TELEGRAM_BOT_TOKEN, // Required
webhookUrl: process.env.WEBHOOK_URL, // Required
secretToken: process.env.WEBHOOK_SECRET_TOKEN, // Optional but recommended
allowedUpdates: ['message', 'callback_query'], // Optional
maxConnections: 100, // Optional
timeout: 10000 // Optional
})
// Set webhook
await webhookClient.setWebhook()
// Get webhook info
const info = await webhookClient.getWebhookInfo()
console.log('Webhook status:', info.url)
// Delete webhook
await webhookClient.deleteWebhook()
// Verify incoming webhook requests
app.post('/telegram-webhook', (req, res) => {
const secretToken = req.headers['x-telegram-bot-api-secret-token']
if (!webhookClient.verifyRequest(secretToken)) {
return res.status(401).send('Unauthorized')
}
const update = webhookClient.parseUpdate(req.body)
if (update.message) {
console.log('Received message:', update.message.text)
}
res.sendStatus(200)
})Smart Thread Routing
Configure automatic message routing to specific Telegram threads:
const messageThreadIds = {
// General fallback
general: 9,
// Hotel system
hotel_system_search: 19,
hotel_system_book: 23,
// Hotel third-party
hotel_third_party_search: 30,
hotel_third_party_book: 34,
// Flight system
flight_system_search: 41,
flight_system_book: 43,
// Tour/Transfer
tour_system_search: 51,
transfer_system_book: 73
}Routing Logic: {product}_{type}_{metric} β Falls back to general
Examples:
hotel+third_party+bookβhotel_third_party_book(34)flight+system+searchβflight_system_search(41)- Unknown combination β
general(9)
Usage Patterns
Pattern 1: Multi-Channel Alert System (Recommended)
Create a shared multi-channel client for your entire project:
// config/alert-client.js
const { MultiChannelAlert } = require('kien-nguyen-support')
// Initialize channels based on available environment variables
const channels = []
if (process.env.TELEGRAM_BOT_TOKEN && process.env.TELEGRAM_CHAT_ID) {
channels.push({
type: 'telegram',
config: {
botToken: process.env.TELEGRAM_BOT_TOKEN,
chatId: process.env.TELEGRAM_CHAT_ID,
service: 'hotel'
}
})
}
if (process.env.SLACK_WEBHOOK_URL) {
channels.push({
type: 'slack',
config: {
webhookUrl: process.env.SLACK_WEBHOOK_URL,
service: 'hotel'
}
})
}
if (process.env.MATTERMOST_URL && process.env.MATTERMOST_TOKEN) {
channels.push({
type: 'mattermost',
config: {
url: process.env.MATTERMOST_URL,
token: process.env.MATTERMOST_TOKEN,
chatId: process.env.MATTERMOST_CHAT_ID,
service: 'hotel'
}
})
}
const alertClient = new MultiChannelAlert({
channels,
service: 'hotel',
environment: process.env.NODE_ENV || 'STAGING',
failSilently: true
})
module.exports = alertClient
// services/hotel-service.js
const alertClient = require('../config/alert-client')
async function bookHotel(hotelData) {
try {
const booking = await processHotelBooking(hotelData)
// Success alert to all channels
await alertClient.success({
booking_id: booking.id,
user_email: hotelData.userEmail,
amount: booking.amount,
currency: booking.currency,
message: `Hotel booking successful: ${booking.id}`
})
return booking
} catch (error) {
// Error alert to all channels
await alertClient.error({
error_code: 'BOOKING_FAILED',
message: error.message,
user_email: hotelData.userEmail,
booking_data: hotelData,
error_stack: error.stack
})
throw error
}
}Pattern 2: Service-Specific Alert Clients
// services/flight-service.js
const { TelegramAlert, SlackAlert } = require('kien-nguyen-support')
// Flight-specific Telegram alerts
const flightTelegram = new TelegramAlert({
botToken: process.env.TELEGRAM_BOT_TOKEN,
chatId: process.env.FLIGHT_CHAT_ID,
service: 'flight',
environment: 'PRODUCTION',
messageThreadIds: {
'flight.error.all': 31,
'flight.info.all': 33,
general: 9
}
})
// Flight-specific Slack alerts
const flightSlack = new SlackAlert({
webhookUrl: process.env.FLIGHT_SLACK_WEBHOOK,
service: 'flight',
channels: {
'flight.error.all': '#flight-errors',
'flight.info.all': '#flight-info'
}
})
async function searchFlights(searchData) {
try {
await flightTelegram.info({
action: 'search_start',
message: 'Flight search initiated',
search_data: searchData
})
const results = await performFlightSearch(searchData)
await flightSlack.success({
action: 'search_complete',
message: `Found ${results.length} flights`,
search_id: searchData.search_id,
results_count: results.length
})
return results
} catch (error) {
// Send error to both Telegram and Slack
await Promise.allSettled([
flightTelegram.error({
error_code: 'SEARCH_FAILED',
message: error.message,
search_data: searchData
}),
flightSlack.error({
error_code: 'SEARCH_FAILED',
message: error.message,
search_data: searchData
})
])
throw error
}
}π Enhanced Multi-Channel Message Format
With version 2.0.0, all alert channels now include:
Smart ID Extraction
Automatically extracts and displays IDs in copyable code blocks:
π **Search ID:**d8e2048ba1974f568a807532752e452f
π **Trace ID:**trace-12345-abcdef
π **Log ID:**63b5c9faf56fc04fdf2509b3874cb6d4
Rich Formatting with Emojis
- π§ Environment:
PRODUCTION - π Type:
third_party - β Error Code:
BOOKING_FAILED - π Message: Error details in code blocks
- π€ User: User information
- π’ Supplier: Supplier details
- π Request Data: Formatted JSON with proper indentation
- π Stack Trace: Limited to first 2 lines for readability
Example Enhanced Message Output
π§ Environment: `PRODUCTION`
π Type: `third_party`
β Error Code: `BOOKING_FAILED`
π Message:Failed to book hotel room
π Search ID:d8e2048ba1974f568a807532752e452f
π Request Data:
```json
{
"adults": 2,
"children": 0,
"departure_date": "2025-09-29",
"search_id": "d8e2048ba1974f568a807532752e452f"
}π Stack Trace:
BookingError: Room not available
at bookRoom (/app/services/booking.js:145:12)
## π§ Troubleshooting & Best Practices
### β Common Issues
#### "message text is empty" Error (Telegram)
**Cause:** StrictMode filtering resulted in empty data or missing required fields.
**Solution:**
```javascript
// β Wrong: No matching fields in specific configuration
const specific = [
{ key: 'user_name', title: 'User' } // But data has 'user', not 'user_name'
]
const data = { user: 'john', method: 'POST' }
// β
Correct: Match field keys exactly
const specific = [
{ key: 'user', title: 'π€ User' }, // Matches data.user
{ key: 'method', title: 'π¨ Method' } // Matches data.method
]No Data Filtering with StrictMode
Cause: strictMode is enabled but no specific configuration provided.
Solution:
// β Wrong: strictMode=true but no specific config
const alert = new TelegramAlert({
botToken: 'token',
chatId: 'chat',
strictMode: true // Will return original data if no specific config
})
// β
Correct: Provide specific configuration
const alert = new TelegramAlert({
botToken: 'token',
chatId: 'chat',
strictMode: true,
specific: [
{ key: 'user', title: 'π€ User' },
{ key: 'error_code', title: 'π΄ Error' }
]
})π― Best Practices
1. Field Naming Consistency
// β
Use consistent field names across your application
const standardFields = [
{ key: 'user', title: 'π€ User' },
{ key: 'method', title: 'π¨ Method' },
{ key: 'status', title: 'π Status' },
{ key: 'error_code', title: 'π΄ Error Code' },
{ key: 'curl', title: 'π» cURL Command' }
]2. Sensitive Data Protection
// β
Use strictMode for production channels
const productionAlert = new MultiChannelAlert({
channels: [
{
type: 'telegram',
config: {
botToken: process.env.TELEGRAM_TOKEN,
chatId: process.env.TELEGRAM_CHAT_ID,
strictMode: true // Filter sensitive data
}
}
],
specific: [
{ key: 'user', title: 'π€ User' },
{ key: 'error_code', title: 'π΄ Error' }
// Sensitive fields like passwords, tokens are automatically excluded
]
})3. Platform-Specific Formatting
// β
Let the library handle platform-specific formatting
const data = {
user: 'john_doe',
metadata: { session_id: '123', ip: '192.168.1.1' }, // Object - auto JSON formatted
curl: 'curl -X POST https://api.com', // Auto code block
error_stack: 'Error\n at function()\n at ...' // Auto truncated
}
// Library automatically formats:
// - Objects as JSON code blocks
// - Curl commands as bash code blocks
// - Stack traces with truncation
// - Titles with emojis4. Configuration Inheritance
// β
Use global config with channel overrides
const multiAlert = new MultiChannelAlert({
channels: [
{
type: 'telegram',
config: {
botToken: 'token',
chatId: 'chat-id',
specific: [ // Override global specific for this channel
{ key: 'user', title: 'π€ User' },
{ key: 'error_code', title: 'π΄ Error' }
]
}
},
{
type: 'slack',
config: {
webhookUrl: 'webhook-url'
// Uses global specific configuration
}
}
],
specific: [ // Global configuration
{ key: 'user', title: 'π€ User' },
{ key: 'method', title: 'π¨ Method' },
{ key: 'status', title: 'π Status' }
],
strictMode: true
})API Reference
Multi-Channel Alerts
new MultiChannelAlert(config)
Create a multi-channel alert instance.
Config Parameters:
channels(Array, required): Array of channel configurationsservice(string, optional): Default service name ('hotel', 'flight', 'tour', 'transfer')environment(string, optional): Default environment ('DEV', 'STAGING', 'PRODUCTION')failSilently(boolean, optional): Don't throw errors if some channels fail (default: true)
Channel Configuration:
{
type: 'telegram', // Channel type (required)
config: { // Channel-specific config (required)
// Channel-specific parameters
botToken: 'token',
chatId: 'chat-id',
service: 'hotel', // Inherits from main config if not provided
environment: 'PROD' // Inherits from main config if not provided
}
}Logger Methods
// Error alert (red/urgent styling)
await multiAlert.error(data)
// Info alert (blue/informational styling)
await multiAlert.info(data)
// Warning alert (yellow/caution styling)
await multiAlert.warn(data)
// Success alert (green/positive styling)
await multiAlert.success(data)Management Methods
// Get channel information
multiAlert.getChannels() // Array of channel info
multiAlert.getChannelCount() // Number of channels
multiAlert.hasChannel('telegram') // Check if type exists
// Dynamic management
multiAlert.addChannel(config) // Add new channel
multiAlert.removeChannel('slack') // Remove by typeResponse Format
{
success: true, // True if at least 1 channel succeeded
results: [ // Array of individual results
{
type: 'telegram',
success: true,
result: { /* telegram response */ }
},
{
type: 'slack',
success: false,
error: 'Webhook URL invalid'
}
],
errors: [ // Array of failed channels
{
type: 'slack',
success: false,
error: 'Webhook URL invalid'
}
],
summary: { // Summary statistics
total: 2,
successful: 1,
failed: 1
}
}Individual Alert Classes
new TelegramAlert(config)
Required Config:
botToken(string): Telegram bot token from @BotFatherchatId(string): Chat/channel ID where messages will be sent
Optional Config:
service(string): Service name for routing ('hotel', 'flight', etc.)environment(string): Environment context ('DEV', 'STAGING', 'PRODUCTION')messageThreadIds(Object): Thread routing configurationbeauty(boolean): Enable rich formatting (default: true)timeout(number): Request timeout in ms (default: 10000)
new SlackAlert(config)
Required Config:
webhookUrl(string): Slack webhook URL from app configuration
Optional Config:
channel(string): Override channel from webhookservice(string): Service name for routingenvironment(string): Environment contextchannels(Object): Channel routing configurationbeauty(boolean): Enable rich formatting (default: true)
new MattermostAlert(config)
Required Config:
url(string): Mattermost server URLtoken(string): Personal access tokenchatId(string): Channel ID or name
Optional Config:
service(string): Service name for routingenvironment(string): Environment context
new EmailAlert(config)
Required Config:
host(string): SMTP server hostport(number): SMTP server portauth.user(string): SMTP usernameauth.pass(string): SMTP password/app passwordfrom(string): From email addressto(string|Array): Recipient email address(es)
Optional Config:
secure(boolean): Use SSL/TLS (default: false for port 587)service(string): Service name for subject lineenvironment(string): Environment context
Third-Party Logging
saveProviderLog(options)
Save HTTP request/response logs to organized files.
Parameters:
action(string): Action name (e.g., 'search', 'book')req(Object|string): Request data (JSON object or XML string)res(Object|string): Response data (JSON object or XML string)code(string): Provider/supplier code (e.g., 'EXPEDIA')name(string): Operation name (e.g., 'search-hotels')
saveProviderCurl(options)
Save curl command to file for debugging.
Parameters:
name(string): Operation namerequest(Object): Request object with method, url, headers, bodycode(string): Provider/supplier codeaction(string, optional): Action name
TelegramClient Class
new TelegramClient(config)
Create a Telegram client instance.
Config Parameters:
botToken(string, required): Telegram bot tokenchatId(string, required): Chat ID to send messages toproduct(string, optional): Default product type ('hotel', 'flight', 'tour', 'transfer')environment(string, optional): Default environment ('DEV', 'STAGING', 'PROD')messageThreadIds(Object, optional): Thread routing configurationdisableNotification(boolean, optional): Disable notifications (default: false)timeout(number, optional): Request timeout in ms (default: 5000)
telegram.sendMessage(options)
Send message using error-handler.js style options parameter.
Options Parameters:
error_message(string, required): Message text to sendtype(string, optional): Alert type ('system', 'third_party')metric(string, optional): Metric for thread routing- All other fields are optional and used for metadata
telegram.sendErrorAlert(options)
Send error alert with automatic thread routing.
Options Parameters:
error_message(string, required): Error messageerror_code(string, optional): Error codetype(string, optional): 'system' or 'third_party' (default: 'system')metric(string, optional): Metric for thread routing (default: 'general')user_email(string, optional): User emailsupplier(Object, optional): Supplier info with code, id, etc.request_metadata(Object|string, optional): Request metadataerror_stack(string, optional): Error stack trace (auto-truncated)metadata(Object|string, optional): Additional metadata
Webhook Client
createTelegramWebhookClient(config)
Create a webhook client for production.
Config Parameters:
botToken(string, required): Telegram bot tokenwebhookUrl(string, required): Webhook URLsecretToken(string, optional): Secret token for verificationallowedUpdates(Array, optional): Update types to receivemaxConnections(number, optional): Max connectionstimeout(number, optional): Request timeout
Multi-Channel Support
Supported Alert Channels (v2.0.0)
- TelegramAlert: Send alerts to Telegram chats/channels with thread routing
- SlackAlert: Send alerts to Slack channels with rich formatting
- MattermostAlert: Send alerts to Mattermost channels
- EmailAlert: Send HTML/text email alerts via SMTP
- DiscordAlert: Send alerts to Discord channels via webhooks
- ZaloAlert: Send alerts via Zalo Official Account
- MessengerAlert: Send alerts via Facebook Messenger
- N8nAlert: Trigger N8n workflows with alert data
- WhatsAppAlert: Send alerts via WhatsApp Business API
- LineAlert: Send alerts via Line Notify API
- ViberAlert: Send alerts via Viber Bot API
- SkypeAlert: Send alerts via Skype Bot Framework
- WeChatAlert: Send alerts via WeChat Work webhook
- RocketChatAlert: Send alerts to Rocket.Chat channels
- FirebaseAlert: Send push notifications via Firebase Cloud Messaging
- MultiChannelAlert: Send to multiple channels simultaneously
Service Types
- hotel: Hotel bookings and searches
- flight: Flight bookings, PNR generation, e-tickets
- tour: Tour packages and bookings
- transfer: Airport transfers and transportation
Alert Types (Logger Methods)
- error(): Error alerts with red/urgent styling
- info(): Informational alerts with blue styling
- warn(): Warning alerts with yellow/caution styling
- success(): Success alerts with green/positive styling
Environment Types
- DEV: Development environment
- STAGING: Staging/testing environment
- PRODUCTION: Production environment
Version History
- v2.0.1 (2025-10-01):
- π Fixed: Data filtering bug in MultiChannelAlert (
item.fieldβitem.key) - π¨ Enhanced: Mattermost message formatting with emoji titles and code blocks
- ποΈ Added: Individual component
strictModesupport (TelegramAlert, SlackAlert, MattermostAlert) - π Improved: Cross-platform formatting consistency for JSON objects and curl commands
- π§ Added: Comprehensive data filtering utilities with backward compatibility
- π Fixed: Data filtering bug in MultiChannelAlert (
- v2.0.0 (2025-09-29): Multi-channel alert system, logger-style API, conditional channels
- v1.1.1 (2025): Enhanced Telegram formatting, smart ID extraction
- v1.0.0 (2025): Initial release with Telegram bot and logging
Best Practices
1. Use MultiChannelAlert for New Projects
// β
Recommended - Multi-channel approach
const { MultiChannelAlert } = require('kien-nguyen-support')
const alert = new MultiChannelAlert({ channels: [...] })
await alert.error(data)
// β Avoid - Manual individual calls
await telegramAlert.error(data)
await slackAlert.error(data)
await emailAlert.error(data)2. Conditional Channel Setup
// β
Only initialize channels with available config
const channels = []
if (process.env.TELEGRAM_BOT_TOKEN) channels.push({...})
if (process.env.SLACK_WEBHOOK_URL) channels.push({...})
// β Don't hardcode all channels
const channels = [telegram, slack, email] // Some might fail3. Use Environment Variables
// β
Use environment-specific configurations
const alert = new MultiChannelAlert({
channels: [...],
environment: process.env.NODE_ENV || 'STAGING',
failSilently: process.env.NODE_ENV === 'production'
})4. Handle Errors Gracefully
// β
Check results and handle failures
const result = await multiAlert.error(data)
if (result.summary.failed > 0) {
console.warn(`${result.summary.failed} channels failed to send alert`)
}
// β
Use failSilently in production
const alert = new MultiChannelAlert({
failSilently: true // Don't break app if alerts fail
})Troubleshooting
Common Issues
1. "Unable to resolve path to module" error:
# Make sure package is installed
npm install kien-nguyen-support
# Check import path
const { MultiChannelAlert } = require('kien-nguyen-support')2. Telegram "Unauthorized" error:
- Check bot token is correct
- Ensure bot is added to the chat/channel
- Verify chat ID format (numbers for groups, @channel for channels)
3. Slack "Invalid webhook URL" error:
- Regenerate webhook URL from Slack app settings
- Ensure webhook is activated for correct channel
4. Email SMTP errors:
- Use app passwords for Gmail (not regular password)
- Check firewall/network allows SMTP traffic
- Verify port (587 for TLS, 465 for SSL)
5. MultiChannelAlert some channels failing:
- Enable
failSilently: trueto continue on errors - Check individual channel configurations
- Review error details in response.errors array
Getting Help
- π Check examples in
/examplesdirectory - π Report bugs: GitHub Issues
- π§ Email: nguyenkien2022001@gmail.com
License
ISC