@checkstack/notification-telegram-backend 0.0.2

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/CHANGELOG.md ADDED
@@ -0,0 +1,85 @@
1
+ # @checkstack/notification-telegram-backend
2
+
3
+ ## 0.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - d20d274: Initial release of all @checkstack packages. Rebranded from Checkmate to Checkstack with new npm organization @checkstack and domain checkstack.dev.
8
+ - Updated dependencies [d20d274]
9
+ - @checkstack/backend-api@0.0.2
10
+ - @checkstack/common@0.0.2
11
+ - @checkstack/notification-backend@0.0.2
12
+
13
+ ## 0.1.2
14
+
15
+ ### Patch Changes
16
+
17
+ - a65e002: Add compile-time type safety for Lucide icon names
18
+
19
+ - Add `LucideIconName` type and `lucideIconSchema` Zod schema to `@checkstack/common`
20
+ - Update backend interfaces (`AuthStrategy`, `NotificationStrategy`, `IntegrationProvider`, `CommandDefinition`) to use `LucideIconName`
21
+ - Update RPC contracts to use `lucideIconSchema` for proper type inference across RPC boundaries
22
+ - Simplify `SocialProviderButton` to use `DynamicIcon` directly (removes 30+ lines of pascalCase conversion)
23
+ - Replace static `iconMap` in `SearchDialog` with `DynamicIcon` for dynamic icon rendering
24
+ - Add fallback handling in `DynamicIcon` when icon name isn't found
25
+ - Fix legacy kebab-case icon names to PascalCase: `mail`→`Mail`, `send`→`Send`, `github`→`Github`, `key-round`→`KeyRound`, `network`→`Network`, `AlertCircle`→`CircleAlert`
26
+
27
+ - Updated dependencies [b4eb432]
28
+ - Updated dependencies [a65e002]
29
+ - @checkstack/backend-api@1.1.0
30
+ - @checkstack/notification-backend@0.1.2
31
+ - @checkstack/common@0.2.0
32
+
33
+ ## 0.1.1
34
+
35
+ ### Patch Changes
36
+
37
+ - @checkstack/notification-backend@0.1.1
38
+
39
+ ## 0.1.0
40
+
41
+ ### Minor Changes
42
+
43
+ - b354ab3: # Strategy Instructions Support & Telegram Notification Plugin
44
+
45
+ ## Strategy Instructions Interface
46
+
47
+ Added `adminInstructions` and `userInstructions` optional fields to the `NotificationStrategy` interface. These allow strategies to export markdown-formatted setup guides that are displayed in the configuration UI:
48
+
49
+ - **`adminInstructions`**: Shown when admins configure platform-wide strategy settings (e.g., how to create API keys)
50
+ - **`userInstructions`**: Shown when users configure their personal settings (e.g., how to link their account)
51
+
52
+ ### Updated Components
53
+
54
+ - `StrategyConfigCard` now accepts an `instructions` prop and renders it before config sections
55
+ - `StrategyCard` passes `adminInstructions` to `StrategyConfigCard`
56
+ - `UserChannelCard` renders `userInstructions` when users need to connect
57
+
58
+ ## New Telegram Notification Plugin
59
+
60
+ Added `@checkstack/notification-telegram-backend` plugin for sending notifications via Telegram:
61
+
62
+ - Uses [grammY](https://grammy.dev/) framework for Telegram Bot API integration
63
+ - Sends messages with MarkdownV2 formatting and inline keyboard buttons for actions
64
+ - Includes comprehensive admin instructions for bot setup via @BotFather
65
+ - Includes user instructions for account linking
66
+
67
+ ### Configuration
68
+
69
+ Admins need to configure a Telegram Bot Token obtained from @BotFather.
70
+
71
+ ### User Linking
72
+
73
+ The strategy uses `contactResolution: { type: "custom" }` for Telegram Login Widget integration. Full frontend integration for the Login Widget is pending future work.
74
+
75
+ ### Patch Changes
76
+
77
+ - Updated dependencies [ffc28f6]
78
+ - Updated dependencies [71275dd]
79
+ - Updated dependencies [ae19ff6]
80
+ - Updated dependencies [b55fae6]
81
+ - Updated dependencies [b354ab3]
82
+ - Updated dependencies [81f3f85]
83
+ - @checkstack/common@0.1.0
84
+ - @checkstack/backend-api@1.0.0
85
+ - @checkstack/notification-backend@0.1.0
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@checkstack/notification-telegram-backend",
3
+ "version": "0.0.2",
4
+ "type": "module",
5
+ "main": "src/index.ts",
6
+ "exports": {
7
+ ".": "./src/index.ts",
8
+ "./plugin-metadata": "./src/plugin-metadata.ts"
9
+ },
10
+ "scripts": {
11
+ "typecheck": "tsc --noEmit",
12
+ "lint": "eslint src --ext .ts"
13
+ },
14
+ "dependencies": {
15
+ "@checkstack/backend-api": "workspace:*",
16
+ "@checkstack/common": "workspace:*",
17
+ "@checkstack/notification-backend": "workspace:*",
18
+ "grammy": "^1.35.0",
19
+ "telegramify-markdown": "^1.3.2",
20
+ "zod": "^4.2.1"
21
+ },
22
+ "devDependencies": {
23
+ "@checkstack/tsconfig": "workspace:*",
24
+ "typescript": "^5.7.2"
25
+ }
26
+ }
package/src/index.ts ADDED
@@ -0,0 +1,216 @@
1
+ import { z } from "zod";
2
+ import { Bot } from "grammy";
3
+ import {
4
+ createBackendPlugin,
5
+ configString,
6
+ Versioned,
7
+ type NotificationStrategy,
8
+ type NotificationSendContext,
9
+ type NotificationDeliveryResult,
10
+ } from "@checkstack/backend-api";
11
+ import { notificationStrategyExtensionPoint } from "@checkstack/notification-backend";
12
+ import { pluginMetadata } from "./plugin-metadata";
13
+
14
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
15
+ // Configuration Schema
16
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
17
+
18
+ /**
19
+ * Admin configuration for Telegram strategy.
20
+ */
21
+ const telegramConfigSchemaV1 = z.object({
22
+ botToken: configString({ "x-secret": true }).describe(
23
+ "Telegram Bot API Token from @BotFather"
24
+ ),
25
+ });
26
+
27
+ type TelegramConfig = z.infer<typeof telegramConfigSchemaV1>;
28
+
29
+ /**
30
+ * User configuration for Telegram - users provide their own chat ID.
31
+ */
32
+ const telegramUserConfigSchema = z.object({
33
+ chatId: z.string().describe("Your Telegram Chat ID"),
34
+ });
35
+
36
+ type TelegramUserConfig = z.infer<typeof telegramUserConfigSchema>;
37
+
38
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
39
+ // Instructions
40
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
41
+
42
+ const adminInstructions = `
43
+ ## Setup a Telegram Bot
44
+
45
+ 1. Open [@BotFather](https://t.me/BotFather) in Telegram
46
+ 2. Send \`/newbot\` and follow the prompts to create your bot
47
+ 3. Copy the **Bot Token** (format: \`123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11\`)
48
+ 4. Send \`/setdomain\` to BotFather and set your domain (e.g., \`yourdomain.com\`)
49
+
50
+ > **Note**: The domain must match where Checkstack is hosted for the Login Widget to work.
51
+ `.trim();
52
+
53
+ const userInstructions = `
54
+ ## Get Your Telegram Chat ID
55
+
56
+ 1. Start a chat with your organization's notification bot
57
+ 2. Send any message to the bot
58
+ 3. Open [@userinfobot](https://t.me/userinfobot) and send \`/start\` to get your Chat ID
59
+ 4. Enter your Chat ID in the field above and save
60
+
61
+ > **Note**: Make sure you've messaged the notification bot before sending a notification, or the bot won't be able to reach you.
62
+ `.trim();
63
+
64
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
65
+ // Telegram Strategy Implementation
66
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
67
+
68
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
69
+ const telegramifyMarkdown = require("telegramify-markdown") as (
70
+ markdown: string,
71
+ unsupportedTagsStrategy?: "escape" | "remove" | "keep"
72
+ ) => string;
73
+
74
+ /**
75
+ * Telegram notification strategy using grammY.
76
+ */
77
+ const telegramStrategy: NotificationStrategy<
78
+ TelegramConfig,
79
+ TelegramUserConfig
80
+ > = {
81
+ id: "telegram",
82
+ displayName: "Telegram",
83
+ description: "Send notifications via Telegram bot messages",
84
+ icon: "Send",
85
+
86
+ config: new Versioned({
87
+ version: 1,
88
+ schema: telegramConfigSchemaV1,
89
+ }),
90
+
91
+ // User-config resolution - users enter their chat ID manually
92
+ contactResolution: { type: "user-config", field: "chatId" },
93
+
94
+ userConfig: new Versioned({
95
+ version: 1,
96
+ schema: telegramUserConfigSchema,
97
+ }),
98
+
99
+ adminInstructions,
100
+ userInstructions,
101
+
102
+ async send(
103
+ context: NotificationSendContext<TelegramConfig, TelegramUserConfig>
104
+ ): Promise<NotificationDeliveryResult> {
105
+ const { userConfig, notification, strategyConfig } = context;
106
+
107
+ if (!strategyConfig.botToken) {
108
+ return {
109
+ success: false,
110
+ error: "Telegram bot token not configured",
111
+ };
112
+ }
113
+
114
+ if (!userConfig?.chatId) {
115
+ return {
116
+ success: false,
117
+ error: "User has not configured their Telegram chat ID",
118
+ };
119
+ }
120
+
121
+ try {
122
+ // Create bot instance
123
+ const bot = new Bot(strategyConfig.botToken);
124
+
125
+ // Build message body using telegramify-markdown for proper escaping and conversion
126
+ let messageBody = "";
127
+ if (notification.body) {
128
+ messageBody = telegramifyMarkdown(notification.body, "escape");
129
+ }
130
+
131
+ // Build title (bold) with proper escaping
132
+ const messageTitle = telegramifyMarkdown(
133
+ `**${notification.title}**`,
134
+ "escape"
135
+ );
136
+
137
+ // Add importance indicator
138
+ const importanceEmoji = {
139
+ info: "ℹ️",
140
+ warning: "⚠️",
141
+ critical: "🚨",
142
+ };
143
+ let messageText = `${
144
+ importanceEmoji[notification.importance]
145
+ } ${messageTitle}`;
146
+ if (messageBody) {
147
+ messageText += `\n\n${messageBody}`;
148
+ }
149
+
150
+ // Build inline keyboard for action button
151
+ const actionUrl = notification.action?.url;
152
+
153
+ // Don't show action button for localhost URLs (Telegram rejects them)
154
+ // Instead, add as inline link in the message
155
+ const isLocalhost =
156
+ actionUrl?.includes("localhost") || actionUrl?.includes("127.0.0.1");
157
+
158
+ if (notification.action && actionUrl && isLocalhost) {
159
+ // Add action as plain text (Telegram won't make localhost links clickable anyway)
160
+ // This makes it easier to copy the URL for debugging
161
+ const plainTextAction = `📎 ${notification.action.label}:\n${actionUrl}\n\n_Note: Telegram blocks localhost URLs, so no inline button is shown._`;
162
+ messageText += `\n\n${telegramifyMarkdown(plainTextAction, "escape")}`;
163
+ }
164
+
165
+ const inlineKeyboard =
166
+ notification.action && actionUrl && !isLocalhost
167
+ ? {
168
+ inline_keyboard: [
169
+ [
170
+ {
171
+ text: notification.action.label,
172
+ url: actionUrl,
173
+ },
174
+ ],
175
+ ],
176
+ }
177
+ : undefined;
178
+
179
+ // Send the message
180
+ const result = await bot.api.sendMessage(userConfig.chatId, messageText, {
181
+ parse_mode: "MarkdownV2",
182
+ reply_markup: inlineKeyboard,
183
+ });
184
+
185
+ return {
186
+ success: true,
187
+ externalId: String(result.message_id),
188
+ };
189
+ } catch (error) {
190
+ const message =
191
+ error instanceof Error ? error.message : "Unknown Telegram API error";
192
+ return {
193
+ success: false,
194
+ error: `Failed to send Telegram message: ${message}`,
195
+ };
196
+ }
197
+ },
198
+ };
199
+
200
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
201
+ // Plugin Definition
202
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
203
+
204
+ export default createBackendPlugin({
205
+ metadata: pluginMetadata,
206
+
207
+ register(env) {
208
+ // Get the notification strategy extension point
209
+ const extensionPoint = env.getExtensionPoint(
210
+ notificationStrategyExtensionPoint
211
+ );
212
+
213
+ // Register the Telegram strategy with our plugin metadata
214
+ extensionPoint.addStrategy(telegramStrategy, pluginMetadata);
215
+ },
216
+ });
@@ -0,0 +1,5 @@
1
+ import type { PluginMetadata } from "@checkstack/common";
2
+
3
+ export const pluginMetadata: PluginMetadata = {
4
+ pluginId: "notification-telegram",
5
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "@checkstack/tsconfig/backend.json"
3
+ }