notifkit 0.1.2 → 0.1.4

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.
Files changed (95) hide show
  1. package/README.md +130 -122
  2. package/dist/index.d.mts +196 -132
  3. package/dist/index.d.mts.map +1 -1
  4. package/dist/index.mjs +1 -1
  5. package/dist/index.mjs.map +1 -1
  6. package/dist/{main-DtHWhueo.mjs → main-40zwq6b0.mjs} +28 -3
  7. package/dist/{main-DtHWhueo.mjs.map → main-40zwq6b0.mjs.map} +1 -1
  8. package/dist/{main-DyfbnJc3.mjs → main-BFre2-HQ.mjs} +2 -2
  9. package/dist/{main-DyfbnJc3.mjs.map → main-BFre2-HQ.mjs.map} +1 -1
  10. package/dist/{main-CAH0_Q6d.mjs → main-BNJtzY61.mjs} +3 -3
  11. package/dist/main-BNJtzY61.mjs.map +1 -0
  12. package/dist/{main-B561M1d3.mjs → main-BOPMYqsW.mjs} +2 -2
  13. package/dist/{main-B561M1d3.mjs.map → main-BOPMYqsW.mjs.map} +1 -1
  14. package/dist/{main-CCfc45ev.mjs → main-CiigNpsP.mjs} +7 -4
  15. package/dist/main-CiigNpsP.mjs.map +1 -0
  16. package/dist/{main-Ce9dcrsg.mjs → main-DeNFQ-UL.mjs} +6 -3
  17. package/dist/{main-Ce9dcrsg.mjs.map → main-DeNFQ-UL.mjs.map} +1 -1
  18. package/dist/{main-B-jwm8ED.mjs → main-DmCPcxOc.mjs} +2 -2
  19. package/dist/{main-B-jwm8ED.mjs.map → main-DmCPcxOc.mjs.map} +1 -1
  20. package/dist/{main-C45e7grq.mjs → main-DvgJSm11.mjs} +2 -2
  21. package/dist/{main-C45e7grq.mjs.map → main-DvgJSm11.mjs.map} +1 -1
  22. package/dist/{src-C-PfEDMY.mjs → src-vG79L-8m.mjs} +57 -26
  23. package/dist/src-vG79L-8m.mjs.map +1 -0
  24. package/drizzle/0002_wide_colleen_wing.sql +2 -0
  25. package/drizzle/0003_skinny_daimon_hellstrom.sql +1 -0
  26. package/drizzle/0004_pretty_bruce_banner.sql +1 -0
  27. package/drizzle/meta/0002_snapshot.json +1460 -0
  28. package/drizzle/meta/0003_snapshot.json +1460 -0
  29. package/drizzle/meta/0004_snapshot.json +1470 -0
  30. package/drizzle/meta/_journal.json +21 -0
  31. package/package.json +3 -2
  32. package/src/client.ts +412 -0
  33. package/src/config/index.ts +107 -0
  34. package/src/contracts/common.ts +28 -0
  35. package/src/contracts/envelope.ts +31 -0
  36. package/src/contracts/events/notification-ai-pending.ts +18 -0
  37. package/src/contracts/events/notification-canceled.ts +7 -0
  38. package/src/contracts/events/notification-created.ts +14 -0
  39. package/src/contracts/events/notification-delivered.ts +17 -0
  40. package/src/contracts/events/notification-dispatched.ts +45 -0
  41. package/src/contracts/events/notification-enriched.ts +46 -0
  42. package/src/contracts/events/notification-failed.ts +19 -0
  43. package/src/contracts/events/notification-requested.ts +36 -0
  44. package/src/contracts/events/notification-scheduled.ts +9 -0
  45. package/src/contracts/events/notification-skipped.ts +9 -0
  46. package/src/contracts/helpers.ts +21 -0
  47. package/src/contracts/index.ts +46 -0
  48. package/src/contracts/metadata.ts +10 -0
  49. package/src/contracts/registry.ts +88 -0
  50. package/src/contracts/sdk.ts +242 -0
  51. package/src/contracts/streams.ts +62 -0
  52. package/src/db/index.ts +69 -0
  53. package/src/db/schema.ts +412 -0
  54. package/src/idempotency/index.ts +50 -0
  55. package/src/index.ts +19 -0
  56. package/src/logger/index.ts +60 -0
  57. package/src/metrics/index.ts +53 -0
  58. package/src/queue/index.ts +501 -0
  59. package/src/rate-limiter/index.ts +210 -0
  60. package/src/redis/index.ts +89 -0
  61. package/src/repositories/index.ts +1246 -0
  62. package/src/server.ts +277 -0
  63. package/src/services/ai/main.ts +404 -0
  64. package/src/services/api/handlers.ts +1734 -0
  65. package/src/services/api/http.ts +64 -0
  66. package/src/services/api/main.ts +693 -0
  67. package/src/services/api/router.ts +82 -0
  68. package/src/services/delivery/main.ts +842 -0
  69. package/src/services/delivery/throttle.ts +71 -0
  70. package/src/services/engine/main.ts +827 -0
  71. package/src/services/enricher/main.ts +594 -0
  72. package/src/services/events/main.ts +365 -0
  73. package/src/services/scheduler/main.ts +319 -0
  74. package/src/services/workflow/main.ts +627 -0
  75. package/src/shared/batch-processor.ts +67 -0
  76. package/src/shared/cache.ts +47 -0
  77. package/src/shared/circuit-breaker.ts +74 -0
  78. package/src/shared/dataloader.ts +41 -0
  79. package/src/shared/events.ts +3 -0
  80. package/src/shared/index.ts +39 -0
  81. package/src/shared/semaphore.ts +33 -0
  82. package/src/shared/utils.ts +64 -0
  83. package/src/templates/cache.ts +32 -0
  84. package/src/templates/index.ts +69 -0
  85. package/src/templates/render.ts +128 -0
  86. package/src/transport/index.ts +96 -0
  87. package/src/unsubscribe/index.ts +127 -0
  88. package/src/workers/health.ts +31 -0
  89. package/src/workers/index.ts +266 -0
  90. package/src/workflows/index.ts +2 -0
  91. package/src/workflows/registry.ts +21 -0
  92. package/src/workflows/sdk.ts +106 -0
  93. package/dist/main-CAH0_Q6d.mjs.map +0 -1
  94. package/dist/main-CCfc45ev.mjs.map +0 -1
  95. package/dist/src-C-PfEDMY.mjs.map +0 -1
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
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
8
 
9
- [![npm version](https://img.shields.io/npm/v/notifkit.svg?style=flat-square&color=6366f1)](https://www.npmjs.com/package/notifkit) [![npm downloads](https://img.shields.io/npm/dm/notifkit.svg?style=flat-square&color=6366f1)](https://www.npmjs.com/package/notifkit) [![Coverage](https://img.shields.io/badge/coverage-85%25-brightgreen.svg?style=flat-square)](https://github.com/devkitshq/notifkit) [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-3178c6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Node.js](https://img.shields.io/badge/node-%3E%3D22.0.0-339933.svg?style=flat-square)](https://nodejs.org) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](./LICENSE)
9
+ [![npm version](https://img.shields.io/npm/v/notifkit.svg?style=flat-square&color=6366f1)](https://www.npmjs.com/package/notifkit) [![npm downloads](https://img.shields.io/npm/dm/notifkit.svg?style=flat-square&color=6366f1)](https://www.npmjs.com/package/notifkit) [![Coverage](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/devkitshq/notifkit/badges/coverage.json&style=flat-square)](https://github.com/devkitshq/notifkit/actions/workflows/ci.yml) [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-3178c6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Node.js](https://img.shields.io/badge/node-%3E%3D22.0.0-339933.svg?style=flat-square)](https://nodejs.org) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](./LICENSE)
10
10
 
11
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)
12
12
 
@@ -53,50 +53,40 @@ await notifkit.notify({
53
53
 
54
54
  notifkit is both an **orchestration engine** and a **typed SDK**.
55
55
 
56
- ```text
57
- ┌──────────────────────────────────────────────────────────┐
58
- Your Application / AI Agent
59
- │ (Typed SDK / REST API / MCP Server) │
60
- └────────────────────────────┬─────────────────────────────┘
61
- │ HTTP POST /v1/notify
62
-
63
- ┌──────────────────────────────────────────────────────────┐
64
- │ Notifkit API Server │
65
- │ • Schema Validation • Auth & Multi-Tenancy │
66
- │ • Idempotency Gate • Priority Queue Ingestion │
67
- └──────────────┬────────────────────────────┬──────────────┘
68
- │ │
69
- ▼ ▼
70
- ┌─────────────────────────────┐ ┌─────────────────────────┐
71
- │ PostgreSQL (Storage) │ │ Redis (Streams & ZSET) │
72
- │ • Users & Preferences │ │ • Priority Queues │
73
- │ • Templates & Workflows │ │ • Scheduled Sends │
74
- │ • Delivery Logs & DLQ │ │ • Sliding Rate Limits │
75
- └──────────────▲──────────────┘ └──────────┬──────────────┘
76
- │ │
77
- │ ┌────────────────────────┘
78
- │ ▼
79
- ┌──────────────────────────────────────────────────────────┐
80
- │ Background Workers Pipeline │
81
- │ │
82
- │ ┌───────────┐ ┌─────────────┐ ┌────────────────┐ │
83
- │ │ Enricher │───►│ Engine │───►│ Delivery │ │
84
- │ │ (Resolve) │ │(Quiet Hours)│ │(Rate Limits/CB)│ │
85
- │ └───────────┘ └──────┬──────┘ └───────┬────────┘ │
86
- │ │ │ │
87
- │ ┌──────▼──────┐ │ │
88
- │ │ Scheduler │────────────┘ │
89
- │ │ (sendAt/QH) │ │
90
- │ └─────────────┘ │
91
- └──────────────────────────────────┬───────────────────────┘
92
- │ Dispatch
93
-
94
- ┌──────────────────────────────────────────────────────────┐
95
- │ Provider Transports │
96
- │ │
97
- │ Email: Resend, SES, Postmark Push: Firebase (FCM) │
98
- │ SMS: Twilio, MessageBird Webhooks: Custom HTTP │
99
- └──────────────────────────────────────────────────────────┘
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
100
90
  ```
101
91
 
102
92
  - **`NotifkitServer`**: Runs the HTTP REST API router (`/v1/notify`, `/health`, `/metrics`) and the background worker pipelines (enricher, decision engine, scheduler, delivery).
@@ -109,67 +99,61 @@ notifkit is both an **orchestration engine** and a **typed SDK**.
109
99
 
110
100
  ---
111
101
 
112
- ## Battle-tested for production
102
+ ## Agent-operable
113
103
 
114
- > **Battle-tested in production:** notifkit powers production notification pipelines handling **thousands of emails, push notifications, and OTPs every day.**
115
- >
116
- > 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.
104
+ https://github.com/user-attachments/assets/4dff98bb-37d3-44b4-bf46-9607c1cd89b5
117
105
 
118
- **Your servers. Your providers. Your data. Zero notification SaaS markups.**
106
+ [▶️ Watch the AI demo](assets/ai_demo.mp4) - this is link to raw video file
119
107
 
120
- ### Reliability & Chaos Engineering
108
+ **notifkit isn't just an API your application can call — your AI agent can operate it directly.**
121
109
 
122
- Because notification delivery is mission-critical, every pipeline component is tested against extreme failure conditions:
110
+ Connect the notifkit MCP server ([`@notifkit/mcp`](./packages/mcp)) to Claude Code, Cursor, Claude Desktop, Gemini, or any MCP-compatible agent:
111
+
112
+ ```bash
113
+ npx -y @notifkit/mcp
114
+ ```
115
+
116
+ ### Ask your agent
123
117
 
124
118
  ```text
125
- ┌────────────────┐ Kill Worker ┌────────────────────────┐
126
- │ Redis Streams │ ──( SIGKILL )────► │ Auto-Claim & Replay │ ──► Zero Lost Messages
127
- └────────────────┘ └────────────────────────┘
128
- ┌────────────────┐ Drop DB/Redis ┌────────────────────────┐
129
- │ Connection Loss│ ──( Disconnect )──► │ Auto-Reconnect / Retry │ ──► In-Flight State Intact
130
- └────────────────┘ └────────────────────────┘
131
- ┌────────────────┐ High Load ┌────────────────────────┐
132
- │ 10k+ Messages │ ──( Burst )───────► │ Concurrency & Limits │ ──► Flat Memory, No Leaks
133
- └────────────────┘ └────────────────────────┘
119
+ You: Why didn't usr_9182 receive their password reset?
120
+
121
+ Agent: The notification was suppressed because usr_9182's email
122
+ address has a hard-bounce suppression from yesterday.
134
123
  ```
135
124
 
136
- - **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.
137
- - **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.
138
- - **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.
139
- - **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.
140
- - **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.
125
+ Your application and your AI agents use the **same notification infrastructure**:
141
126
 
142
- ---
127
+ - **Send & dispatch** — Send one-off notifications or campaigns to users, lists, and segments (`send_notification`, `send_campaign`)
128
+ - **Investigate & triage** — Diagnose delivery issues by inspecting message histories, provider responses, and quiet hours (`get_delivery_logs`, `get_notification`)
129
+ - **Schedule & cancel** — Schedule future sends and cancel pending notifications (`list_scheduled`, `cancel_notification`)
130
+ - **Campaign analytics** — Check delivery, open, click, bounce, and complaint metrics (`list_campaigns`, `get_campaign_stats`)
131
+ - **Template management** — List, preview, and update templates with sample data (`list_templates`, `preview_template`, `upsert_template`)
132
+ - **Users & preferences** — Look up users, contacts, preferences, and segment membership (`list_users`, `get_user_preferences`, `update_user_preferences`)
133
+ - **Workflow operations** — Trigger workflows and inspect workflow runs (`create_workflow`, `trigger_workflow`, `get_workflow_run`)
134
+ - **Suppressions & health** — Manage bounce suppressions, check system queues, and replay dead-letter messages (`list_suppressions`, `get_dead_letters`, `replay_dead_letter`)
143
135
 
144
- ## What you get
136
+ ### From “write a script” to “just ask”
145
137
 
146
- | The problem you don't want to build | How notifkit solves it |
147
- | :------------------------------------------------------- | :------------------------------------------------------------------- |
148
- | **“Should this user receive it?”** | User preferences, topic opt-outs, and consent gates |
149
- | **“Is this a bad time to send?”** | Timezone-aware quiet hours that defer non-urgent sends |
150
- | **“What if push fails?”** | Automatic ordered multi-channel fallback (`push` → `email` → `sms`) |
151
- | **“What if my worker crashes?”** | Redis Streams consumer groups, retries, and durable idempotency |
152
- | **“What if an event fires twice?”** | 24-hour deduplication via idempotency keys |
153
- | **“Can I send this later?”** | Priority scheduling with `sendAt` and cancellation before dispatch |
154
- | **“Can I send this 3 days after signup?”** | Stateful multi-step workflows with `wait` and `waitForEvent` |
155
- | **“How do I know what happened?”** | Queryable delivery logs, Prometheus metrics, and campaign reporting |
156
- | **“What happens when a provider goes down?”** | Circuit breakers, exponential backoff, and DLQ replay |
157
- | **“What about bounces and spam complaints?”** | RFC 8058 one-click unsubscribe and automatic hard-bounce suppression |
158
- | **“What if I don't want another SaaS holding my data?”** | 100% self-hosted on your PostgreSQL and Redis |
138
+ | Without an agent | With NotifKit MCP |
139
+ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
140
+ | 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 |
159
141
 
160
- > **The idea is simple:** You decide what to say. **notifkit handles getting it there reliably.**
142
+ [Set up MCP](https://notifkit.dev/docs/mcp.html) · [MCP documentation](https://notifkit.dev/docs/mcp.html)
161
143
 
162
144
  ---
163
145
 
164
- ## What notifkit is — and what it isn't
146
+ ## AI-assisted migration
165
147
 
166
- **What it is:** the durable notification infrastructure layer running directly inside your own stack.
148
+ Already have notification code scattered across your application?
167
149
 
168
- **What it isn't:** a marketing automation suite.
150
+ Point your coding agent at:
169
151
 
170
- notifkit is not Customer.io, OneSignal, or SendGrid. You bring your own provider accounts — your keys, your billing, your deliverability.
152
+ ```text
153
+ https://notifkit.dev/llms-full.txt
154
+ ```
171
155
 
172
- First-party providers ship for Resend and Firebase Cloud Messaging. Anything else is a simple `Transport` class with a `send()` method.
156
+ It can understand notifkit's API and help identify ad-hoc notification code in your repository and refactor it into durable notifkit calls.
173
157
 
174
158
  ---
175
159
 
@@ -241,57 +225,69 @@ curl -X POST http://localhost:3000/v1/notify \
241
225
 
242
226
  ---
243
227
 
244
- ## Agent-operable
245
-
246
- **notifkit isn't just an API your application can call — your AI agent can operate it directly.**
228
+ ## Battle-tested for production
247
229
 
248
- Connect the notifkit MCP server ([`@notifkit/mcp`](./packages/mcp)) to Claude Code, Cursor, Claude Desktop, Gemini, or any MCP-compatible agent:
230
+ > **Battle-tested in production:** notifkit powers production notification pipelines handling **thousands of emails, push notifications, and OTPs every day.**
231
+ >
232
+ > 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.
249
233
 
250
- ```bash
251
- npx -y @notifkit/mcp
252
- ```
234
+ **Your servers. Your providers. Your data. Zero notification SaaS markups.**
253
235
 
254
- ### Ask your agent
236
+ ### Reliability & Chaos Engineering
255
237
 
256
- ```text
257
- You: Why didn't usr_9182 receive their password reset?
238
+ Because notification delivery is mission-critical, every pipeline component is tested against extreme failure conditions:
258
239
 
259
- Agent: The notification was suppressed because usr_9182's email
260
- address has a hard-bounce suppression from yesterday.
240
+ ```mermaid
241
+ flowchart LR
242
+ S1["Redis Streams"] -->|"Kill Worker (SIGKILL)"| M1["Auto-Claim and Replay"] --> O1["Zero Lost Messages"]
243
+ S2["Connection Loss"] -->|"Drop DB / Redis"| M2["Auto-Reconnect / Retry"] --> O2["In-Flight State Intact"]
244
+ S3["10k+ Messages"] -->|"Burst"| M3["Concurrency and Limits"] --> O3["Flat Memory, No Leaks"]
245
+
246
+ classDef fault stroke:#ef4444,stroke-width:2px
247
+ classDef guard stroke:#6366f1,stroke-width:2px
248
+ classDef result stroke:#22c55e,stroke-width:2px
249
+ class S1,S2,S3 fault
250
+ class M1,M2,M3 guard
251
+ class O1,O2,O3 result
261
252
  ```
262
253
 
263
- Your application and your AI agents use the **same notification infrastructure**:
254
+ - **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.
255
+ - **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.
256
+ - **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.
257
+ - **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.
258
+ - **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.
264
259
 
265
- - **Send & dispatch** — Send one-off notifications or campaigns to users, lists, and segments (`send_notification`, `send_campaign`)
266
- - **Investigate & triage** — Diagnose delivery issues by inspecting message histories, provider responses, and quiet hours (`get_delivery_logs`, `get_notification`)
267
- - **Schedule & cancel** — Schedule future sends and cancel pending notifications (`list_scheduled`, `cancel_notification`)
268
- - **Campaign analytics** — Check delivery, open, click, bounce, and complaint metrics (`list_campaigns`, `get_campaign_stats`)
269
- - **Template management** — List, preview, and update templates with sample data (`list_templates`, `preview_template`, `upsert_template`)
270
- - **Users & preferences** — Look up users, contacts, preferences, and segment membership (`list_users`, `get_user_preferences`, `update_user_preferences`)
271
- - **Workflow operations** — Trigger workflows and inspect workflow runs (`create_workflow`, `trigger_workflow`, `get_workflow_run`)
272
- - **Suppressions & health** — Manage bounce suppressions, check system queues, and replay dead-letter messages (`list_suppressions`, `get_dead_letters`, `replay_dead_letter`)
260
+ ---
273
261
 
274
- ### From “write a script” to “just ask”
262
+ ## What you get
275
263
 
276
- | Without an agent | With NotifKit MCP |
277
- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
278
- | 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 |
264
+ | The problem you don't want to build | How notifkit solves it |
265
+ | :------------------------------------------------------- | :------------------------------------------------------------------- |
266
+ | **“Should this user receive it?”** | User preferences, topic opt-outs, and consent gates |
267
+ | **“Is this a bad time to send?”** | Timezone-aware quiet hours that defer non-urgent sends |
268
+ | **“What if push fails?”** | Automatic ordered multi-channel fallback (`push` → `email` → `sms`) |
269
+ | **“What if my worker crashes?”** | Redis Streams consumer groups, retries, and durable idempotency |
270
+ | **“What if an event fires twice?”** | 24-hour deduplication via idempotency keys |
271
+ | **“Can I send this later?”** | Priority scheduling with `sendAt` and cancellation before dispatch |
272
+ | **“Can I send this 3 days after signup?”** | Stateful multi-step workflows with `wait` and `waitForEvent` |
273
+ | **“How do I know what happened?”** | Queryable delivery logs, Prometheus metrics, and campaign reporting |
274
+ | **“What happens when a provider goes down?”** | Circuit breakers, exponential backoff, and DLQ replay |
275
+ | **“What about bounces and spam complaints?”** | RFC 8058 one-click unsubscribe and automatic hard-bounce suppression |
276
+ | **“What if I don't want another SaaS holding my data?”** | 100% self-hosted on your PostgreSQL and Redis |
279
277
 
280
- [Set up MCP](https://notifkit.dev/docs/mcp.html) · [MCP documentation](https://notifkit.dev/docs/mcp.html)
278
+ > **The idea is simple:** You decide what to say. **notifkit handles getting it there reliably.**
281
279
 
282
280
  ---
283
281
 
284
- ## AI-assisted migration
282
+ ## What notifkit is — and what it isn't
285
283
 
286
- Already have notification code scattered across your application?
284
+ **What it is:** the durable notification infrastructure layer running directly inside your own stack.
287
285
 
288
- Point your coding agent at:
286
+ **What it isn't:** a marketing automation suite.
289
287
 
290
- ```text
291
- https://notifkit.dev/llms-full.txt
292
- ```
288
+ notifkit is not Customer.io, OneSignal, or SendGrid. You bring your own provider accounts — your keys, your billing, your deliverability.
293
289
 
294
- It can understand notifkit's API and help identify ad-hoc notification code in your repository and refactor it into durable notifkit calls.
290
+ First-party providers ship for Resend and Firebase Cloud Messaging. Anything else is a simple `Transport` class with a `send()` method.
295
291
 
296
292
  ---
297
293
 
@@ -299,7 +295,7 @@ It can understand notifkit's API and help identify ad-hoc notification code in y
299
295
 
300
296
  | | |
301
297
  | :------------------ | :------------------------------------------------------------------------------------- |
302
- | **Channels** | `email`, `sms`, `push`, `webhook` |
298
+ | **Channels** | `email`, `sms`, `push`, `webhook`, `telegram`, `discord`, `whatsapp`, `slack` |
303
299
  | **Targeting** | A user, a list of users, a segment, or a topic |
304
300
  | **Priorities** | `low`, `normal`, `high`, `critical` — separate stream lanes |
305
301
  | **Scheduling** | Future sends with `sendAt`, quiet-hours deferral, cancellation |
@@ -324,13 +320,18 @@ First-party packages:
324
320
 
325
321
  - [`@notifkit/provider-resend`](./packages/provider-resend) — transactional email via Resend
326
322
  - [`@notifkit/provider-fcm`](./packages/provider-fcm) — push notifications via Firebase Cloud Messaging
323
+ - [`@notifkit/provider-slack`](./packages/provider-slack) — Slack messages via Incoming Webhooks or the Web API
324
+ - [`@notifkit/provider-twilio`](./packages/provider-twilio) — SMS via Twilio, with signature-verified delivery status callbacks
325
+ - [`@notifkit/provider-telegram`](./packages/provider-telegram) — messages via a Telegram bot
326
+ - [`@notifkit/provider-discord`](./packages/provider-discord) — messages via a Discord webhook
327
+ - [`@notifkit/provider-whatsapp`](./packages/provider-whatsapp) — messages via Meta's WhatsApp Cloud API
327
328
 
328
329
  For anything else, implement a simple `Transport`:
329
330
 
330
331
  ```ts
331
332
  class MyTransport implements Transport {
332
333
  async send(message) {
333
- // Send through Twilio, SES, Postmark, APNs,
334
+ // Send through SES, Postmark, APNs,
334
335
  // SendGrid, a custom webhook, or anything else.
335
336
  }
336
337
  }
@@ -390,6 +391,13 @@ npm test
390
391
 
391
392
  The test suite starts its own PostgreSQL and Redis containers, so Docker is the only thing you need running.
392
393
 
394
+ ## Contact
395
+
396
+ Questions, bugs, or ideas — mail me. I run this on my own company, which delivers a lot of notifications daily (100K+/day).
397
+
398
+ - **Email:** [contact.devkitshq@gmail.com](mailto:contact.devkitshq@gmail.com)
399
+ - **Book a 30-min call:** [calendly.com/contact-devkitshq/30min](https://calendly.com/contact-devkitshq/30min)
400
+
393
401
  ## License
394
402
 
395
403
  MIT. Do what you like with it, including commercially. See [LICENSE](./LICENSE).