notifkit 0.1.1 → 0.1.3
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/README.md +344 -51
- package/dist/index.d.mts +6 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
# notifkit
|
|
4
4
|
|
|
5
|
-
**
|
|
6
|
-
|
|
5
|
+
**You shouldn't have to build a notification system.**
|
|
6
|
+
|
|
7
|
+
Self-hosted notification infrastructure for product notifications. One API call handles email, SMS, push, and webhooks — with preferences, quiet hours, retries, fallback, scheduling, workflows, and delivery logs built in.
|
|
8
|
+
|
|
9
|
+
[](https://www.npmjs.com/package/notifkit) [](https://www.npmjs.com/package/notifkit) [](https://github.com/devkitshq/notifkit) [](https://www.typescriptlang.org/) [](https://nodejs.org) [](./LICENSE)
|
|
7
10
|
|
|
8
11
|
[Documentation](https://notifkit.dev/docs/) · [Quickstart](https://notifkit.dev/docs/quickstart.html) · [Examples](https://notifkit.dev/docs/examples.html) · [notifkit.dev](https://notifkit.dev)
|
|
9
12
|
|
|
@@ -11,83 +14,373 @@ One call delivers to email, SMS, push, and webhook — routed by preference, qui
|
|
|
11
14
|
|
|
12
15
|
---
|
|
13
16
|
|
|
14
|
-
|
|
17
|
+
### The first notification is easy
|
|
15
18
|
|
|
16
|
-
```
|
|
17
|
-
|
|
19
|
+
```ts
|
|
20
|
+
await sendEmail({
|
|
21
|
+
to: user.email,
|
|
22
|
+
subject: "Order Shipped",
|
|
23
|
+
...
|
|
24
|
+
});
|
|
18
25
|
```
|
|
19
26
|
|
|
20
|
-
|
|
21
|
-
`node_modules/notifkit/drizzle` — and in development notifkit starts throwaway Postgres
|
|
22
|
-
and Redis containers for you, so Docker is the only prerequisite to try it.
|
|
27
|
+
### Then reality hits
|
|
23
28
|
|
|
24
|
-
|
|
29
|
+
Users opt out. People are asleep. Push tokens die. Providers throw 503s. Some channels fail and need fallback. You need timezone-aware quiet hours, future scheduling, deduplication, multi-channel templates, delivery logs, unsubscribe handling, multi-step workflows, and a dead-letter queue nobody wants to maintain.
|
|
25
30
|
|
|
26
|
-
|
|
31
|
+
**notifkit is that machinery, already built.**
|
|
27
32
|
|
|
28
|
-
|
|
33
|
+
Your app makes one typed call. notifkit handles the rest — **who gets it, which channel to use, when to send it, whether they're allowed to receive it, and what happens when delivery fails.**
|
|
29
34
|
|
|
30
35
|
```ts
|
|
36
|
+
import { notifkit } from "notifkit";
|
|
37
|
+
|
|
31
38
|
await notifkit.notify({
|
|
32
39
|
user: "usr_123",
|
|
33
40
|
template: "order-shipped",
|
|
34
41
|
channels: ["push", "email"],
|
|
35
|
-
fallback: true,
|
|
42
|
+
fallback: true,
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
> **Push first. If it fails, email.**
|
|
47
|
+
>
|
|
48
|
+
> Preferences, consent, quiet hours, retries, deduplication, throttling, template rendering, and delivery tracking happen behind that single call.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## What actually runs
|
|
53
|
+
|
|
54
|
+
notifkit is both an **orchestration engine** and a **typed SDK**.
|
|
55
|
+
|
|
56
|
+
```mermaid
|
|
57
|
+
flowchart TD
|
|
58
|
+
App["Your Application / AI Agent<br/>Typed SDK · REST API · MCP Server"]
|
|
59
|
+
|
|
60
|
+
App -->|"HTTP POST /v1/notify"| API
|
|
61
|
+
|
|
62
|
+
API["Notifkit API Server<br/>Schema Validation · Auth · Multi-Tenancy<br/>Idempotency Gate · Priority Queue Ingestion"]
|
|
63
|
+
|
|
64
|
+
API --> PG
|
|
65
|
+
API --> REDIS
|
|
66
|
+
|
|
67
|
+
PG[("PostgreSQL — Storage<br/>Users · Preferences<br/>Templates · Workflows<br/>Delivery Logs · DLQ")]
|
|
68
|
+
REDIS[("Redis — Streams / ZSET<br/>Priority Queues<br/>Scheduled Sends<br/>Sliding Rate Limits")]
|
|
69
|
+
|
|
70
|
+
subgraph WORKERS["Background Workers Pipeline"]
|
|
71
|
+
direction LR
|
|
72
|
+
ENRICH["Enricher<br/>(Resolve)"] --> ENGINE["Engine<br/>(Quiet Hours)"] --> DELIVER["Delivery<br/>(Rate Limits / CB)"]
|
|
73
|
+
ENGINE --> SCHED["Scheduler<br/>(sendAt / QH)"]
|
|
74
|
+
SCHED --> DELIVER
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
REDIS -->|"consume"| ENRICH
|
|
78
|
+
ENRICH -.->|"read / write state"| PG
|
|
79
|
+
DELIVER -.->|"delivery logs"| PG
|
|
80
|
+
DELIVER -->|"Dispatch"| PROVIDERS
|
|
81
|
+
|
|
82
|
+
PROVIDERS["Provider Transports<br/>Email: Resend, SES, Postmark · Push: Firebase (FCM)<br/>SMS: Twilio, MessageBird · Webhooks: Custom HTTP"]
|
|
83
|
+
|
|
84
|
+
classDef entry stroke:#6366f1,stroke-width:2px
|
|
85
|
+
classDef store stroke:#0ea5e9,stroke-width:2px
|
|
86
|
+
classDef work stroke:#22c55e,stroke-width:2px
|
|
87
|
+
class App,API,PROVIDERS entry
|
|
88
|
+
class PG,REDIS store
|
|
89
|
+
class ENRICH,ENGINE,DELIVER,SCHED work
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
- **`NotifkitServer`**: Runs the HTTP REST API router (`/v1/notify`, `/health`, `/metrics`) and the background worker pipelines (enricher, decision engine, scheduler, delivery).
|
|
93
|
+
- **`NotifkitClient`**: The lightweight client your application uses to trigger notifications, sync templates, and manage users over HTTP.
|
|
94
|
+
|
|
95
|
+
### Topologies
|
|
96
|
+
|
|
97
|
+
- **Single Process (Monolith)**: Run the API and all workers in the same Node.js process (`services: ["all"]`). Perfect for small-to-medium apps, side projects, and staging.
|
|
98
|
+
- **Distributed Services**: Run stateless API servers (`services: ["api"]`) behind a load balancer and scale worker pools (`services: ["enricher", "engine", "delivery", "scheduler"]`) horizontally across Redis Streams consumer groups.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Battle-tested for production
|
|
103
|
+
|
|
104
|
+
> **Battle-tested in production:** notifkit powers production notification pipelines handling **thousands of emails, push notifications, and OTPs every day.**
|
|
105
|
+
>
|
|
106
|
+
> It is the infrastructure we built because we needed it ourselves — rather than spending months reinventing distributed notification plumbing or paying SaaS tolls per alert.
|
|
107
|
+
|
|
108
|
+
**Your servers. Your providers. Your data. Zero notification SaaS markups.**
|
|
109
|
+
|
|
110
|
+
### Reliability & Chaos Engineering
|
|
111
|
+
|
|
112
|
+
Because notification delivery is mission-critical, every pipeline component is tested against extreme failure conditions:
|
|
113
|
+
|
|
114
|
+
```mermaid
|
|
115
|
+
flowchart LR
|
|
116
|
+
S1["Redis Streams"] -->|"Kill Worker (SIGKILL)"| M1["Auto-Claim and Replay"] --> O1["Zero Lost Messages"]
|
|
117
|
+
S2["Connection Loss"] -->|"Drop DB / Redis"| M2["Auto-Reconnect / Retry"] --> O2["In-Flight State Intact"]
|
|
118
|
+
S3["10k+ Messages"] -->|"Burst"| M3["Concurrency and Limits"] --> O3["Flat Memory, No Leaks"]
|
|
119
|
+
|
|
120
|
+
classDef fault stroke:#ef4444,stroke-width:2px
|
|
121
|
+
classDef guard stroke:#6366f1,stroke-width:2px
|
|
122
|
+
classDef result stroke:#22c55e,stroke-width:2px
|
|
123
|
+
class S1,S2,S3 fault
|
|
124
|
+
class M1,M2,M3 guard
|
|
125
|
+
class O1,O2,O3 result
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
- **Chaos Monkey Testing (`tests/chaos/crash.test.ts`)**: Background worker processes are randomly terminated with `SIGKILL` during active, high-throughput message streaming. Consumer group Pending Entries List (PEL) re-claims guarantee **zero lost messages** and seamless failover.
|
|
129
|
+
- **Infrastructure Recovery Testing (`tests/chaos/recovery.test.ts`)**: PostgreSQL and Redis connections are forcefully severed and restored under live traffic. Verifies automatic client reconnection, worker backpressure, and durable state resumption.
|
|
130
|
+
- **High-Throughput Load Testing (`tests/chaos/load.test.ts`)**: Stressed with bursts of **10,000+ notifications** across parallel worker pools, verifying queue drain velocity, sliding-window rate limiters, and flat memory profiles without leaks.
|
|
131
|
+
- **Race Conditions & Concurrency (`tests/race-conditions.test.ts`, `tests/idempotency.test.ts`)**: Hardened against concurrent duplicate dispatches, overlapping quiet-hour boundary evaluations, atomic user updates, and 24-hour idempotency key deduplication.
|
|
132
|
+
- **100% Real Ephemeral Containers**: Unit, integration, and chaos test suites execute against real PostgreSQL and Redis containers via [Testcontainers](https://testcontainers.com), eliminating mocks for core storage and streaming primitives.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## What you get
|
|
137
|
+
|
|
138
|
+
| The problem you don't want to build | How notifkit solves it |
|
|
139
|
+
| :------------------------------------------------------- | :------------------------------------------------------------------- |
|
|
140
|
+
| **“Should this user receive it?”** | User preferences, topic opt-outs, and consent gates |
|
|
141
|
+
| **“Is this a bad time to send?”** | Timezone-aware quiet hours that defer non-urgent sends |
|
|
142
|
+
| **“What if push fails?”** | Automatic ordered multi-channel fallback (`push` → `email` → `sms`) |
|
|
143
|
+
| **“What if my worker crashes?”** | Redis Streams consumer groups, retries, and durable idempotency |
|
|
144
|
+
| **“What if an event fires twice?”** | 24-hour deduplication via idempotency keys |
|
|
145
|
+
| **“Can I send this later?”** | Priority scheduling with `sendAt` and cancellation before dispatch |
|
|
146
|
+
| **“Can I send this 3 days after signup?”** | Stateful multi-step workflows with `wait` and `waitForEvent` |
|
|
147
|
+
| **“How do I know what happened?”** | Queryable delivery logs, Prometheus metrics, and campaign reporting |
|
|
148
|
+
| **“What happens when a provider goes down?”** | Circuit breakers, exponential backoff, and DLQ replay |
|
|
149
|
+
| **“What about bounces and spam complaints?”** | RFC 8058 one-click unsubscribe and automatic hard-bounce suppression |
|
|
150
|
+
| **“What if I don't want another SaaS holding my data?”** | 100% self-hosted on your PostgreSQL and Redis |
|
|
151
|
+
|
|
152
|
+
> **The idea is simple:** You decide what to say. **notifkit handles getting it there reliably.**
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## What notifkit is — and what it isn't
|
|
157
|
+
|
|
158
|
+
**What it is:** the durable notification infrastructure layer running directly inside your own stack.
|
|
159
|
+
|
|
160
|
+
**What it isn't:** a marketing automation suite.
|
|
161
|
+
|
|
162
|
+
notifkit is not Customer.io, OneSignal, or SendGrid. You bring your own provider accounts — your keys, your billing, your deliverability.
|
|
163
|
+
|
|
164
|
+
First-party providers ship for Resend and Firebase Cloud Messaging. Anything else is a simple `Transport` class with a `send()` method.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Quickstart
|
|
169
|
+
|
|
170
|
+
### 1. Install
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
npm install notifkit @notifkit/provider-resend
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### 2. Run the engine and dispatch your first notification
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
import { NotifkitServer, NotifkitClient } from "notifkit";
|
|
180
|
+
import { ResendTransport } from "@notifkit/provider-resend";
|
|
181
|
+
|
|
182
|
+
// 1. Start the server (runs API + workers; auto-starts Postgres & Redis in dev)
|
|
183
|
+
const server = new NotifkitServer({
|
|
184
|
+
services: ["all"],
|
|
185
|
+
port: 3000,
|
|
186
|
+
providers: [new ResendTransport({ apiKey: process.env.RESEND_API_KEY! })],
|
|
187
|
+
});
|
|
188
|
+
await server.start();
|
|
189
|
+
|
|
190
|
+
// 2. Instantiate client and register a template
|
|
191
|
+
const notifkit = new NotifkitClient({ baseUrl: "http://localhost:3000" });
|
|
192
|
+
|
|
193
|
+
await notifkit.syncTemplates({
|
|
194
|
+
templates: [
|
|
195
|
+
{
|
|
196
|
+
id: "order-shipped",
|
|
197
|
+
channel: "email",
|
|
198
|
+
content: { subject: "Order #{{orderId}} Shipped", text: "Your order is on the way!" },
|
|
199
|
+
},
|
|
200
|
+
],
|
|
36
201
|
});
|
|
202
|
+
|
|
203
|
+
// 3. Register user and dispatch
|
|
204
|
+
await notifkit.addUser({ id: "usr_123", email: "alex@acme.com" });
|
|
205
|
+
|
|
206
|
+
await notifkit.notify({
|
|
207
|
+
user: "usr_123",
|
|
208
|
+
template: "order-shipped",
|
|
209
|
+
channels: ["email"],
|
|
210
|
+
data: { orderId: "9481" },
|
|
211
|
+
});
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### 3. Or call directly via REST API
|
|
215
|
+
|
|
216
|
+
You don't need the Node.js SDK — notifkit exposes a standard HTTP REST API, so you can dispatch notifications and manage resources from any language (cURL, Python, Go, etc.):
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
curl -X POST http://localhost:3000/v1/notify \
|
|
220
|
+
-H "Content-Type: application/json" \
|
|
221
|
+
-d '{
|
|
222
|
+
"user": "usr_123",
|
|
223
|
+
"template": "order-shipped",
|
|
224
|
+
"channels": ["email"],
|
|
225
|
+
"data": { "orderId": "9481" }
|
|
226
|
+
}'
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Development vs. Production
|
|
230
|
+
|
|
231
|
+
- **Local Development**: Docker is the only prerequisite. In development, notifkit starts throwaway PostgreSQL and Redis containers automatically.
|
|
232
|
+
- **Production**: Node 22+, PostgreSQL, Redis. Run migrations by pointing `drizzle-kit` at `node_modules/notifkit/drizzle`.
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## Agent-operable
|
|
237
|
+
|
|
238
|
+
**notifkit isn't just an API your application can call — your AI agent can operate it directly.**
|
|
239
|
+
|
|
240
|
+
Connect the notifkit MCP server ([`@notifkit/mcp`](./packages/mcp)) to Claude Code, Cursor, Claude Desktop, Gemini, or any MCP-compatible agent:
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
npx -y @notifkit/mcp
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Ask your agent
|
|
247
|
+
|
|
248
|
+
```text
|
|
249
|
+
You: Why didn't usr_9182 receive their password reset?
|
|
250
|
+
|
|
251
|
+
Agent: The notification was suppressed because usr_9182's email
|
|
252
|
+
address has a hard-bounce suppression from yesterday.
|
|
37
253
|
```
|
|
38
254
|
|
|
39
|
-
|
|
255
|
+
Your application and your AI agents use the **same notification infrastructure**:
|
|
256
|
+
|
|
257
|
+
- **Send & dispatch** — Send one-off notifications or campaigns to users, lists, and segments (`send_notification`, `send_campaign`)
|
|
258
|
+
- **Investigate & triage** — Diagnose delivery issues by inspecting message histories, provider responses, and quiet hours (`get_delivery_logs`, `get_notification`)
|
|
259
|
+
- **Schedule & cancel** — Schedule future sends and cancel pending notifications (`list_scheduled`, `cancel_notification`)
|
|
260
|
+
- **Campaign analytics** — Check delivery, open, click, bounce, and complaint metrics (`list_campaigns`, `get_campaign_stats`)
|
|
261
|
+
- **Template management** — List, preview, and update templates with sample data (`list_templates`, `preview_template`, `upsert_template`)
|
|
262
|
+
- **Users & preferences** — Look up users, contacts, preferences, and segment membership (`list_users`, `get_user_preferences`, `update_user_preferences`)
|
|
263
|
+
- **Workflow operations** — Trigger workflows and inspect workflow runs (`create_workflow`, `trigger_workflow`, `get_workflow_run`)
|
|
264
|
+
- **Suppressions & health** — Manage bounce suppressions, check system queues, and replay dead-letter messages (`list_suppressions`, `get_dead_letters`, `replay_dead_letter`)
|
|
265
|
+
|
|
266
|
+
### From “write a script” to “just ask”
|
|
267
|
+
|
|
268
|
+
| Without an agent | With NotifKit MCP |
|
|
269
|
+
| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
270
|
+
| Jump into the DB to find contact info → open Twilio/Resend or write a throwaway script → format the payload → check their timezone manually → fire it off → hope it delivered | **You:** _“Send an urgent update to alex@acme.com that his package was lost in transit and support is rushing a replacement — text him if push doesn't deliver.”_<br><br>**Agent:** Looks up `alex@acme.com` → renders template → dispatches push with SMS fallback → bypasses quiet hours for urgent delivery → tracks delivery status → confirms it hit his phone |
|
|
40
271
|
|
|
41
|
-
|
|
42
|
-
| ----------------- | ----------------------------------------------------------------------------------- |
|
|
43
|
-
| **Channels** | `email`, `sms`, `push`, `webhook` |
|
|
44
|
-
| **Targeting** | A user, a list of users, a segment, or a topic |
|
|
45
|
-
| **Priorities** | `low`, `normal`, `high`, `critical` — separate stream lanes |
|
|
46
|
-
| **Scheduling** | Future sends with `sendAt`, quiet-hours deferral, cancel before dispatch |
|
|
47
|
-
| **Preferences** | Per-user channel and topic opt-outs, quiet hours, contact-level overrides |
|
|
48
|
-
| **Workflows** | Multi-step sequences with `wait`, `waitForEvent`, and `notify` steps |
|
|
49
|
-
| **Reliability** | Redis Streams, 24h idempotency, backoff retries, DLQ, provider circuit breakers |
|
|
50
|
-
| **Templates** | `{{var}}` interpolation with escaping decided by the destination field |
|
|
51
|
-
| **AI** | Optional LLM augmentation before render, via the Vercel AI SDK |
|
|
52
|
-
| **Multi-tenancy** | Projects with isolated keys, data, and rate limits |
|
|
53
|
-
| **Consent** | RFC 8058 one-click unsubscribe; complaints and hard bounces suppress automatically |
|
|
54
|
-
| **Reporting** | Tag a send with a `campaign` label, then read delivery and engagement totals back |
|
|
55
|
-
| **Agents** | An MCP server ([`@notifkit/mcp`](./packages/mcp)) driving all of it from a terminal |
|
|
56
|
-
| **Observability** | Prometheus `/metrics`, `/health`, `/live`, `/ready`, and a queryable delivery log |
|
|
272
|
+
[Set up MCP](https://notifkit.dev/docs/mcp.html) · [MCP documentation](https://notifkit.dev/docs/mcp.html)
|
|
57
273
|
|
|
58
|
-
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## AI-assisted migration
|
|
59
277
|
|
|
60
|
-
|
|
278
|
+
Already have notification code scattered across your application?
|
|
61
279
|
|
|
62
|
-
|
|
280
|
+
Point your coding agent at:
|
|
281
|
+
|
|
282
|
+
```text
|
|
283
|
+
https://notifkit.dev/llms-full.txt
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
It can understand notifkit's API and help identify ad-hoc notification code in your repository and refactor it into durable notifkit calls.
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## Feature matrix
|
|
291
|
+
|
|
292
|
+
| | |
|
|
293
|
+
| :------------------ | :------------------------------------------------------------------------------------- |
|
|
294
|
+
| **Channels** | `email`, `sms`, `push`, `webhook` |
|
|
295
|
+
| **Targeting** | A user, a list of users, a segment, or a topic |
|
|
296
|
+
| **Priorities** | `low`, `normal`, `high`, `critical` — separate stream lanes |
|
|
297
|
+
| **Scheduling** | Future sends with `sendAt`, quiet-hours deferral, cancellation |
|
|
298
|
+
| **Preferences** | Per-user channel and topic opt-outs, quiet hours, contact-level overrides |
|
|
299
|
+
| **Workflows** | Multi-step sequences with `wait`, `waitForEvent`, and `notify` steps |
|
|
300
|
+
| **Reliability** | Redis Streams, 24h idempotency, retries, DLQ, provider circuit breakers |
|
|
301
|
+
| **Templates** | `{{var}}` interpolation with destination-aware escaping |
|
|
302
|
+
| **AI** | Optional LLM augmentation before render via the Vercel AI SDK |
|
|
303
|
+
| **Multi-tenancy** | Projects with isolated keys, data, and rate limits |
|
|
304
|
+
| **Consent** | RFC 8058 one-click unsubscribe; complaints and hard bounces suppress automatically |
|
|
305
|
+
| **Reporting** | Campaign labels with delivery and engagement totals |
|
|
306
|
+
| **Agent operation** | MCP server for sending, triage, campaigns, templates, workflows, and system operations |
|
|
307
|
+
| **Observability** | Prometheus `/metrics`, `/health`, `/live`, `/ready`, and queryable delivery logs |
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## Providers
|
|
312
|
+
|
|
313
|
+
Bring your own provider accounts.
|
|
314
|
+
|
|
315
|
+
First-party packages:
|
|
316
|
+
|
|
317
|
+
- [`@notifkit/provider-resend`](./packages/provider-resend) — transactional email via Resend
|
|
318
|
+
- [`@notifkit/provider-fcm`](./packages/provider-fcm) — push notifications via Firebase Cloud Messaging
|
|
319
|
+
|
|
320
|
+
For anything else, implement a simple `Transport`:
|
|
321
|
+
|
|
322
|
+
```ts
|
|
323
|
+
class MyTransport implements Transport {
|
|
324
|
+
async send(message) {
|
|
325
|
+
// Send through Twilio, SES, Postmark, APNs,
|
|
326
|
+
// SendGrid, a custom webhook, or anything else.
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
**Your keys. Your billing. Your deliverability.**
|
|
332
|
+
|
|
333
|
+
---
|
|
63
334
|
|
|
64
335
|
## Documentation
|
|
65
336
|
|
|
66
|
-
Everything lives at **
|
|
337
|
+
Everything lives at [**notifkit.dev/docs**](https://notifkit.dev/docs/).
|
|
338
|
+
|
|
339
|
+
| | |
|
|
340
|
+
| :----------------------------------------------------------------------------- | :------------------------------------------------------- |
|
|
341
|
+
| [Quickstart](https://notifkit.dev/docs/quickstart.html) | Install to first delivered notification |
|
|
342
|
+
| [How it works](https://notifkit.dev/docs/concepts.html) | Core concepts and the notification pipeline |
|
|
343
|
+
| [Channels & fallback](https://notifkit.dev/docs/guides/routing.html) | Multicast, ordered fallback, and custom transports |
|
|
344
|
+
| [Preferences & quiet hours](https://notifkit.dev/docs/guides/preferences.html) | Preference, consent, and timing rules |
|
|
345
|
+
| [Templates & AI](https://notifkit.dev/docs/guides/templates.html) | Interpolation, escaping, and per-channel content |
|
|
346
|
+
| [Segments & scheduling](https://notifkit.dev/docs/guides/segments.html) | Fan-out, priority lanes, `sendAt`, and idempotency |
|
|
347
|
+
| [Workflows](https://notifkit.dev/docs/guides/workflows.html) | Multi-step sequences, recurring sends, and digests |
|
|
348
|
+
| [Examples](https://notifkit.dev/docs/examples.html) | Runnable projects |
|
|
349
|
+
| [Architecture](https://notifkit.dev/docs/architecture.html) | Streams, delivery guarantees, topologies, and data model |
|
|
350
|
+
| [Deployment](https://notifkit.dev/docs/deployment.html) | Docker, Compose, and production topologies |
|
|
351
|
+
| [Operations](https://notifkit.dev/docs/operations.html) | Health, metrics, DLQ, key rotation, and shutdown |
|
|
352
|
+
| [Reference](https://notifkit.dev/docs/reference.html) | API, payloads, and SDK methods |
|
|
353
|
+
| [MCP server](https://notifkit.dev/docs/mcp.html) | Operate notifkit from an AI agent |
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## Why build this?
|
|
67
358
|
|
|
68
|
-
|
|
69
|
-
| ------------------------------------------------------------------------------ | ---------------------------------------------------------- |
|
|
70
|
-
| [Quickstart](https://notifkit.dev/docs/quickstart.html) | Install to first delivered notification, about ten minutes |
|
|
71
|
-
| [How it works](https://notifkit.dev/docs/concepts.html) | The five nouns and the pipeline they move through |
|
|
72
|
-
| [Channels & fallback](https://notifkit.dev/docs/guides/routing.html) | Multicast, ordered fallback, writing a transport |
|
|
73
|
-
| [Preferences & quiet hours](https://notifkit.dev/docs/guides/preferences.html) | The four gates every notification passes |
|
|
74
|
-
| [Templates & AI](https://notifkit.dev/docs/guides/templates.html) | Interpolation, escaping, per-channel content |
|
|
75
|
-
| [Segments & scheduling](https://notifkit.dev/docs/guides/segments.html) | Fan-out, priority lanes, `sendAt`, idempotency |
|
|
76
|
-
| [Workflows](https://notifkit.dev/docs/guides/workflows.html) | Multi-step sequences, recurring sends, digests |
|
|
77
|
-
| [Examples](https://notifkit.dev/docs/examples.html) | The five runnable projects in [`examples/`](./examples) |
|
|
78
|
-
| [Architecture](https://notifkit.dev/docs/architecture.html) | Streams, delivery guarantees, topologies, data model |
|
|
79
|
-
| [Deployment](https://notifkit.dev/docs/deployment.html) | Dockerfile, Compose, splitting API from workers |
|
|
80
|
-
| [Operations](https://notifkit.dev/docs/operations.html) | Health, metrics, the DLQ, key rotation, shutdown |
|
|
81
|
-
| [Reference](https://notifkit.dev/docs/reference.html) | Every endpoint, payload shape, and SDK method |
|
|
82
|
-
| [MCP server](https://notifkit.dev/docs/mcp.html) | Send and report on campaigns from a terminal agent |
|
|
359
|
+
Because notification infrastructure looks simple until you're responsible for it.
|
|
83
360
|
|
|
84
|
-
|
|
361
|
+
You can spend months building queues, retries, provider adapters, preference systems, quiet-hour logic, workflows, suppression handling, and operational tooling.
|
|
85
362
|
|
|
86
|
-
|
|
363
|
+
Or you can use the infrastructure we built for ourselves.
|
|
364
|
+
|
|
365
|
+
**notifkit exists so your team can spend its time building the product — not another notification platform.**
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## Star the repo ⭐
|
|
370
|
+
|
|
371
|
+
If notifkit saves you a month or two you were about to spend building this yourself, **[give it a star on GitHub](https://github.com/devkitshq/notifkit)** — it's the cheapest way to help other people find it.
|
|
87
372
|
|
|
88
373
|
## Contributing
|
|
89
374
|
|
|
90
|
-
Issues and pull requests are welcome.
|
|
375
|
+
Issues and pull requests are welcome.
|
|
376
|
+
|
|
377
|
+
```bash
|
|
378
|
+
npm install
|
|
379
|
+
npm run build
|
|
380
|
+
npm test
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
The test suite starts its own PostgreSQL and Redis containers, so Docker is the only thing you need running.
|
|
91
384
|
|
|
92
385
|
## License
|
|
93
386
|
|
package/dist/index.d.mts
CHANGED
|
@@ -443,7 +443,6 @@ declare const NotificationEnrichedPayloadSchema: z.ZodObject<{
|
|
|
443
443
|
channel: "push" | "email" | "sms" | "webhook" | "in-app";
|
|
444
444
|
priority: "low" | "normal" | "high" | "critical";
|
|
445
445
|
projectId: string;
|
|
446
|
-
rawEventId: string;
|
|
447
446
|
recipientId: string;
|
|
448
447
|
templateVariables: Record<string, unknown>;
|
|
449
448
|
recipient: {
|
|
@@ -464,6 +463,7 @@ declare const NotificationEnrichedPayloadSchema: z.ZodObject<{
|
|
|
464
463
|
pushToken?: string | undefined;
|
|
465
464
|
pushTokens?: string[] | undefined;
|
|
466
465
|
};
|
|
466
|
+
rawEventId: string;
|
|
467
467
|
aiPrompts?: Record<string, string> | undefined;
|
|
468
468
|
templateId?: string | undefined;
|
|
469
469
|
campaignId?: string | undefined;
|
|
@@ -473,7 +473,6 @@ declare const NotificationEnrichedPayloadSchema: z.ZodObject<{
|
|
|
473
473
|
channel: "push" | "email" | "sms" | "webhook" | "in-app";
|
|
474
474
|
priority: "low" | "normal" | "high" | "critical";
|
|
475
475
|
projectId: string;
|
|
476
|
-
rawEventId: string;
|
|
477
476
|
recipientId: string;
|
|
478
477
|
templateVariables: Record<string, unknown>;
|
|
479
478
|
recipient: {
|
|
@@ -494,6 +493,7 @@ declare const NotificationEnrichedPayloadSchema: z.ZodObject<{
|
|
|
494
493
|
pushTokens?: string[] | undefined;
|
|
495
494
|
locale?: string | undefined;
|
|
496
495
|
};
|
|
496
|
+
rawEventId: string;
|
|
497
497
|
aiPrompts?: Record<string, string> | undefined;
|
|
498
498
|
templateId?: string | undefined;
|
|
499
499
|
campaignId?: string | undefined;
|
|
@@ -702,9 +702,9 @@ declare const NotificationDispatchedPayloadSchema: z.ZodObject<{
|
|
|
702
702
|
priority: "low" | "normal" | "high" | "critical";
|
|
703
703
|
projectId: string;
|
|
704
704
|
taskId: string;
|
|
705
|
+
enrichedEventId: string;
|
|
705
706
|
recipientId: string;
|
|
706
707
|
templateVariables: Record<string, unknown>;
|
|
707
|
-
enrichedEventId: string;
|
|
708
708
|
renderedContent: {
|
|
709
709
|
content: Record<string, unknown>;
|
|
710
710
|
attachments?: {
|
|
@@ -747,8 +747,8 @@ declare const NotificationDispatchedPayloadSchema: z.ZodObject<{
|
|
|
747
747
|
priority: "low" | "normal" | "high" | "critical";
|
|
748
748
|
projectId: string;
|
|
749
749
|
taskId: string;
|
|
750
|
-
recipientId: string;
|
|
751
750
|
enrichedEventId: string;
|
|
751
|
+
recipientId: string;
|
|
752
752
|
renderedContent: {
|
|
753
753
|
content: Record<string, unknown>;
|
|
754
754
|
attachments?: {
|
|
@@ -993,6 +993,7 @@ declare const NotificationAiPendingPayloadSchema: z.ZodObject<{
|
|
|
993
993
|
priority: "low" | "normal" | "high" | "critical";
|
|
994
994
|
aiPrompts: Record<string, string>;
|
|
995
995
|
projectId: string;
|
|
996
|
+
enrichedEventId: string;
|
|
996
997
|
recipientId: string;
|
|
997
998
|
templateVariables: Record<string, unknown>;
|
|
998
999
|
recipient: {
|
|
@@ -1013,7 +1014,6 @@ declare const NotificationAiPendingPayloadSchema: z.ZodObject<{
|
|
|
1013
1014
|
pushToken?: string | undefined;
|
|
1014
1015
|
pushTokens?: string[] | undefined;
|
|
1015
1016
|
};
|
|
1016
|
-
enrichedEventId: string;
|
|
1017
1017
|
templateId?: string | undefined;
|
|
1018
1018
|
scheduledAt?: string | undefined;
|
|
1019
1019
|
fallbackChain?: ("push" | "email" | "sms" | "webhook" | "in-app")[] | undefined;
|
|
@@ -1022,6 +1022,7 @@ declare const NotificationAiPendingPayloadSchema: z.ZodObject<{
|
|
|
1022
1022
|
priority: "low" | "normal" | "high" | "critical";
|
|
1023
1023
|
aiPrompts: Record<string, string>;
|
|
1024
1024
|
projectId: string;
|
|
1025
|
+
enrichedEventId: string;
|
|
1025
1026
|
recipientId: string;
|
|
1026
1027
|
templateVariables: Record<string, unknown>;
|
|
1027
1028
|
recipient: {
|
|
@@ -1042,7 +1043,6 @@ declare const NotificationAiPendingPayloadSchema: z.ZodObject<{
|
|
|
1042
1043
|
pushTokens?: string[] | undefined;
|
|
1043
1044
|
locale?: string | undefined;
|
|
1044
1045
|
};
|
|
1045
|
-
enrichedEventId: string;
|
|
1046
1046
|
templateId?: string | undefined;
|
|
1047
1047
|
scheduledAt?: string | undefined;
|
|
1048
1048
|
fallbackChain?: ("push" | "email" | "sms" | "webhook" | "in-app")[] | undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "notifkit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Self-hosted notification infrastructure. One call delivers to email, SMS, push, and webhook — routed by preference, quiet hours, and consent.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "devkitshq",
|