Typed operational alerts for TacticLaunch services: a small client + transports + templates layer so apps stop copy-pasting Telegram fetch snippets and string formatting.
- Ship lifecycle and billing signals to ops chat (new user, payment succeeded) with consistent copy and parse modes.
- Format digest-style messages from your own scheduler or worker (
digest.daily/digest.weekly/digest.monthlytemplates). - Route different severities to different chats using named transports (
default,security, …).
- Backend / full-stack engineers on Node 18+ who already use (or plan to use) Telegram Bot API for ops visibility.
- Teams that want shared vocabulary (
user.registered, …) and typed payloads without building a second notification platform.
You still can — this package is a thin convenience layer: one place for timeouts, forum threads, error handling policy, and event templates. It is not a hosted relay, queue, or outbox.
npm install @tacticlaunch/alertsFor coding assistants: a copy-paste prompt that describes the package surface and how to wire it into a host app lives in docs/INTEGRATION_PROMPT.md (also shipped on npm under node_modules/@tacticlaunch/alerts/docs/).
Scheduled digests: this package does not run timers or cron. Wire client.send('digest.daily', …) (or other events) from your job runner, queue, or platform scheduler.
- Put
botTokenand chat IDs in environment variables or a secrets manager — never commit tokens. - MarkdownV2 / HTML: the package does not escape message text. Safe formatting is the caller’s responsibility (see tests for the passthrough contract).
import {
createAlertClient,
createTelegramTransport,
builtInTemplates,
type BuiltInEventMap,
} from '@tacticlaunch/alerts';
interface AppEventMap extends BuiltInEventMap {
'order.shipped': { orderId: string };
}
const client = createAlertClient<AppEventMap>({
transports: {
default: createTelegramTransport({
botToken: process.env.TELEGRAM_BOT_TOKEN!,
chatId: process.env.TELEGRAM_CHAT_ID!,
messageThreadId: process.env.TELEGRAM_THREAD_ID
? Number(process.env.TELEGRAM_THREAD_ID)
: undefined,
}),
},
templates: {
...builtInTemplates,
'order.shipped': (data) => ({
text: `Order shipped: ${data.orderId}`,
parseMode: 'HTML',
}),
},
});
await client.send('user.registered', {
userId: 'usr_123',
email: 'user@example.com',
});Use one Telegram transport instance per destination and pick the channel per send:
const client = createAlertClient({
transports: {
default: createTelegramTransport({
botToken: process.env.TELEGRAM_BOT_TOKEN!,
chatId: process.env.TELEGRAM_CHAT_DEFAULT!,
}),
security: createTelegramTransport({
botToken: process.env.TELEGRAM_BOT_TOKEN!,
chatId: process.env.TELEGRAM_CHAT_SECURITY!,
}),
},
templates: builtInTemplates,
});
await client.send('billing.payment_succeeded', payload, {
channel: 'security',
});transports.default is required. Unknown channel keys invoke onError with kind: 'unknown_channel' and do not throw unless throw: true.
await client.sendRaw(
{ text: '<b>Ad-hoc</b> alert', parseMode: 'HTML' },
{ channel: 'default' },
);By default failures are logged via console.error and do not reject unless you pass throw: true. Override with onError for metrics or PagerDuty-style escalation.
| Export | Role |
|---|---|
createAlertClient |
Template registry + send / sendRaw |
createTelegramTransport |
sendMessage via native fetch (Node 18+) |
builtInTemplates / BuiltInEventMap |
Presets: user.registered, billing.payment_succeeded, digest.* |
This package follows Semantic Versioning. Releases are tagged vMAJOR.MINOR.PATCH on GitHub; see CHANGELOG.md for details. Breaking changes bump the major version.
npm ci
npm run typecheck
npm run lint
npm test
npm run buildMIT — see LICENSE.