omnimsg
v1.0.1
Published
Universal messaging SDK for Mattermost, Discord, and more
Maintainers
Readme
omnimsg
Universal messaging SDK for Mattermost, Discord, and more.
Omnimsg provides a clean, type-safe TypeScript interface for sending messages to multiple messaging platforms through a unified API.
Features
- 🚀 Type-safe: Full TypeScript support with comprehensive type definitions
- 🔌 Multiple Providers: Support for Mattermost and Discord (easily extensible)
- 📦 Lightweight: Minimal dependencies, zero runtime overhead for TypeScript users
- 🛡️ Error Handling: Comprehensive error classes and validation
- 🔄 Retry Logic: Built-in retry support with exponential backoff
- ⚡ Modern ES: Written in TypeScript, targeting ES2020+
Installation
# npm
npm install omnimsg
# yarn
yarn add omnimsg
# pnpm
pnpm add omnimsgQuick Start
import { Omnimsg, PROVIDER } from 'omnimsg';
const client = new Omnimsg();
// Configure Mattermost
const mattermost = client.provider(PROVIDER.MATTERMOST, {
webhookUrl: 'https://your-mattermost.com/hooks/xxxxxxxxxxxxxxxxxxxxxxxxxx',
channelName: 'general',
username: 'Notifier Bot',
iconUrl: 'https://example.com/icon.png',
iconEmoji: ':robot_face:'
});
// Send a message to Mattermost
await mattermost.send({
text: 'Hello from omnimsg!',
attachments: [{
color: 'good',
title: 'Success',
text: 'Message sent successfully'
}]
});
// Configure Discord
const discord = client.provider(PROVIDER.DISCORD, {
webhookUrl: 'https://discord.com/api/webhooks/xxxx/yyyy',
username: 'Notifier',
avatarUrl: 'https://example.com/avatar.png'
});
// Send an embed to Discord
await discord.send({
content: 'Hello from omnimsg!',
embeds: [{
title: 'Notification',
description: 'This is an embed from omnimsg',
color: 0x00ff00,
fields: [
{ name: 'Status', value: '✅ Success', inline: true },
{ name: 'Time', value: new Date().toISOString(), inline: true }
]
}]
});Provider Configuration
Mattermost
const mattermost = client.provider(PROVIDER.MATTERMOST, {
webhookUrl: 'https://mattermost.example.com/hooks/xxxxxxxxx', // Required
channelName: 'general', // Optional - overrides webhook's default channel
username: 'Bot Name', // Optional - overrides webhook's default username
iconUrl: 'https://...', // Optional - bot avatar URL
iconEmoji: ':robot_face:', // Optional - bot emoji
timeout: 30000, // Optional - request timeout in ms
retries: 3 // Optional - number of retries
});Mattermost Message Format
await mattermost.send({
text: 'Hello world!', // Optional - message text with markdown support
channel: 'custom-channel', // Optional - override default channel
username: 'Custom Bot', // Optional - override default username
iconUrl: 'https://...', // Optional - override avatar
iconEmoji: ':wave:', // Optional - override emoji
attachments: [{
fallback: 'This is an attachment', // Required for attachments
color: '#36a64f', // Optional - hex color code
pretext: 'Optional pretext', // Optional - text before attachment
author_name: 'Author', // Optional
author_link: 'https://...', // Optional
author_icon: 'https://...', // Optional
title: 'Attachment Title', // Optional
title_link: 'https://...', // Optional
text: 'Main attachment text', // Optional
fields: [ // Optional
{
title: 'Field 1',
value: 'Value 1',
short: true
}
],
image_url: 'https://...', // Optional
thumb_url: 'https://...', // Optional
footer: 'Footer text', // Optional
footer_icon: 'https://...', // Optional
ts: Date.now() / 1000 // Optional - timestamp
}],
props: { // Optional - custom properties
custom_field: 'value'
}
});Discord
const discord = client.provider(PROVIDER.DISCORD, {
webhookUrl: 'https://discord.com/api/webhooks/xxxx/yyyy', // Required
username: 'Bot Name', // Optional - overrides webhook's default username
avatarUrl: 'https://...', // Optional - overrides webhook's default avatar
timeout: 30000, // Optional - request timeout in ms
retries: 3 // Optional - number of retries
});Discord Message Format
await discord.send({
content: 'Hello world!', // Optional - message text (max 2000 chars)
username: 'Custom Bot', // Optional - override default username
avatarUrl: 'https://...', // Optional - override avatar
tts: false, // Optional - text-to-speech
embeds: [{ // Optional - array of embeds (max 10)
title: 'Embed Title', // Optional (max 256 chars)
description: 'Embed description', // Optional (max 4096 chars)
url: 'https://...', // Optional
color: 0x00ff00, // Optional - hex color
timestamp: new Date().toISOString(), // Optional
footer: { // Optional
text: 'Footer text',
icon_url: 'https://...'
},
image: { // Optional
url: 'https://...'
},
thumbnail: { // Optional
url: 'https://...'
},
author: { // Optional
name: 'Author Name',
url: 'https://...',
icon_url: 'https://...'
},
fields: [ // Optional (max 25 fields)
{
name: 'Field Name', // Required (max 256 chars)
value: 'Field Value', // Required (max 1024 chars)
inline: true // Optional
}
]
}],
allowed_mentions: { // Optional
parse: ['users', 'roles'],
users: ['user-id'],
roles: ['role-id'],
replied_user: true
},
components: [{ // Optional - UI components
type: 1,
components: [{
type: 2,
style: 1, // 1=primary, 2=secondary, 3=success, 4=danger, 5=link
label: 'Button',
custom_id: 'button_click',
emoji: {
name: '👍'
}
}]
}]
});Error Handling
Omnimsg provides comprehensive error handling with specific error types:
import {
MessagingError,
ConfigurationError,
ValidationError,
NetworkError,
RateLimitError,
AuthenticationError
} from 'omnimsg';
try {
await provider.send(message);
} catch (error) {
if (error instanceof ConfigurationError) {
console.error('Configuration error:', error.message);
} else if (error instanceof ValidationError) {
console.error('Validation error:', error.message);
} else if (error instanceof RateLimitError) {
console.error('Rate limited, retry after:', error.retryAfter);
}
// ... handle other error types
}Advanced Usage
Managing Multiple Providers
const client = new Omnimsg();
// Configure multiple providers
client.provider(PROVIDER.MATTERMOST, mattermostConfig);
client.provider(PROVIDER.DISCORD, discordConfig);
// Get configured providers
const configured = client.getConfiguredProviders();
console.log(configured); // ['mattermost', 'discord']
// Check if a provider is configured
if (client.isProviderConfigured(PROVIDER.MATTERMOST)) {
// Use the provider
}
// Remove a provider
client.removeProvider(PROVIDER.MATTERMOST);Sending Messages Directly
const client = new Omnimsg();
// Configure providers first
client.provider(PROVIDER.MATTERMOST, mattermostConfig);
client.provider(PROVIDER.DISCORD, discordConfig);
// Send messages using the client
const result1 = await client.send(PROVIDER.MATTERMOST, mattermostMessage);
const result2 = await client.send(PROVIDER.DISCORD, discordMessage);Custom Configuration
const mattermost = client.provider(PROVIDER.MATTERMOST, {
webhookUrl: 'https://...',
timeout: 60000, // 60 second timeout
retries: 5, // 5 retries on failure
channelName: 'alerts',
username: 'Alert Bot'
});API Reference
Classes
Omnimsg- Main client class for managing providersMattermostProvider- Mattermost-specific provider implementationDiscordProvider- Discord-specific provider implementation
Types
PROVIDER- Enum of available providersMattermostConfig- Mattermost provider configurationMattermostMessage- Mattermost message formatDiscordConfig- Discord provider configurationDiscordMessage- Discord message formatSendResult- Result of a send operation
Errors
MessagingError- Base error classConfigurationError- Invalid configurationValidationError- Invalid message formatNetworkError- Network-related errorsRateLimitError- Rate limit exceededAuthenticationError- Authentication failed
Development
# Install dependencies
pnpm install
# Build the project
pnpm build
# Run tests
pnpm test
# Watch mode
pnpm dev
# Type checking
pnpm type-check
# Linting
pnpm lintContributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT © Ashik
Related Projects
- axios - HTTP client
- discord.js - Discord API wrapper
- node-mattermost - Mattermost API reference
