smart-alert-t 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +239 -0
- package/dist/alertType.d.ts +23 -0
- package/dist/alertType.js +42 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +20 -0
- package/dist/messageFormatter.d.ts +27 -0
- package/dist/messageFormatter.js +80 -0
- package/dist/smartAlert.d.ts +71 -0
- package/dist/smartAlert.js +175 -0
- package/package.json +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Gift Balogun (https://giftbalogun.name.ng/)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
# SmartAlert-T (SAT) — Node.js
|
|
2
|
+
|
|
3
|
+
> **The first line of defense for your servers and applications.**
|
|
4
|
+
> Send beautiful, structured **Telegram** alerts — `critical`, `warning`, `info` — straight from your Node.js code, cron jobs and background workers.
|
|
5
|
+
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](https://nodejs.org/)
|
|
8
|
+
[](https://www.typescriptlang.org/)
|
|
9
|
+
|
|
10
|
+
Built by **[Gift Balogun](https://giftbalogun.name.ng/)**. This is the Node.js twin of the PHP/Laravel SmartAlert-T package — **identical message styling and footer** across both runtimes.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## ✨ Features
|
|
15
|
+
|
|
16
|
+
- 🚨 **Three alert levels** — Critical, Warning, Info — each with distinct emoji + styling.
|
|
17
|
+
- 💬 Send to **individual users, groups, supergroups and channels**.
|
|
18
|
+
- 🟦 **TypeScript-first** — ships with full type definitions.
|
|
19
|
+
- ⏱️ **Cron & background-process friendly** — optional non-throwing mode so alerting never crashes your jobs.
|
|
20
|
+
- 🏷️ Rich **context metadata** block + automatic timestamp.
|
|
21
|
+
- 🔒 HTML-safe message escaping.
|
|
22
|
+
- 🪶 **Zero runtime dependencies** — built on the Node.js core `https` module.
|
|
23
|
+
- 🖋️ Branded footer with copyright to Gift Balogun on every message.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 📦 Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install smart-alert-t
|
|
31
|
+
# or
|
|
32
|
+
yarn add smart-alert-t
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Requires **Node.js >= 14**.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 🤖 Getting your Telegram credentials
|
|
40
|
+
|
|
41
|
+
1. **Create a bot** — open [@BotFather](https://t.me/BotFather), send `/newbot`, and copy the **bot token** (e.g. `123456789:AAH...`).
|
|
42
|
+
2. **Find your chat id:**
|
|
43
|
+
- **Personal chat**: message [@userinfobot](https://t.me/userinfobot) for your numeric id.
|
|
44
|
+
- **Group**: add the bot to the group, then open `https://api.telegram.org/bot<TOKEN>/getUpdates` and read `chat.id` (group ids are usually negative).
|
|
45
|
+
- **Channel**: use `@your_channel_username` and make the bot an admin.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 🚀 Quick start
|
|
50
|
+
|
|
51
|
+
### CommonJS
|
|
52
|
+
|
|
53
|
+
```js
|
|
54
|
+
const { SmartAlert } = require('smart-alert-t');
|
|
55
|
+
|
|
56
|
+
const alert = SmartAlert.make({
|
|
57
|
+
token: 'YOUR_BOT_TOKEN',
|
|
58
|
+
chatId: 'YOUR_CHAT_ID', // user, group, or @channel
|
|
59
|
+
appName: 'Payments API', // optional label on every alert
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
await alert.critical('Database down', 'Primary DB is unreachable.', { host: 'db-01' });
|
|
63
|
+
await alert.warning('High memory', 'Worker memory at 86%.', { service: 'queue' });
|
|
64
|
+
await alert.info('Deploy complete', 'v2.4.1 shipped to prod.', { version: '2.4.1' });
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### ES Modules / TypeScript
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { SmartAlert } from 'smart-alert-t';
|
|
71
|
+
|
|
72
|
+
const alert = new SmartAlert({
|
|
73
|
+
token: process.env.SMART_ALERT_TOKEN!,
|
|
74
|
+
chatId: process.env.SMART_ALERT_CHAT_ID!,
|
|
75
|
+
appName: 'Billing Service',
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
await alert.info('Job done', 'Nightly export completed.', { rows: 48211 });
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 🎨 The three alert types
|
|
84
|
+
|
|
85
|
+
| Method | Emoji | Use it for |
|
|
86
|
+
|---------------|:-----:|----------------------------------------------|
|
|
87
|
+
| `critical()` | 🚨 | Outages, data loss, anything paging-worthy |
|
|
88
|
+
| `warning()` | ⚠️ | Degraded state that needs attention soon |
|
|
89
|
+
| `info()` | ℹ️ | Deploys, job completions, routine heads-up |
|
|
90
|
+
|
|
91
|
+
Every method shares the same signature and returns a `Promise`:
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
alert.critical(
|
|
95
|
+
title: string, // short headline
|
|
96
|
+
message: string, // body text
|
|
97
|
+
context?: Record<string, unknown>, // optional metadata block
|
|
98
|
+
chatId?: string | number | null, // optional per-call destination override
|
|
99
|
+
): Promise<SmartAlertResult>;
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
A rendered alert looks like:
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
🚨 [CRITICAL] Database down
|
|
106
|
+
App: Payments API
|
|
107
|
+
|
|
108
|
+
Primary DB is unreachable.
|
|
109
|
+
|
|
110
|
+
• host: db-01
|
|
111
|
+
• region: eu-west-1
|
|
112
|
+
|
|
113
|
+
🕒 2026-06-03 10:42:11 UTC
|
|
114
|
+
Powered by SmartAlert-T © 2026 — Gift Balogun
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## 👥 Sending to users vs. groups vs. channels
|
|
120
|
+
|
|
121
|
+
The destination is just the `chatId`:
|
|
122
|
+
|
|
123
|
+
```js
|
|
124
|
+
// Individual user
|
|
125
|
+
await alert.info('Hi', 'Personal message.', {}, 123456789);
|
|
126
|
+
|
|
127
|
+
// Group / supergroup (ids are typically negative)
|
|
128
|
+
await alert.warning('Heads up', 'Group message.', {}, -1001234567890);
|
|
129
|
+
|
|
130
|
+
// Public channel
|
|
131
|
+
await alert.critical('Outage', 'Channel broadcast.', {}, '@my_status_channel');
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Set a default `chatId` in the constructor and override it per call only when needed.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## ⏰ Using it in cron jobs & background processes
|
|
139
|
+
|
|
140
|
+
Set `throwOnError: false` so a transient Telegram hiccup can never crash your scheduled task — the promise resolves to `{ ok: false, error }` instead of rejecting.
|
|
141
|
+
|
|
142
|
+
```js
|
|
143
|
+
const os = require('os');
|
|
144
|
+
const { SmartAlert } = require('smart-alert-t');
|
|
145
|
+
|
|
146
|
+
const alert = SmartAlert.make({
|
|
147
|
+
token: process.env.SMART_ALERT_TOKEN,
|
|
148
|
+
chatId: process.env.SMART_ALERT_CHAT_ID,
|
|
149
|
+
appName: `Server: ${os.hostname()}`,
|
|
150
|
+
throwOnError: false,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
const result = await alert.warning('Disk filling up', 'Root volume at 82%.', { used: '82%' });
|
|
154
|
+
if (!result.ok) {
|
|
155
|
+
console.error('[SAT] delivery failed:', result.error);
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Crontab example** (every 5 minutes):
|
|
160
|
+
|
|
161
|
+
```cron
|
|
162
|
+
SMART_ALERT_TOKEN=123456789:AAH...
|
|
163
|
+
SMART_ALERT_CHAT_ID=-1001234567890
|
|
164
|
+
*/5 * * * * /usr/bin/node /var/www/app/examples/cron-health-check.js >> /var/log/sat.log 2>&1
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**node-cron example:**
|
|
168
|
+
|
|
169
|
+
```js
|
|
170
|
+
const cron = require('node-cron');
|
|
171
|
+
const { SmartAlert } = require('smart-alert-t');
|
|
172
|
+
|
|
173
|
+
const alert = SmartAlert.make({
|
|
174
|
+
token: process.env.SMART_ALERT_TOKEN,
|
|
175
|
+
chatId: process.env.SMART_ALERT_CHAT_ID,
|
|
176
|
+
throwOnError: false,
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
cron.schedule('*/5 * * * *', async () => {
|
|
180
|
+
// your health check...
|
|
181
|
+
await alert.info('Heartbeat', 'Service is alive.');
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
See [`examples/basic-usage.js`](examples/basic-usage.js), [`examples/cron-health-check.js`](examples/cron-health-check.js) and [`examples/typescript-usage.ts`](examples/typescript-usage.ts) for complete scripts.
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## ⚙️ Configuration reference
|
|
190
|
+
|
|
191
|
+
| Option | Type | Default | Description |
|
|
192
|
+
|----------------|----------------------------|-----------|----------------------------------------------------------|
|
|
193
|
+
| `token` | `string` | — | Telegram bot token from @BotFather. **Required.** |
|
|
194
|
+
| `chatId` | `string \| number \| null` | `null` | Default destination (user/group/`@channel`). |
|
|
195
|
+
| `appName` | `string \| null` | `null` | Optional label shown on every alert. |
|
|
196
|
+
| `timeout` | `number` | `10000` | Request timeout in **milliseconds**. |
|
|
197
|
+
| `throwOnError` | `boolean` | `true` | Reject on failure (`true`) or resolve an error payload. |
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## 🛡️ Error handling
|
|
202
|
+
|
|
203
|
+
Default mode rejects with a `SmartAlertError`:
|
|
204
|
+
|
|
205
|
+
```js
|
|
206
|
+
const { SmartAlert, SmartAlertError } = require('smart-alert-t');
|
|
207
|
+
|
|
208
|
+
try {
|
|
209
|
+
await alert.critical('X', 'Y');
|
|
210
|
+
} catch (err) {
|
|
211
|
+
if (err instanceof SmartAlertError) {
|
|
212
|
+
// log, retry, fall back to email, ...
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
With `throwOnError: false`, every call resolves to `{ ok: false, error }` on failure and the decoded Telegram response on success.
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## 🧪 Testing & building
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
npm install
|
|
225
|
+
npm run build # compile TypeScript -> dist/
|
|
226
|
+
npm test # run the offline unit tests
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
The test suite covers alert-type validation, message formatting, HTML escaping and error handling — all **without network calls**.
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## 📄 License
|
|
234
|
+
|
|
235
|
+
MIT © [Gift Balogun](https://giftbalogun.name.ng/)
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
<p align="center"><sub>Powered by SmartAlert-T (SAT) — built with ❤️ by <a href="https://giftbalogun.name.ng/">Gift Balogun</a></sub></p>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Defines the supported SmartAlert-T alert types and their visual styling.
|
|
3
|
+
*
|
|
4
|
+
* Each alert type maps to an emoji and a human readable label that is used to
|
|
5
|
+
* build a consistent, easily scannable Telegram message. The styling mirrors
|
|
6
|
+
* the PHP version of SmartAlert-T so alerts look identical across runtimes.
|
|
7
|
+
*
|
|
8
|
+
* @author Gift Balogun <https://giftbalogun.name.ng/>
|
|
9
|
+
*/
|
|
10
|
+
export type AlertTypeValue = 'critical' | 'warning' | 'info';
|
|
11
|
+
export declare const AlertType: {
|
|
12
|
+
CRITICAL: "critical";
|
|
13
|
+
WARNING: "warning";
|
|
14
|
+
INFO: "info";
|
|
15
|
+
/** Return all valid alert type identifiers. */
|
|
16
|
+
all(): AlertTypeValue[];
|
|
17
|
+
/** Determine whether the given type is supported. */
|
|
18
|
+
isValid(type: string): type is AlertTypeValue;
|
|
19
|
+
/** Get the emoji associated with an alert type. */
|
|
20
|
+
emoji(type: string): string;
|
|
21
|
+
/** Get the upper-cased label associated with an alert type. */
|
|
22
|
+
label(type: string): string;
|
|
23
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Defines the supported SmartAlert-T alert types and their visual styling.
|
|
4
|
+
*
|
|
5
|
+
* Each alert type maps to an emoji and a human readable label that is used to
|
|
6
|
+
* build a consistent, easily scannable Telegram message. The styling mirrors
|
|
7
|
+
* the PHP version of SmartAlert-T so alerts look identical across runtimes.
|
|
8
|
+
*
|
|
9
|
+
* @author Gift Balogun <https://giftbalogun.name.ng/>
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.AlertType = void 0;
|
|
13
|
+
const STYLES = {
|
|
14
|
+
critical: { emoji: '🚨', label: 'CRITICAL' },
|
|
15
|
+
warning: { emoji: '⚠️', label: 'WARNING' },
|
|
16
|
+
info: { emoji: 'ℹ️', label: 'INFO' },
|
|
17
|
+
};
|
|
18
|
+
exports.AlertType = {
|
|
19
|
+
CRITICAL: 'critical',
|
|
20
|
+
WARNING: 'warning',
|
|
21
|
+
INFO: 'info',
|
|
22
|
+
/** Return all valid alert type identifiers. */
|
|
23
|
+
all() {
|
|
24
|
+
return Object.keys(STYLES);
|
|
25
|
+
},
|
|
26
|
+
/** Determine whether the given type is supported. */
|
|
27
|
+
isValid(type) {
|
|
28
|
+
return Object.prototype.hasOwnProperty.call(STYLES, String(type).toLowerCase());
|
|
29
|
+
},
|
|
30
|
+
/** Get the emoji associated with an alert type. */
|
|
31
|
+
emoji(type) {
|
|
32
|
+
var _a, _b;
|
|
33
|
+
const key = String(type).toLowerCase();
|
|
34
|
+
return (_b = (_a = STYLES[key]) === null || _a === void 0 ? void 0 : _a.emoji) !== null && _b !== void 0 ? _b : STYLES.info.emoji;
|
|
35
|
+
},
|
|
36
|
+
/** Get the upper-cased label associated with an alert type. */
|
|
37
|
+
label(type) {
|
|
38
|
+
var _a, _b;
|
|
39
|
+
const key = String(type).toLowerCase();
|
|
40
|
+
return (_b = (_a = STYLES[key]) === null || _a === void 0 ? void 0 : _a.label) !== null && _b !== void 0 ? _b : STYLES.info.label;
|
|
41
|
+
},
|
|
42
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SmartAlert-T (SAT) — Telegram alerting for Node.js.
|
|
3
|
+
*
|
|
4
|
+
* The first line of defense for your servers and applications.
|
|
5
|
+
*
|
|
6
|
+
* @author Gift Balogun <https://giftbalogun.name.ng/>
|
|
7
|
+
* @license MIT
|
|
8
|
+
*/
|
|
9
|
+
export { SmartAlert, SmartAlertError } from './smartAlert';
|
|
10
|
+
export type { SmartAlertConfig, SmartAlertResult } from './smartAlert';
|
|
11
|
+
export { AlertType } from './alertType';
|
|
12
|
+
export type { AlertTypeValue } from './alertType';
|
|
13
|
+
export { MessageFormatter } from './messageFormatter';
|
|
14
|
+
export type { AlertContext } from './messageFormatter';
|
|
15
|
+
import { SmartAlert } from './smartAlert';
|
|
16
|
+
export default SmartAlert;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* SmartAlert-T (SAT) — Telegram alerting for Node.js.
|
|
4
|
+
*
|
|
5
|
+
* The first line of defense for your servers and applications.
|
|
6
|
+
*
|
|
7
|
+
* @author Gift Balogun <https://giftbalogun.name.ng/>
|
|
8
|
+
* @license MIT
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.MessageFormatter = exports.AlertType = exports.SmartAlertError = exports.SmartAlert = void 0;
|
|
12
|
+
var smartAlert_1 = require("./smartAlert");
|
|
13
|
+
Object.defineProperty(exports, "SmartAlert", { enumerable: true, get: function () { return smartAlert_1.SmartAlert; } });
|
|
14
|
+
Object.defineProperty(exports, "SmartAlertError", { enumerable: true, get: function () { return smartAlert_1.SmartAlertError; } });
|
|
15
|
+
var alertType_1 = require("./alertType");
|
|
16
|
+
Object.defineProperty(exports, "AlertType", { enumerable: true, get: function () { return alertType_1.AlertType; } });
|
|
17
|
+
var messageFormatter_1 = require("./messageFormatter");
|
|
18
|
+
Object.defineProperty(exports, "MessageFormatter", { enumerable: true, get: function () { return messageFormatter_1.MessageFormatter; } });
|
|
19
|
+
const smartAlert_2 = require("./smartAlert");
|
|
20
|
+
exports.default = smartAlert_2.SmartAlert;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional key/value metadata attached to an alert.
|
|
3
|
+
*/
|
|
4
|
+
export type AlertContext = Record<string, unknown>;
|
|
5
|
+
/**
|
|
6
|
+
* Builds the final Telegram message body for an alert.
|
|
7
|
+
*
|
|
8
|
+
* Produces HTML formatted messages (Telegram "HTML" parse mode) with a
|
|
9
|
+
* consistent header, optional context block and a branded footer. The exact
|
|
10
|
+
* same layout is mirrored in the PHP version of SmartAlert-T.
|
|
11
|
+
*
|
|
12
|
+
* @author Gift Balogun <https://giftbalogun.name.ng/>
|
|
13
|
+
*/
|
|
14
|
+
export declare class MessageFormatter {
|
|
15
|
+
static readonly AUTHOR = "Gift Balogun";
|
|
16
|
+
static readonly AUTHOR_URL = "https://giftbalogun.name.ng/";
|
|
17
|
+
/**
|
|
18
|
+
* Format an alert into a Telegram-ready HTML string.
|
|
19
|
+
*/
|
|
20
|
+
format(type: string, title: string, message: string, context?: AlertContext, appName?: string | null): string;
|
|
21
|
+
/** Convert any context value to a readable string. */
|
|
22
|
+
private stringify;
|
|
23
|
+
/** Human readable UTC timestamp. */
|
|
24
|
+
private timestamp;
|
|
25
|
+
/** Escape user supplied content for the Telegram HTML parse mode. */
|
|
26
|
+
private escape;
|
|
27
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MessageFormatter = void 0;
|
|
4
|
+
const alertType_1 = require("./alertType");
|
|
5
|
+
/**
|
|
6
|
+
* Builds the final Telegram message body for an alert.
|
|
7
|
+
*
|
|
8
|
+
* Produces HTML formatted messages (Telegram "HTML" parse mode) with a
|
|
9
|
+
* consistent header, optional context block and a branded footer. The exact
|
|
10
|
+
* same layout is mirrored in the PHP version of SmartAlert-T.
|
|
11
|
+
*
|
|
12
|
+
* @author Gift Balogun <https://giftbalogun.name.ng/>
|
|
13
|
+
*/
|
|
14
|
+
class MessageFormatter {
|
|
15
|
+
/**
|
|
16
|
+
* Format an alert into a Telegram-ready HTML string.
|
|
17
|
+
*/
|
|
18
|
+
format(type, title, message, context = {}, appName) {
|
|
19
|
+
const emoji = alertType_1.AlertType.emoji(type);
|
|
20
|
+
const label = alertType_1.AlertType.label(type);
|
|
21
|
+
const lines = [];
|
|
22
|
+
let header = `${emoji} <b>[${label}]</b>`;
|
|
23
|
+
if (title && title.length > 0) {
|
|
24
|
+
header += ` ${this.escape(title)}`;
|
|
25
|
+
}
|
|
26
|
+
lines.push(header);
|
|
27
|
+
if (appName) {
|
|
28
|
+
lines.push(`<b>App:</b> ${this.escape(appName)}`);
|
|
29
|
+
}
|
|
30
|
+
lines.push('');
|
|
31
|
+
lines.push(this.escape(message));
|
|
32
|
+
const entries = Object.entries(context || {});
|
|
33
|
+
if (entries.length > 0) {
|
|
34
|
+
lines.push('');
|
|
35
|
+
for (const [key, value] of entries) {
|
|
36
|
+
lines.push(`• <b>${this.escape(key)}:</b> ${this.escape(this.stringify(value))}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
lines.push('');
|
|
40
|
+
lines.push(`<i>🕒 ${this.escape(this.timestamp())}</i>`);
|
|
41
|
+
lines.push(`<i>Powered by SmartAlert-T © ${new Date().getFullYear()} — ` +
|
|
42
|
+
`<a href="${MessageFormatter.AUTHOR_URL}">${MessageFormatter.AUTHOR}</a></i>`);
|
|
43
|
+
return lines.join('\n');
|
|
44
|
+
}
|
|
45
|
+
/** Convert any context value to a readable string. */
|
|
46
|
+
stringify(value) {
|
|
47
|
+
if (value === null || value === undefined) {
|
|
48
|
+
return '';
|
|
49
|
+
}
|
|
50
|
+
if (typeof value === 'boolean') {
|
|
51
|
+
return value ? 'true' : 'false';
|
|
52
|
+
}
|
|
53
|
+
if (typeof value === 'object') {
|
|
54
|
+
try {
|
|
55
|
+
return JSON.stringify(value);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return String(value);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return String(value);
|
|
62
|
+
}
|
|
63
|
+
/** Human readable UTC timestamp. */
|
|
64
|
+
timestamp() {
|
|
65
|
+
const d = new Date();
|
|
66
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
67
|
+
return (`${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())} ` +
|
|
68
|
+
`${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}:${pad(d.getUTCSeconds())} UTC`);
|
|
69
|
+
}
|
|
70
|
+
/** Escape user supplied content for the Telegram HTML parse mode. */
|
|
71
|
+
escape(value) {
|
|
72
|
+
return String(value)
|
|
73
|
+
.replace(/&/g, '&')
|
|
74
|
+
.replace(/</g, '<')
|
|
75
|
+
.replace(/>/g, '>');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
exports.MessageFormatter = MessageFormatter;
|
|
79
|
+
MessageFormatter.AUTHOR = 'Gift Balogun';
|
|
80
|
+
MessageFormatter.AUTHOR_URL = 'https://giftbalogun.name.ng/';
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { AlertContext } from './messageFormatter';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration options for {@link SmartAlert}.
|
|
4
|
+
*/
|
|
5
|
+
export interface SmartAlertConfig {
|
|
6
|
+
/** Telegram bot token from @BotFather. Required. */
|
|
7
|
+
token: string;
|
|
8
|
+
/** Default destination: user id, group id (often negative) or "@channel". */
|
|
9
|
+
chatId?: string | number | null;
|
|
10
|
+
/** Optional application/service name shown on every alert. */
|
|
11
|
+
appName?: string | null;
|
|
12
|
+
/** Request timeout in milliseconds. Default: 10000. */
|
|
13
|
+
timeout?: number;
|
|
14
|
+
/** When true (default) failures reject the promise; when false they resolve to an error payload. */
|
|
15
|
+
throwOnError?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Result returned by the Telegram API (or an error payload in non-throwing mode).
|
|
19
|
+
*/
|
|
20
|
+
export interface SmartAlertResult {
|
|
21
|
+
ok: boolean;
|
|
22
|
+
error?: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
result?: unknown;
|
|
25
|
+
[key: string]: unknown;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Error thrown for any SmartAlert-T configuration or transport failure.
|
|
29
|
+
*/
|
|
30
|
+
export declare class SmartAlertError extends Error {
|
|
31
|
+
constructor(message: string);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* SmartAlert-T (SAT)
|
|
35
|
+
*
|
|
36
|
+
* A lightweight Telegram alerting client — the first line of defense for your
|
|
37
|
+
* servers and applications. Send CRITICAL, WARNING and INFO alerts to Telegram
|
|
38
|
+
* users or groups directly from Node.js, cron jobs or background workers.
|
|
39
|
+
*
|
|
40
|
+
* Built on the Node.js core `https` module — zero runtime dependencies.
|
|
41
|
+
*
|
|
42
|
+
* @author Gift Balogun <https://giftbalogun.name.ng/>
|
|
43
|
+
* @license MIT
|
|
44
|
+
*/
|
|
45
|
+
export declare class SmartAlert {
|
|
46
|
+
static readonly VERSION = "1.0.0";
|
|
47
|
+
private static readonly API_BASE;
|
|
48
|
+
private readonly token;
|
|
49
|
+
private readonly defaultChatId;
|
|
50
|
+
private readonly appName;
|
|
51
|
+
private readonly timeout;
|
|
52
|
+
private readonly throwOnError;
|
|
53
|
+
private readonly formatter;
|
|
54
|
+
constructor(config: SmartAlertConfig);
|
|
55
|
+
/** Convenience factory. */
|
|
56
|
+
static make(config: SmartAlertConfig): SmartAlert;
|
|
57
|
+
/** Send a CRITICAL alert (🚨). */
|
|
58
|
+
critical(title: string, message: string, context?: AlertContext, chatId?: string | number | null): Promise<SmartAlertResult>;
|
|
59
|
+
/** Send a WARNING alert (⚠️). */
|
|
60
|
+
warning(title: string, message: string, context?: AlertContext, chatId?: string | number | null): Promise<SmartAlertResult>;
|
|
61
|
+
/** Send an INFO alert (ℹ️). */
|
|
62
|
+
info(title: string, message: string, context?: AlertContext, chatId?: string | number | null): Promise<SmartAlertResult>;
|
|
63
|
+
/**
|
|
64
|
+
* Send an alert of an arbitrary (validated) type.
|
|
65
|
+
*/
|
|
66
|
+
send(type: string, title: string, message: string, context?: AlertContext, chatId?: string | number | null): Promise<SmartAlertResult>;
|
|
67
|
+
/** Build a failure result (throwing or resolving based on config). */
|
|
68
|
+
private fail;
|
|
69
|
+
/** Perform the HTTPS request to the Telegram Bot API. */
|
|
70
|
+
private dispatch;
|
|
71
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.SmartAlert = exports.SmartAlertError = void 0;
|
|
37
|
+
const https = __importStar(require("https"));
|
|
38
|
+
const url_1 = require("url");
|
|
39
|
+
const alertType_1 = require("./alertType");
|
|
40
|
+
const messageFormatter_1 = require("./messageFormatter");
|
|
41
|
+
/**
|
|
42
|
+
* Error thrown for any SmartAlert-T configuration or transport failure.
|
|
43
|
+
*/
|
|
44
|
+
class SmartAlertError extends Error {
|
|
45
|
+
constructor(message) {
|
|
46
|
+
super(message);
|
|
47
|
+
this.name = 'SmartAlertError';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
exports.SmartAlertError = SmartAlertError;
|
|
51
|
+
/**
|
|
52
|
+
* SmartAlert-T (SAT)
|
|
53
|
+
*
|
|
54
|
+
* A lightweight Telegram alerting client — the first line of defense for your
|
|
55
|
+
* servers and applications. Send CRITICAL, WARNING and INFO alerts to Telegram
|
|
56
|
+
* users or groups directly from Node.js, cron jobs or background workers.
|
|
57
|
+
*
|
|
58
|
+
* Built on the Node.js core `https` module — zero runtime dependencies.
|
|
59
|
+
*
|
|
60
|
+
* @author Gift Balogun <https://giftbalogun.name.ng/>
|
|
61
|
+
* @license MIT
|
|
62
|
+
*/
|
|
63
|
+
class SmartAlert {
|
|
64
|
+
constructor(config) {
|
|
65
|
+
var _a, _b, _c, _d, _e;
|
|
66
|
+
this.token = (_a = config === null || config === void 0 ? void 0 : config.token) !== null && _a !== void 0 ? _a : '';
|
|
67
|
+
this.defaultChatId = (_b = config === null || config === void 0 ? void 0 : config.chatId) !== null && _b !== void 0 ? _b : null;
|
|
68
|
+
this.appName = (_c = config === null || config === void 0 ? void 0 : config.appName) !== null && _c !== void 0 ? _c : null;
|
|
69
|
+
this.timeout = (_d = config === null || config === void 0 ? void 0 : config.timeout) !== null && _d !== void 0 ? _d : 10000;
|
|
70
|
+
this.throwOnError = (_e = config === null || config === void 0 ? void 0 : config.throwOnError) !== null && _e !== void 0 ? _e : true;
|
|
71
|
+
this.formatter = new messageFormatter_1.MessageFormatter();
|
|
72
|
+
if (!this.token) {
|
|
73
|
+
throw new SmartAlertError('SmartAlert-T: a Telegram bot token is required. Create one with @BotFather.');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/** Convenience factory. */
|
|
77
|
+
static make(config) {
|
|
78
|
+
return new SmartAlert(config);
|
|
79
|
+
}
|
|
80
|
+
/** Send a CRITICAL alert (🚨). */
|
|
81
|
+
critical(title, message, context = {}, chatId) {
|
|
82
|
+
return this.send(alertType_1.AlertType.CRITICAL, title, message, context, chatId);
|
|
83
|
+
}
|
|
84
|
+
/** Send a WARNING alert (⚠️). */
|
|
85
|
+
warning(title, message, context = {}, chatId) {
|
|
86
|
+
return this.send(alertType_1.AlertType.WARNING, title, message, context, chatId);
|
|
87
|
+
}
|
|
88
|
+
/** Send an INFO alert (ℹ️). */
|
|
89
|
+
info(title, message, context = {}, chatId) {
|
|
90
|
+
return this.send(alertType_1.AlertType.INFO, title, message, context, chatId);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Send an alert of an arbitrary (validated) type.
|
|
94
|
+
*/
|
|
95
|
+
async send(type, title, message, context = {}, chatId) {
|
|
96
|
+
if (!alertType_1.AlertType.isValid(type)) {
|
|
97
|
+
return this.fail(`SmartAlert-T: invalid alert type '${type}'. Use one of: ${alertType_1.AlertType.all().join(', ')}.`);
|
|
98
|
+
}
|
|
99
|
+
const target = chatId !== null && chatId !== void 0 ? chatId : this.defaultChatId;
|
|
100
|
+
if (target === null || target === undefined || target === '') {
|
|
101
|
+
return this.fail('SmartAlert-T: no chat id provided. Pass one explicitly or set a default chatId.');
|
|
102
|
+
}
|
|
103
|
+
const text = this.formatter.format(type, title, message, context, this.appName);
|
|
104
|
+
return this.dispatch(target, text);
|
|
105
|
+
}
|
|
106
|
+
/** Build a failure result (throwing or resolving based on config). */
|
|
107
|
+
fail(error, extra = {}) {
|
|
108
|
+
if (this.throwOnError) {
|
|
109
|
+
return Promise.reject(new SmartAlertError(error));
|
|
110
|
+
}
|
|
111
|
+
return Promise.resolve({ ok: false, error, ...extra });
|
|
112
|
+
}
|
|
113
|
+
/** Perform the HTTPS request to the Telegram Bot API. */
|
|
114
|
+
dispatch(chatId, text) {
|
|
115
|
+
return new Promise((resolve, reject) => {
|
|
116
|
+
const endpoint = new url_1.URL(`${SmartAlert.API_BASE}/bot${this.token}/sendMessage`);
|
|
117
|
+
const body = JSON.stringify({
|
|
118
|
+
chat_id: chatId,
|
|
119
|
+
text,
|
|
120
|
+
parse_mode: 'HTML',
|
|
121
|
+
disable_web_page_preview: true,
|
|
122
|
+
});
|
|
123
|
+
const options = {
|
|
124
|
+
method: 'POST',
|
|
125
|
+
hostname: endpoint.hostname,
|
|
126
|
+
path: endpoint.pathname + endpoint.search,
|
|
127
|
+
headers: {
|
|
128
|
+
'Content-Type': 'application/json',
|
|
129
|
+
'Content-Length': Buffer.byteLength(body),
|
|
130
|
+
},
|
|
131
|
+
timeout: this.timeout,
|
|
132
|
+
};
|
|
133
|
+
const settle = (err, extra = {}) => {
|
|
134
|
+
if (this.throwOnError) {
|
|
135
|
+
reject(new SmartAlertError(err));
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
resolve({ ok: false, error: err, ...extra });
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
const req = https.request(options, (res) => {
|
|
142
|
+
let data = '';
|
|
143
|
+
res.on('data', (chunk) => (data += chunk));
|
|
144
|
+
res.on('end', () => {
|
|
145
|
+
var _a;
|
|
146
|
+
let parsed = null;
|
|
147
|
+
try {
|
|
148
|
+
parsed = JSON.parse(data);
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
settle(`SmartAlert-T: unexpected Telegram response (HTTP ${res.statusCode}).`, {
|
|
152
|
+
raw: data,
|
|
153
|
+
});
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (!parsed.ok) {
|
|
157
|
+
settle(`SmartAlert-T: Telegram API error — ${(_a = parsed.description) !== null && _a !== void 0 ? _a : 'unknown error'}`, { response: parsed });
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
resolve(parsed);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
req.on('error', (e) => settle(`SmartAlert-T: transport error — ${e.message}`));
|
|
164
|
+
req.on('timeout', () => {
|
|
165
|
+
req.destroy();
|
|
166
|
+
settle('SmartAlert-T: request timed out.');
|
|
167
|
+
});
|
|
168
|
+
req.write(body);
|
|
169
|
+
req.end();
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
exports.SmartAlert = SmartAlert;
|
|
174
|
+
SmartAlert.VERSION = '1.0.0';
|
|
175
|
+
SmartAlert.API_BASE = 'https://api.telegram.org';
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "smart-alert-t",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "SmartAlert-T (SAT) — A lightweight Telegram alerting library for Node.js. The first line of defense for your servers and applications. Send critical, warning and info alerts to Telegram users or groups from cron jobs and background processes.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"type": "commonjs",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"README.md",
|
|
11
|
+
"LICENSE"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"prepublishOnly": "npm run build",
|
|
16
|
+
"test": "node test/smartAlert.test.js",
|
|
17
|
+
"example": "node examples/basic-usage.js"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"telegram",
|
|
21
|
+
"alert",
|
|
22
|
+
"alerting",
|
|
23
|
+
"notification",
|
|
24
|
+
"monitoring",
|
|
25
|
+
"cron",
|
|
26
|
+
"bot",
|
|
27
|
+
"smartalert",
|
|
28
|
+
"sat",
|
|
29
|
+
"devops"
|
|
30
|
+
],
|
|
31
|
+
"author": {
|
|
32
|
+
"name": "Gift Balogun",
|
|
33
|
+
"url": "https://giftbalogun.name.ng/"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://giftbalogun.name.ng/",
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "https://github.com/giftbalogun/smart-alert-t.git"
|
|
39
|
+
},
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/giftbalogun/smart-alert-t/issues"
|
|
42
|
+
},
|
|
43
|
+
"license": "MIT",
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=14"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/node": "^20.19.41",
|
|
49
|
+
"typescript": "^5.4.0"
|
|
50
|
+
}
|
|
51
|
+
}
|