Cloud Notification Library
npm install airhorn




Airhorn simplifies the process of notifications by using templates to send messages across various providers with a common easy to use interface.
- Supports multiple notification types: SMS, Email, Mobile Push, Webhooks
- A unified API for all notification types using the send() method.
- Hooks and Emitting built in by default for extendability and observability.
- Send Strategy (Round Robin, Fail Over, All) Choose the best delivery method for each notification.
- Built in Webhook support for sending notifications to external services.
- Built in support for retries and error handling on sends.
- Advanced caching on template compilation and execution.
- Load a template from a file for easy GitOps based workflows.
- Many supported providers such as Twilio (with Sendgrid), AWS, and Google Cloud.
- Robust (6+ template formats) templating via ecto
- Easily build your own provider with minimal effort via AirhornProvider interface.
- Statistics tracking for send successes, failures, and execution times (instance only).
- ESM and Typescript based supporting Nodejs 20+
- Maintained on a regular basis with updates and improvements.
- Getting Started
- Airhorn Options
- Using Send Helper Methods
- Airhorn Send Response
- Send Strategies
- Airhorn API
- Using Webhooks
- Statistics
- Emitting Events
- Load Template Helper
- Core Supported Providers
- Third Party Providers
- Creating a Provider
- How to Contribute
- Licensing and Copyright
To get started with Airhorn, you can install it via npm:
``bash`
npm install airhorn
Once installed, this gives you the main send functionality and built in webhook support. You can use it in your project like so:
`typescript
import { Airhorn, AirhornProviderType } from "airhorn";
const airhorn = new Airhorn();
const template = {
from: "https://mywebhookdomain.com",
content: "Hey <%= name %> this is a test message from Airhorn",
templateEngine: "ejs",
}
const data = { name: "John" };
await airhorn.send("https://mockhttp.org/post", template, data, AirhornProviderType.WEBHOOK);
`
Now lets configure the Airhorn instance with your preferred providers such as Twilio for SMS and SendGrid for Email.
`bash`
npm install airhorn @airhornjs/twilio
`typescript
import { Airhorn, AirhornProviderType } from "airhorn";
import { AirhornTwilio } from "@airhornjs/twilio";
const providers = [
new AirhornTwilio({
accountSid: "your_account_sid",
authToken: "your_auth_token"
}),
];
const airhorn = new Airhorn({
providers
});
// this will give you twilio and webhook (built in) support. Now lets create a template and send it!
const template = {
from: "+12223334444",
content: "Hey <%= name %> this is a test message from Airhorn",
templateEngine: "ejs",
}
const data = { name: "John" };
await airhorn.send("+1234567890", template, data, AirhornProviderType.SMS);
`
To learn about the available providers and their capabilities, check the Providers section.
Airhorn provides a variety of options to customize its behavior. You can configure these options when creating an instance of the Airhorn class:
`typescript
import { Airhorn, AirhornSendStrategy } from "airhorn";
const airhorn = new Airhorn({
sendStrategy: AirhornSendStrategy.RoundRobin
});
`
Here is the AirhornOptions type:
`typescriptuseWebhookProvider
export type AirhornOptions = {
/**
* Whether to enable caching.
* @default true
*/
cache?: boolean | Cacheable | CacheableOptions;
/**
* Whether to collect statistics.
* @default false
*/
statistics?: boolean;
/**
* The providers to add to the Airhorn instance. AirhornWebhook is added by default unless is set to false.`
*/
providers?: Array
/**
* Whether to use the built-in webhook provider.
* @default true
*/
useWebhookProvider?: boolean;
/**
* The retry strategy to use when sending messages.
* @default 0
*/
retryStrategy?: AirhornRetryStrategy;
/**
* The timeout to use when sending messages.
* @default 100
*/
timeout?: number;
/**
* The send strategy to use when sending messages.
* @default AirhornSendStrategy.RoundRobin
*/
sendStrategy?: AirhornSendStrategy;
/**
* Whether to throw an error if sending fails. By default we use emitting for errors
* @default false
*/
throwOnErrors?: boolean;
};
Airhorn provides helper methods for common tasks. For example, you can use the sendSMS method to send SMS messages easily:
`typescript
import { Airhorn } from "airhorn";
import { AirhornTwilio } from "@airhornjs/twilio";
const providers = [
new AirhornTwilio({
accountSid: "your_account_sid",
authToken: "your_auth_token"
}),
];
const airhorn = new Airhorn({
providers
});
const template = {
from: "+12223334444",
content: "Hey <%= name %> this is a test message from Airhorn",
templateEngine: "ejs",
}
const data = { name: "John" };
await airhorn.sendSMS("+1234567890", template, data);
`
All helper methods accept an optional AirhornSendOptions parameter to override the send strategy per call:
`typescript
import { Airhorn, AirhornSendStrategy } from "airhorn";
import { AirhornTwilio } from "@airhornjs/twilio";
const airhorn = new Airhorn({
providers: [
new AirhornTwilio({ accountSid: "sid_1", authToken: "token_1" }),
new AirhornTwilio({ accountSid: "sid_2", authToken: "token_2" }),
]
});
const template = {
from: "+12223334444",
content: "Hey <%= name %> this is a test message from Airhorn",
templateEngine: "ejs",
}
const data = { name: "John" };
// Send SMS using fail-over strategy
await airhorn.sendSMS("+1234567890", template, data, {
sendStrategy: AirhornSendStrategy.FailOver
});
`
Here are the following helper methods available:
- sendSMS: Sends an SMS message.sendEmail
- : Sends an email message.sendMobilePush
- : Sends a mobile push notification.sendWebhook
- : Sends a webhook notification.sendAll
- : Sends to all providers simultaneously.sendFailOver
- : Tries providers in order until one succeeds.sendRoundRobin
- : Cycles through providers round-robin.
The send method returns an AirhornSendResult object that contains information about the send operation. Here is the structure of the AirhornSendResult type:
`typescript`
export type AirhornSendResult = {
/**
* The providers that were used to send the message.
*/
providers: Array
/**
* The message that was sent.
*/
message?: AirhornProviderMessage;
/**
* Whether the message was sent successfully.
*/
success: boolean;
/**
* The response from the provider.
*/
// biome-ignore lint/suspicious/noExplicitAny: expected
response: any;
/**
* The number of times the message was retried.
*/
retries: number;
/**
* The errors that occurred while sending the message.
*/
errors: Array
/**
* The time taken to execute the send operation.
*/
executionTime: number;
};
Airhorn supports multiple send strategies to control how notifications are delivered. The send() method dispatches to the appropriate strategy method based on the configured sendStrategy (default: RoundRobin). You can also call each strategy method directly.
- Round Robin (sendRoundRobin): Cycles through providers, selecting the next one on each call. _(Default)_sendFailOver
- Fail Over (): Tries each provider in order until one succeeds.sendAll
- All (): Sends the notification to all providers simultaneously.
You can configure the default send strategy when creating the Airhorn instance:
`typescript
import { Airhorn, AirhornSendStrategy } from "airhorn";
const airhorn = new Airhorn({
sendStrategy: AirhornSendStrategy.RoundRobin
});
`
Or call a strategy method directly:
Sends a notification to all providers simultaneously. Succeeds if at least one provider succeeds.
`typescript
import { Airhorn, AirhornSendType } from "airhorn";
const airhorn = new Airhorn();
const template = {
from: "https://mywebhookdomain.com",
content: "Hey <%= name %> this is a notification from Airhorn",
templateEngine: "ejs",
}
const data = { name: "John" };
const result = await airhorn.sendAll("https://mockhttp.org/post", template, data, AirhornSendType.Webhook);
`
Tries each provider in order until one succeeds. If the first provider fails, it moves to the next.
`typescript
import { Airhorn, AirhornSendType } from "airhorn";
const airhorn = new Airhorn();
const template = {
from: "https://mywebhookdomain.com",
content: "Hey <%= name %> this is a notification from Airhorn",
templateEngine: "ejs",
}
const data = { name: "John" };
const result = await airhorn.sendFailOver("https://mockhttp.org/post", template, data, AirhornSendType.Webhook);
`
Cycles through providers, selecting the next one on each call. This is the default strategy.
`typescript
import { Airhorn, AirhornSendType } from "airhorn";
const airhorn = new Airhorn();
const template = {
from: "https://mywebhookdomain.com",
content: "Hey <%= name %> this is a notification from Airhorn",
templateEngine: "ejs",
}
const data = { name: "John" };
const result = await airhorn.sendRoundRobin("https://mockhttp.org/post", template, data, AirhornSendType.Webhook);
`
Here are all the properties and methods available and a brief description of each:
- .cache: Gets the cache instance which is based on cacheable..retryStrategy
- : Gets the retry strategy..timeout
- : Gets the timeout for sending messages..sendStrategy
- : Gets the send strategy..throwOnErrors
- : Gets the throw on errors flag..statistics
- : Access the statistics instance. go to Statistics to learn more..providers
- : Gets the list of configured providers.send()
- : Dispatches to the appropriate strategy method based on the configured sendStrategy.sendAll()
- : Sends to all providers simultaneously.sendFailOver()
- : Tries providers in order until one succeeds.sendRoundRobin()
- : Cycles through providers round-robin.sendSMS()
- : Sends an SMS message.sendEmail()
- : Sends an email message.sendMobilePush()
- : Sends a mobile push notification.sendWebhook()
- : Sends a webhook notification.loadTemplate()
- : Helper method that loads a template from the file system. Go to Load Template Helper to learn more.getProvidersByType()
- : Gets the list of providers by type. _(Used Internally)_setCache()
- : Sets the cache instance. _(Used Internally)_addProviders()
- : Adds new providers to the Airhorn instance. _(Used Internally)_generateMessage()
- : Generates a message from a template and data. _(Used Internally)_
Webhooks is built into Airhorn as a default provider and can be used to send notifications to external services. To use the built in webhooks just create an instance of the Airhorn class and call the send or sendWebhook method.
An example using the send method (recommended):
`typescript
import { Airhorn, AirhornProviderType } from "airhorn";
const template = {
from: "+12223334444",
to: "+1234567890",
content: "Hey <%= name %> this is a test message from Airhorn",
templateEngine: "ejs",
}
const data = { name: "John" };
await airhorn.send("https://mockhttp.org/post", template, data, AirhornProviderType.WEBHOOK);
`
To send using the helper function sendWebhook:
`typescript
import { Airhorn } from "airhorn";
const airhorn = new Airhorn();
const template = {
from: "+12223334444",
to: "+1234567890",
content: "Hey <%= name %> this is a test message from Airhorn",
templateEngine: "ejs",
}
const data = { name: "John" };
await airhorn.sendWebhook("https://mockhttp.org/post", template, data);
`
Airhorn provides built-in statistics to help you monitor the performance of your notifications. You can access the statistics instance through the .statistics property:
`typescript
import { Airhorn } from "airhorn";
const airhorn = new Airhorn({ statistics: true });
// Now you can use the stats object to get information about sent notifications
console.log(Total Sends: ${airhorn.statistics.totalSends});Total Successful Sends: ${airhorn.statistics.totalSendSuccesses}
console.log();Total Failed Sends: ${airhorn.statistics.totalSendFailures}
console.log();
// execution time statistics
console.log(Total Execution Time: ${airhorn.statistics.totalExecutionTime} ms);Average Execution Time: ${airhorn.statistics.averageExecutionTime} ms
console.log();Minimum Execution Time: ${airhorn.statistics.minimumExecutionTime} ms
console.log();Maximum Execution Time: ${airhorn.statistics.maxExecutionTime} ms
console.log();
// execution time data Array
console.log(All Execution Times: ${airhorn.statistics.executionTimes});Slowest Execution Times: ${airhorn.statistics.slowestExecutionTimes}
console.log();Fastest Execution Times: ${airhorn.statistics.fastestExecutionTimes}
console.log();`
By default, Airhorn statistics are disabled. You can enable them by setting the statistics option to true when creating the Airhorn instance. If you want to enable it after the Airhorn instance is created do the following:
`typescript
import { Airhorn } from "airhorn";
const airhorn = new Airhorn();
airhorn.statistics.enable();
`
To reset the statistics, you can call the reset method:
`typescript
import { Airhorn } from "airhorn";
const airhorn = new Airhorn();
airhorn.statistics.reset();
`
Airhorn provides event emitting by default with the following events:
- error: Emitted when there is an error.send.success
- : Emitted when a notification is successfully sent.send.failure
- : Emitted when a notification fails to send.
You can listen for these events using the on method:
`typescript
import { Airhorn, AirhornEvent, type AirhornSendResult } from "airhorn";
const airhorn = new Airhorn();
airhorn.on(AirhornEvent.SendSuccess, (data: AirhornSendResult) => {
console.log(Notification sent successfully: ${data});
});
airhorn.on(AirhornEvent.SendFailure, (data: AirhornSendResult) => {
console.error(Failed to send notification: ${data});`
});
In previous versions of Airhon we used the file system to load all the templates into a store that was used by the instance. Now, we offer an easy method to just load it from a markdown file if you want from anywhere on the file system.
Here is an example of how to use the loadTemplate helper method:
`typescript
import { Airhorn } from "airhorn";
const airhorn = new Airhorn();
const template = await airhorn.loadTemplate("path/to/template.md");
// now you can send with that template
await airhorn.send("https://mockhttp.org/post", template, data, AirhornProviderType.WEBHOOK);
`
An example of the markdown format is located at ./packages/airhorn/test/fixtures.
We currently support twilio, aws, and azure with thier offerings. Here is a chart showing what functionality is in each:
| Provider | SMS | Email | Push | Webhook |
|----------|-----|-------|------|---------|
| (built in airhorn) | ❌ | ❌ | ❌ | ✅ |@airhornjs/twilio
| | ✅ | ✅ | ❌ | ❌ |@airhornjs/aws
| | ✅ | ✅ | ✅ | ❌ |@airhornjs/azure
| | ✅ | ✅ | ✅ | ❌ |
Note: We used to support firebase because of mobile push but it made more sense to focus on aws and azure because it is more comprehensive.
If you have built a provider library let us know! We are more than happy to list it here!
To create a provider you can extend the AirhornProvider interface and implement the required methods for your specific provider.
`typescript
import { AirhornProvider } from "airhorn";
class MyCustomProvider implements AirhornProvider {
// Implement required methods
}
`
Once implemented, you can use your custom provider just like any other provider in Airhorn.
`typescript
import { Airhorn, AirhornProvider } from "airhorn";
class MyCustomProvider implements AirhornProvider {
// Implement required methods
}
const airhorn = new Airhorn({
providers: [new MyCustomProvider()]
});
`
Use one of the built in providers as a reference such as @airhornjs/twilio.
Now that you've set up your workspace, you're ready to contribute changes to the airhorn repository you can refer to the CONTRIBUTING guide. If you have any questions please feel free to ask by creating an issue and label it question`.
This project is MIT License © Jared Wray