@checkstack/notification-smtp-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,83 @@
1
+ # @checkstack/notification-smtp-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.0.4
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.0.3
34
+
35
+ ### Patch Changes
36
+
37
+ - @checkstack/notification-backend@0.1.1
38
+
39
+ ## 0.0.2
40
+
41
+ ### Patch 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
+ - Updated dependencies [ffc28f6]
76
+ - Updated dependencies [71275dd]
77
+ - Updated dependencies [ae19ff6]
78
+ - Updated dependencies [b55fae6]
79
+ - Updated dependencies [b354ab3]
80
+ - Updated dependencies [81f3f85]
81
+ - @checkstack/common@0.1.0
82
+ - @checkstack/backend-api@1.0.0
83
+ - @checkstack/notification-backend@0.1.0
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "@checkstack/notification-smtp-backend",
3
+ "version": "0.0.2",
4
+ "type": "module",
5
+ "main": "src/index.ts",
6
+ "exports": {
7
+ ".": "./src/index.ts"
8
+ },
9
+ "scripts": {
10
+ "typecheck": "tsc --noEmit"
11
+ },
12
+ "dependencies": {
13
+ "@checkstack/backend-api": "workspace:*",
14
+ "@checkstack/notification-backend": "workspace:*",
15
+ "@checkstack/common": "workspace:*",
16
+ "nodemailer": "^7.0.3",
17
+ "zod": "^4.2.1"
18
+ },
19
+ "devDependencies": {
20
+ "@types/nodemailer": "^6.4.17",
21
+ "@checkstack/tsconfig": "workspace:*",
22
+ "typescript": "^5.9.3"
23
+ }
24
+ }
package/src/index.ts ADDED
@@ -0,0 +1,194 @@
1
+ import {
2
+ createBackendPlugin,
3
+ type NotificationStrategy,
4
+ Versioned,
5
+ configString,
6
+ markdownToHtml,
7
+ markdownToPlainText,
8
+ wrapInEmailLayout,
9
+ configNumber,
10
+ configBoolean,
11
+ } from "@checkstack/backend-api";
12
+ import { notificationStrategyExtensionPoint } from "@checkstack/notification-backend";
13
+ import { z } from "zod";
14
+ import { createTransport, type Transporter } from "nodemailer";
15
+ import { pluginMetadata } from "./plugin-metadata";
16
+
17
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
18
+ // SMTP Configuration Schema
19
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
20
+
21
+ /**
22
+ * SMTP configuration schema with versioning support.
23
+ * Uses configString with x-secret for sensitive fields.
24
+ */
25
+ const smtpConfigSchemaV1 = z.object({
26
+ host: configString({}).optional().describe("SMTP server hostname"),
27
+ port: configNumber({}).default(587).describe("SMTP server port"),
28
+ secure: configBoolean({}).default(false).describe("Use TLS/SSL (port 465)"),
29
+ username: configString({ "x-secret": true })
30
+ .describe("SMTP username")
31
+ .optional(),
32
+ password: configString({ "x-secret": true })
33
+ .describe("SMTP password")
34
+ .optional(),
35
+ fromAddress: configString({})
36
+ .email()
37
+ .optional()
38
+ .describe("Sender email address"),
39
+ fromName: configString({}).optional().describe("Sender display name"),
40
+ });
41
+
42
+ type SmtpConfig = z.infer<typeof smtpConfigSchemaV1>;
43
+
44
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
45
+ // Email Layout Configuration Schema (Admin-Customizable)
46
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
47
+
48
+ /**
49
+ * Layout configuration for email styling.
50
+ * Admins can customize branding via the settings UI.
51
+ */
52
+ const smtpLayoutConfigSchemaV1 = z.object({
53
+ logoUrl: configString({})
54
+ .url()
55
+ .optional()
56
+ .describe("Logo URL (max 200px wide)"),
57
+ primaryColor: configString({ "x-color": true })
58
+ .describe("Primary brand color (hex)")
59
+ .default("#3b82f6"),
60
+ accentColor: configString({ "x-color": true })
61
+ .describe("Accent color for buttons")
62
+ .optional(),
63
+ footerText: configString({})
64
+ .default("This is an automated notification.")
65
+ .describe("Footer text"),
66
+ });
67
+
68
+ type SmtpLayoutConfig = z.infer<typeof smtpLayoutConfigSchemaV1>;
69
+
70
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
71
+ // SMTP Strategy Implementation
72
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
73
+
74
+ const smtpStrategy: NotificationStrategy<
75
+ SmtpConfig,
76
+ undefined,
77
+ SmtpLayoutConfig
78
+ > = {
79
+ id: "smtp",
80
+ displayName: "Email (SMTP)",
81
+ description: "Send notifications via email using SMTP",
82
+ icon: "Mail",
83
+
84
+ config: new Versioned({
85
+ version: 1,
86
+ schema: smtpConfigSchemaV1,
87
+ }),
88
+
89
+ layoutConfig: new Versioned({
90
+ version: 1,
91
+ schema: smtpLayoutConfigSchemaV1,
92
+ }),
93
+
94
+ contactResolution: { type: "auth-email" },
95
+
96
+ adminInstructions: `
97
+ ## SMTP Configuration
98
+
99
+ Configure your SMTP server to enable email notifications:
100
+
101
+ 1. Enter your SMTP server **hostname** and **port** (587 for TLS, 465 for SSL)
102
+ 2. If authentication is required, provide **username** and **password**
103
+ 3. Set the **sender email address** (must be valid for your mail server)
104
+ 4. Optionally configure a **display name** for the sender
105
+
106
+ > **Tip**: For Gmail, use \`smtp.gmail.com\` port 587 with an App Password.
107
+ `.trim(),
108
+
109
+ async send({ contact, notification, strategyConfig, layoutConfig }) {
110
+ // Validate required config
111
+ if (!strategyConfig.host || !strategyConfig.fromAddress) {
112
+ return {
113
+ success: false,
114
+ error: "SMTP is not configured. Please configure host and fromAddress.",
115
+ };
116
+ }
117
+
118
+ // Create transporter
119
+ const transporter: Transporter = createTransport({
120
+ host: strategyConfig.host,
121
+ port: strategyConfig.port,
122
+ secure: strategyConfig.secure,
123
+ auth: strategyConfig.username
124
+ ? {
125
+ user: strategyConfig.username,
126
+ pass: strategyConfig.password,
127
+ }
128
+ : undefined,
129
+ });
130
+
131
+ // Construct sender field
132
+ const from = strategyConfig.fromName
133
+ ? `"${strategyConfig.fromName}" <${strategyConfig.fromAddress}>`
134
+ : strategyConfig.fromAddress;
135
+
136
+ // Convert markdown body to HTML (if provided)
137
+ const bodyHtml = notification.body ? markdownToHtml(notification.body) : "";
138
+
139
+ // Generate plain text fallback
140
+ const plainText = notification.body
141
+ ? markdownToPlainText(notification.body)
142
+ : notification.title;
143
+
144
+ // Wrap content in the email layout with admin customizations
145
+ const html = wrapInEmailLayout({
146
+ title: notification.title,
147
+ bodyHtml,
148
+ importance: notification.importance,
149
+ action: notification.action,
150
+ logoUrl: layoutConfig?.logoUrl,
151
+ primaryColor: layoutConfig?.primaryColor,
152
+ accentColor: layoutConfig?.accentColor,
153
+ footerText: layoutConfig?.footerText,
154
+ });
155
+
156
+ try {
157
+ const result = await transporter.sendMail({
158
+ from,
159
+ to: contact,
160
+ subject: notification.title,
161
+ text: plainText,
162
+ html,
163
+ });
164
+
165
+ return {
166
+ success: true,
167
+ externalId: result.messageId,
168
+ };
169
+ } catch (error) {
170
+ return {
171
+ success: false,
172
+ error: error instanceof Error ? error.message : String(error),
173
+ };
174
+ }
175
+ },
176
+ };
177
+
178
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
179
+ // Plugin Definition
180
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
181
+
182
+ export default createBackendPlugin({
183
+ metadata: pluginMetadata,
184
+
185
+ register(env) {
186
+ // Get the notification strategy extension point
187
+ const extensionPoint = env.getExtensionPoint(
188
+ notificationStrategyExtensionPoint
189
+ );
190
+
191
+ // Register the SMTP strategy with our plugin metadata
192
+ extensionPoint.addStrategy(smtpStrategy, pluginMetadata);
193
+ },
194
+ });
@@ -0,0 +1,9 @@
1
+ import { definePluginMetadata } from "@checkstack/common";
2
+
3
+ /**
4
+ * Plugin metadata for the Notification SMTP backend.
5
+ * This is the single source of truth for the plugin ID.
6
+ */
7
+ export const pluginMetadata = definePluginMetadata({
8
+ pluginId: "notification-smtp",
9
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "@checkstack/tsconfig/backend.json"
3
+ }