@notifykit/sdk 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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 NotifyKit
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,622 @@
1
+ # NotifyKit SDK
2
+
3
+ Official Node.js/TypeScript SDK for NotifyKit - Send emails and webhooks with ease.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @notifykit/sdk
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { NotifyKitClient } from "@notifykit/sdk";
15
+
16
+ const notifyKit = new NotifyKitClient({
17
+ apiKey: "ntfy_sk_your_api_key",
18
+ });
19
+
20
+ // Send an email
21
+ await notifyKit.sendEmail({
22
+ to: "user@example.com",
23
+ subject: "Welcome!",
24
+ body: "<h1>Hello World</h1>",
25
+ });
26
+ ```
27
+
28
+ ---
29
+
30
+ ## Sending Emails
31
+
32
+ **Important:** Emails are queued immediately (HTTP 202 Accepted) and delivered asynchronously. Check job status to confirm delivery.
33
+
34
+ ### Basic Email
35
+
36
+ ```typescript
37
+ await notifyKit.sendEmail({
38
+ to: "user@example.com",
39
+ subject: "Order Confirmed",
40
+ body: "<h1>Thanks for your order!</h1>",
41
+ });
42
+ ```
43
+
44
+ ### Custom From Address
45
+
46
+ ```typescript
47
+ await notifyKit.sendEmail({
48
+ to: "user@example.com",
49
+ subject: "Welcome",
50
+ body: "<h1>Hello</h1>",
51
+ from: "hello@yourapp.com", // Must be a verified domain
52
+ });
53
+ ```
54
+
55
+ ### Prevent Duplicate Sends (Recommended)
56
+
57
+ ```typescript
58
+ await notifyKit.sendEmail({
59
+ to: "user@example.com",
60
+ subject: "Welcome",
61
+ body: "<h1>Hello</h1>",
62
+ idempotencyKey: "user-123-welcome", // Prevents duplicate sends on retry
63
+ });
64
+ ```
65
+
66
+ **How idempotency works:**
67
+
68
+ - Same key → Request rejected with 409 Conflict, original job returned
69
+ - Different key → New email sent
70
+ - No key → Always sends (not recommended for production)
71
+
72
+ ---
73
+
74
+ ## Sending Webhooks
75
+
76
+ **Important:** Like emails, webhooks are queued immediately (HTTP 202 Accepted) and delivered asynchronously. Check job status to confirm delivery.
77
+
78
+ ### Basic Webhook
79
+
80
+ ```typescript
81
+ await notifyKit.sendWebhook({
82
+ url: "https://yourapp.com/webhooks/order",
83
+ payload: {
84
+ orderId: "12345",
85
+ status: "completed",
86
+ },
87
+ });
88
+ ```
89
+
90
+ ### With Custom Headers and Method
91
+
92
+ ```typescript
93
+ await notifyKit.sendWebhook({
94
+ url: "https://yourapp.com/webhooks/order",
95
+ method: "POST", // GET, POST, PUT, PATCH, DELETE(default is POST)
96
+ payload: { orderId: "12345" },
97
+ headers: {
98
+ "X-Event-Type": "order.created",
99
+ "X-Signature": "abc123",
100
+ },
101
+ idempotencyKey: "order-12345-webhook",
102
+ });
103
+ ```
104
+
105
+ ---
106
+
107
+ ## Tracking Jobs
108
+
109
+ All notifications return a job object with a job Id that can be tracked.
110
+
111
+ ### Check Job Status
112
+
113
+ **Important:** `sendEmail()` returns immediately after queuing the job (HTTP 202 Accepted). The actual email is sent asynchronously by a background worker. Always check the job status to confirm delivery.
114
+
115
+ ```typescript
116
+ const job = await notifyKit.sendEmail({
117
+ to: "user@example.com",
118
+ subject: "Test",
119
+ body: "<h1>Test</h1>",
120
+ });
121
+
122
+ console.log(`Job ID: ${job.jobId}`); // Save this for later tracking
123
+
124
+ // Check status later
125
+ const status = await notifyKit.getJob(job.jobId);
126
+
127
+ console.log(status.status); // 'pending' | 'processing' | 'completed' | 'failed'
128
+
129
+ if (status.status === "completed") {
130
+ console.log("Email sent successfully!");
131
+ } else if (status.status === "failed") {
132
+ console.error(" Failed:", status.errorMessage);
133
+ }
134
+ ```
135
+
136
+ ### List Jobs with Filters
137
+
138
+ ```typescript
139
+ const result = await notifyKit.listJobs({
140
+ page: 1,
141
+ limit: 20,
142
+ type: "email", // Filter by type: 'email' or 'webhook'
143
+ status: "failed", // Filter by status: 'pending', 'processing', 'completed', 'failed'
144
+ });
145
+
146
+ console.log(`Total: ${result.pagination.total} jobs`);
147
+ console.log(`Pages: ${result.pagination.totalPages}`);
148
+
149
+ result.data.forEach((job) => {
150
+ console.log(`${job.id}: ${job.status} (${job.attempts} attempts)`);
151
+ });
152
+ ```
153
+
154
+ ### Retry Failed Jobs
155
+
156
+ ```typescript
157
+ const job = await notifyKit.sendEmail({...});
158
+
159
+ // Later, if job failed
160
+ const status = await notifyKit.getJob(job.jobId);
161
+
162
+ if (status.status === "failed") {
163
+ // Retry the job
164
+ await notifyKit.retryJob(job.jobId);
165
+ console.log("Job queued for retry");
166
+ }
167
+ ```
168
+
169
+ **Note:** Only jobs with status `failed` can be retried.
170
+
171
+ ---
172
+
173
+ ## Domain Management
174
+
175
+ Use your own verified domain to send emails (e.g., `welcome@yourapp.com` instead of `noreply@notifykit.dev`).
176
+
177
+ ### Step 1: Request Domain Verification
178
+
179
+ ```typescript
180
+ const verification = await notifyKit.requestDomainVerification("yourapp.com");
181
+
182
+ console.log(`Domain: ${verification.domain}`);
183
+ console.log(`Status: ${verification.status}`); // 'pending' or 'verified'
184
+ ```
185
+
186
+ **Response:**
187
+
188
+ ```json
189
+ {
190
+ "domain": "yourapp.com",
191
+ "status": "pending",
192
+ "dnsRecords": [
193
+ {
194
+ "id": 1,
195
+ "type": "CNAME",
196
+ "host": "em8724.yourapp.com",
197
+ "value": "u12345678.wl123.sendgrid.net",
198
+ "description": "Mail CNAME - Routes email through SendGrid"
199
+ },
200
+ {
201
+ "id": 2,
202
+ "type": "CNAME",
203
+ "host": "s1._domainkey.yourapp.com",
204
+ "value": "s1.domainkey.u12345678.wl123.sendgrid.net",
205
+ "description": "DKIM 1 - Email authentication (prevents spoofing)"
206
+ },
207
+ {
208
+ "id": 3,
209
+ "type": "CNAME",
210
+ "host": "s2._domainkey.yourapp.com",
211
+ "value": "s2.domainkey.u12345678.wl123.sendgrid.net",
212
+ "description": "DKIM 2 - Email authentication (backup)"
213
+ }
214
+ ],
215
+ "instructions": {
216
+ "message": "Add these DNS records to your domain registrar",
217
+ "steps": [
218
+ "1. Login to your domain registrar (Namecheap, GoDaddy, Cloudflare, etc.)",
219
+ "2. Navigate to DNS settings for your domain",
220
+ "3. Add each CNAME record below",
221
+ "4. Wait 15-60 minutes for DNS propagation",
222
+ "5. Click 'Verify Domain' to check status"
223
+ ],
224
+ "estimatedTime": "15-60 minutes"
225
+ }
226
+ }
227
+ ```
228
+
229
+ ### Understanding DNS Records
230
+
231
+ **Record 1: Mail CNAME** (`em8724.yourapp.com`)
232
+
233
+ - Routes emails through SendGrid's infrastructure
234
+ - Allows sending from `welcome@em.yourapp.com`
235
+
236
+ **Record 2 & 3: DKIM Records** (`s1._domainkey` and `s2._domainkey`)
237
+
238
+ - Digital signatures that prove emails are from you
239
+ - Prevents spoofing and improves deliverability
240
+ - Two records provide redundancy during key rotation
241
+
242
+ ### Step 2: Add DNS Records to Your Domain
243
+
244
+ Go to your domain registrar and add the 3 CNAME records:
245
+
246
+ **Example for Cloudflare:**
247
+
248
+ ```
249
+ Type: CNAME
250
+ Name: em8724
251
+ Content: u12345678.wl123.sendgrid.net
252
+ Proxy status: DNS only (disable proxy)
253
+ ```
254
+
255
+ **Example for Namecheap:**
256
+
257
+ ```
258
+ Type: CNAME Record
259
+ Host: em8724
260
+ Value: u12345678.wl123.sendgrid.net
261
+ TTL: Automatic
262
+ ```
263
+
264
+ **DNS propagation takes 15-60 minutes** (sometimes up to 24 hours).
265
+
266
+ ### Step 3: Verify Domain
267
+
268
+ After adding DNS records and waiting for propagation:
269
+
270
+ ```typescript
271
+ const status = await notifyKit.verifyDomain();
272
+
273
+ if (status.verified) {
274
+ console.log("Domain verified!");
275
+ console.log("You can now send from: welcome@em.yourapp.com");
276
+ } else {
277
+ console.log("DNS still propagating...");
278
+ console.log(status.message);
279
+
280
+ // Check validation results for issues
281
+ if (status.validationResults) {
282
+ console.log("Validation details:", status.validationResults);
283
+ }
284
+ }
285
+ ```
286
+
287
+ **Response:**
288
+
289
+ ```json
290
+ {
291
+ "domain": "yourapp.com",
292
+ "verified": true,
293
+ "message": "Domain verified! You can now send emails from this domain."
294
+ }
295
+ ```
296
+
297
+ ### Step 4: Send Emails from Your Domain
298
+
299
+ Once verified, emails automatically use `noreply@em.yourapp.com` if you don't specify a `from` address:
300
+
301
+ ```typescript
302
+ // Automatically uses: noreply@em.yourapp.com
303
+ await notifyKit.sendEmail({
304
+ to: "user@example.com",
305
+ subject: "Welcome!",
306
+ body: "Welcome to MyApp!",
307
+ // No 'from' specified → Uses noreply@em.yourapp.com
308
+ });
309
+
310
+ // Or specify a custom sender address on your domain
311
+ await notifyKit.sendEmail({
312
+ to: "user@example.com",
313
+ subject: "Support Response",
314
+ body: "We're here to help",
315
+ from: "support@em.yourapp.com", // Custom sender
316
+ });
317
+
318
+ // You can also use different names with the same domain
319
+ await notifyKit.sendEmail({
320
+ to: "user@example.com",
321
+ subject: "Order Shipped",
322
+ body: "Your order is on the way!",
323
+ from: "orders@em.yourapp.com", // Different sender
324
+ });
325
+ ```
326
+
327
+ **Important: The `em.` Subdomain**
328
+
329
+ Emails are sent from `em.yourapp.com` (subdomain), **not** `yourapp.com` (main domain).
330
+
331
+ **Examples:**
332
+
333
+ - Correct: `welcome@em.yourapp.com`
334
+ - Correct: `support@em.yourapp.com`
335
+ - Wrong: `welcome@yourapp.com` (will be rejected)
336
+
337
+ **Why the subdomain?**
338
+
339
+ Using a dedicated subdomain (`em.`) for transactional emails protects your main domain's reputation:
340
+
341
+ 1. **Isolation**: If a transactional email is marked as spam, it doesn't hurt your main domain
342
+ 2. **Separate reputation**: Your business emails (`team@yourapp.com`) remain trusted
343
+
344
+ **What recipients see:**
345
+
346
+ ```
347
+ From: support@em.yourapp.com
348
+ ```
349
+
350
+ Most email clients only show `yourapp.com` in the sender name, so users typically see it as coming from your domain.
351
+
352
+ **If you try to use the main domain:**
353
+
354
+ ```typescript
355
+ await notifyKit.sendEmail({
356
+ from: "hello@yourapp.com", // Missing "em."
357
+ });
358
+
359
+ // Error: "Cannot send from hello@yourapp.com. Use em.yourapp.com instead
360
+ // (e.g., hello@em.yourapp.com)"
361
+ ```
362
+
363
+ ### Check Domain Status Anytime
364
+
365
+ ```typescript
366
+ const info = await notifyKit.getDomainStatus();
367
+
368
+ console.log(`Domain: ${info.domain}`); // 'yourapp.com' or null
369
+ console.log(`Verified: ${info.verified}`); // true or false
370
+ console.log(`Status: ${info.status}`); // 'not_configured', 'pending', 'verified'
371
+
372
+ if (info.verified) {
373
+ console.log(`Verified at: ${info.verifiedAt}`);
374
+ }
375
+ ```
376
+
377
+ **Response:**
378
+
379
+ ```json
380
+ {
381
+ "domain": "yourapp.com",
382
+ "verified": true,
383
+ "status": "verified",
384
+ "dnsRecords": [...],
385
+ "requestedAt": "2026-01-04T10:00:00.000Z",
386
+ "verifiedAt": "2026-01-04T10:45:00.000Z"
387
+ }
388
+ ```
389
+
390
+ ### Remove Domain Configuration
391
+
392
+ ```typescript
393
+ await notifyKit.removeDomain();
394
+ console.log(
395
+ "Domain removed. Emails will now send from NotifyKit's default domain."
396
+ );
397
+ ```
398
+
399
+ **Note:** You can only have **one verified domain at a time**. Requesting a new domain automatically replaces the old one.
400
+
401
+ ---
402
+
403
+ ## Troubleshooting Domain Verification
404
+
405
+ ### DNS Not Verifying After 1 Hour
406
+
407
+ **Check DNS propagation:**
408
+
409
+ ```bash
410
+ # Check if CNAME exists
411
+ dig em8724.yourapp.com CNAME
412
+
413
+ # Should return: u12345678.wl123.sendgrid.net
414
+ ```
415
+
416
+ **Common issues:**
417
+
418
+ 1. **Wrong host name** - Some registrars need full hostname (`em8724.yourapp.com`), others just the subdomain (`em8724`)
419
+ 2. **Proxy enabled** (Cloudflare) - Disable proxy, use "DNS only"
420
+ 3. **TTL too high** - Lower TTL to 300 seconds (5 minutes) for faster propagation
421
+ 4. **Old records** - Delete any existing records for the same hostname first
422
+
423
+ ### Emails Still Sending from NotifyKit Domain
424
+
425
+ **Possible causes:**
426
+
427
+ 1. Domain not verified yet - Check status: `await notifyKit.getDomainStatus()`
428
+ 2. Free plan - Custom domains only available on paid plans (Indie, Startup)
429
+ 3. Verification failed - DNS records may have been removed
430
+
431
+ ### Verification Says "Domain Already Verified by Another Customer"
432
+
433
+ Each domain can only be verified by one NotifyKit account. If you own this domain:
434
+
435
+ 1. Remove it from the other account first
436
+ 2. Then verify it on your current account
437
+
438
+ ---
439
+
440
+ ## Best Practices
441
+
442
+ ### Use Subdomain for Transactional Emails
443
+
444
+ **Good:** `noreply@em.yourapp.com` (dedicated subdomain)
445
+ **Bad:** `noreply@yourapp.com` (main domain)
446
+
447
+ **Why?** If transactional emails are marked as spam, it doesn't hurt your main domain's reputation for important business emails.
448
+
449
+ ### Set Up DMARC (Optional but Recommended)
450
+
451
+ Add a TXT record to improve email deliverability:
452
+
453
+ ```
454
+ Type: TXT
455
+ Name: _dmarc
456
+ Value: v=DMARC1; p=none; rua=mailto:dmarc-reports@yourapp.com
457
+ ```
458
+
459
+ This enables email authentication reporting and protects against spoofing.
460
+
461
+ ### Monitor Your Domain Reputation
462
+
463
+ - Check SendGrid Activity Feed regularly
464
+ - Watch for high bounce rates (>5% is concerning)
465
+ - Remove invalid email addresses from your lists
466
+ - Never send unsolicited emails (spam)
467
+
468
+ ---
469
+
470
+ ## Real-World Examples
471
+
472
+ ### User Signup Flow
473
+
474
+ ```typescript
475
+ import { NotifyKitClient } from "@notifykit/sdk";
476
+
477
+ const notifyKit = new NotifyKitClient({
478
+ apiKey: process.env.NOTIFYKIT_API_KEY,
479
+ });
480
+
481
+ async function handleUserSignup(user) {
482
+ await notifyKit.sendEmail({
483
+ to: user.email,
484
+ subject: "Welcome to MyApp!",
485
+ body: `
486
+ <h1>Hi ${user.name}!</h1>
487
+ <p>Thanks for signing up. Get started by exploring our features.</p>
488
+ <a href="https://myapp.com/get-started">Get Started</a>
489
+ `,
490
+ idempotencyKey: `user-${user.id}-welcome`,
491
+ });
492
+ }
493
+ ```
494
+
495
+ ### Order Confirmation with Multiple Notifications
496
+
497
+ ```typescript
498
+ async function handleOrderPlaced(order) {
499
+ // Send email to customer
500
+ await notifyKit.sendEmail({
501
+ to: order.customerEmail,
502
+ subject: `Order #${order.id} Confirmed`,
503
+ body: generateOrderConfirmationEmail(order),
504
+ idempotencyKey: `order-${order.id}-customer-email`,
505
+ });
506
+
507
+ // Notify warehouse system via webhook
508
+ await notifyKit.sendWebhook({
509
+ url: "https://warehouse-system.com/api/new-order",
510
+ method: "POST",
511
+ payload: {
512
+ orderId: order.id,
513
+ items: order.items,
514
+ shippingAddress: order.shippingAddress,
515
+ priority: order.priority,
516
+ },
517
+ headers: {
518
+ "X-Warehouse-Token": process.env.WAREHOUSE_API_TOKEN,
519
+ },
520
+ idempotencyKey: `order-${order.id}-warehouse-webhook`,
521
+ });
522
+
523
+ // Send to analytics
524
+ await notifyKit.sendWebhook({
525
+ url: "https://analytics.myapp.com/track",
526
+ payload: {
527
+ event: "order.placed",
528
+ orderId: order.id,
529
+ revenue: order.total,
530
+ customerId: order.customerId,
531
+ },
532
+ idempotencyKey: `order-${order.id}-analytics`,
533
+ });
534
+ }
535
+ ```
536
+
537
+ ### Background Job Status Monitoring
538
+
539
+ ```typescript
540
+ async function sendEmailWithMonitoring(
541
+ to: string,
542
+ subject: string,
543
+ body: string
544
+ ) {
545
+ const job = await notifyKit.sendEmail({ to, subject, body });
546
+
547
+ // Check status after 5 seconds
548
+ setTimeout(async () => {
549
+ const status = await notifyKit.getJob(job.jobId);
550
+
551
+ if (status.status === "failed") {
552
+ console.error(`Email delivery failed: ${status.errorMessage}`);
553
+ await alertAdmin(`Email to ${to} failed`);
554
+ }
555
+ }, 5000);
556
+
557
+ return job;
558
+ }
559
+ ```
560
+
561
+ ---
562
+
563
+ ## Configuration
564
+
565
+ ### Custom Base URL (Self-Hosted or Staging)
566
+
567
+ ```typescript
568
+ const notifyKit = new NotifyKitClient({
569
+ apiKey: "ntfy_sk_...",
570
+ baseUrl: "https://staging-api.notifykit.dev", // Default: https://api.notifykit.dev
571
+ });
572
+ ```
573
+
574
+ ---
575
+
576
+ ## API Reference
577
+
578
+ | Method | Description | Returns |
579
+ | ----------------------------------- | -------------------------------- | ---------------------------- |
580
+ | `sendEmail(options)` | Send an email notification | `JobResponse` |
581
+ | `sendWebhook(options)` | Send a webhook notification | `JobResponse` |
582
+ | `getJob(jobId)` | Get job status by ID | `JobStatus` |
583
+ | `listJobs(options?)` | List jobs with optional filters | `{ data, pagination }` |
584
+ | `retryJob(jobId)` | Retry a failed job | `JobResponse` |
585
+ | `requestDomainVerification(domain)` | Request domain verification | `DomainVerificationResponse` |
586
+ | `verifyDomain()` | Check domain DNS verification | `DomainStatusResponse` |
587
+ | `getDomainStatus()` | Get current domain configuration | `DomainInfoResponse` |
588
+ | `removeDomain()` | Remove domain configuration | `{ message: string }` |
589
+
590
+ ### TypeScript Types
591
+
592
+ All methods are fully typed. Import types for use in your code:
593
+
594
+ ```typescript
595
+ import {
596
+ NotifyKitClient,
597
+ SendEmailOptions,
598
+ SendWebhookOptions,
599
+ JobResponse,
600
+ JobStatus,
601
+ NotifyKitError,
602
+ } from "@notifykit/sdk";
603
+ ```
604
+
605
+ ---
606
+
607
+ ## Requirements
608
+
609
+ - Node.js 16+ or browser with fetch support
610
+ - TypeScript 4.5+ (optional, for type checking)
611
+
612
+ ---
613
+
614
+ ## Support
615
+
616
+ - 🐛 Issues: [GitHub Issues](https://github.com/brayzonn/notifykit-sdk/issues)
617
+
618
+ ---
619
+
620
+ ## License
621
+
622
+ MIT © NotifyKit
@@ -0,0 +1,27 @@
1
+ import { NotifyKitConfig, SendEmailOptions, SendWebhookOptions, JobResponse, JobStatus, ApiInfo, PaginationMeta } from "./types";
2
+ export declare class NotifyKitClient {
3
+ private client;
4
+ constructor(config: NotifyKitConfig);
5
+ /** Test API connection */
6
+ ping(): Promise<string>;
7
+ /** Get API information */
8
+ getApiInfo(): Promise<ApiInfo>;
9
+ /** Send an email notification */
10
+ sendEmail(options: SendEmailOptions): Promise<JobResponse>;
11
+ /** Send a webhook notification */
12
+ sendWebhook(options: SendWebhookOptions): Promise<JobResponse>;
13
+ /** Get job status by ID */
14
+ getJob(jobId: string): Promise<JobStatus>;
15
+ /** List jobs with optional filters */
16
+ listJobs(options?: {
17
+ page?: number;
18
+ limit?: number;
19
+ type?: "email" | "webhook";
20
+ status?: "pending" | "processing" | "completed" | "failed";
21
+ }): Promise<{
22
+ data: JobStatus[];
23
+ pagination: PaginationMeta;
24
+ }>;
25
+ /** Retry a failed job */
26
+ retryJob(jobId: string): Promise<JobResponse>;
27
+ }
package/dist/client.js ADDED
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.NotifyKitClient = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const errors_1 = require("./errors");
9
+ class NotifyKitClient {
10
+ constructor(config) {
11
+ if (!config.apiKey) {
12
+ throw new Error("API key is required");
13
+ }
14
+ this.client = axios_1.default.create({
15
+ baseURL: config.baseUrl || "https://api.notifykit.dev",
16
+ headers: {
17
+ "X-API-Key": config.apiKey,
18
+ "Content-Type": "application/json",
19
+ },
20
+ });
21
+ this.client.interceptors.response.use((response) => {
22
+ const apiResponse = response.data?.data;
23
+ if (!apiResponse)
24
+ return response.data;
25
+ if (apiResponse.message)
26
+ return apiResponse.message;
27
+ return apiResponse;
28
+ }, (error) => {
29
+ if (error.response) {
30
+ const data = error.response.data;
31
+ const statusCode = error.response.status;
32
+ let message = error.message;
33
+ let errors = null;
34
+ if (data?.error) {
35
+ if (Array.isArray(data.error)) {
36
+ errors = data.error;
37
+ message = data.error.join(", ");
38
+ }
39
+ else {
40
+ message = data.error;
41
+ }
42
+ }
43
+ else if (data?.message) {
44
+ if (Array.isArray(data.message)) {
45
+ errors = data.message;
46
+ message = "Validation failed";
47
+ }
48
+ else {
49
+ message = data.message;
50
+ }
51
+ }
52
+ throw new errors_1.NotifyKitError(message, statusCode, data, errors);
53
+ }
54
+ throw new errors_1.NotifyKitError(error.message || "Network error occurred");
55
+ });
56
+ }
57
+ // ================================
58
+ // APP
59
+ // ================================
60
+ /** Test API connection */
61
+ async ping() {
62
+ return await this.client.get("/api/v1/ping");
63
+ }
64
+ /** Get API information */
65
+ async getApiInfo() {
66
+ return await this.client.get("/api/v1/info");
67
+ }
68
+ // ================================
69
+ // NOTIFICATIONS
70
+ // ================================
71
+ /** Send an email notification */
72
+ async sendEmail(options) {
73
+ return await this.client.post("/api/v1/notifications/email", options);
74
+ }
75
+ /** Send a webhook notification */
76
+ async sendWebhook(options) {
77
+ return await this.client.post("/api/v1/notifications/webhook", options);
78
+ }
79
+ /** Get job status by ID */
80
+ async getJob(jobId) {
81
+ return await this.client.get(`/api/v1/notifications/jobs/${jobId}`);
82
+ }
83
+ /** List jobs with optional filters */
84
+ async listJobs(options) {
85
+ return await this.client.get("/api/v1/notifications/jobs", {
86
+ params: options,
87
+ });
88
+ }
89
+ /** Retry a failed job */
90
+ async retryJob(jobId) {
91
+ return await this.client.post(`/api/v1/notifications/jobs/${jobId}/retry`);
92
+ }
93
+ }
94
+ exports.NotifyKitClient = NotifyKitClient;
@@ -0,0 +1,14 @@
1
+ export declare class NotifyKitError extends Error {
2
+ statusCode?: number | undefined;
3
+ response?: any | undefined;
4
+ errors?: any[] | undefined;
5
+ constructor(message: string, statusCode?: number | undefined, response?: any | undefined, errors?: any[] | undefined);
6
+ /**
7
+ * Get formatted error message with details
8
+ */
9
+ getFullMessage(): string;
10
+ /**
11
+ * Check if error is a specific HTTP status
12
+ */
13
+ isStatus(code: number): boolean;
14
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NotifyKitError = void 0;
4
+ class NotifyKitError extends Error {
5
+ constructor(message, statusCode, response, errors) {
6
+ super(message);
7
+ this.statusCode = statusCode;
8
+ this.response = response;
9
+ this.errors = errors;
10
+ this.name = "NotifyKitError";
11
+ Error.captureStackTrace(this, this.constructor);
12
+ }
13
+ /**
14
+ * Get formatted error message with details
15
+ */
16
+ getFullMessage() {
17
+ let msg = this.message;
18
+ if (this.statusCode) {
19
+ msg = `[${this.statusCode}] ${msg}`;
20
+ }
21
+ if (this.errors && this.errors.length > 0) {
22
+ msg +=
23
+ "\nValidation errors:\n" +
24
+ this.errors.map((e) => ` - ${e}`).join("\n");
25
+ }
26
+ return msg;
27
+ }
28
+ /**
29
+ * Check if error is a specific HTTP status
30
+ */
31
+ isStatus(code) {
32
+ return this.statusCode === code;
33
+ }
34
+ }
35
+ exports.NotifyKitError = NotifyKitError;
@@ -0,0 +1,3 @@
1
+ export { NotifyKitClient } from "./client";
2
+ export * from "./types";
3
+ export * from "./errors";
package/dist/index.js ADDED
@@ -0,0 +1,21 @@
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.NotifyKitClient = void 0;
18
+ var client_1 = require("./client");
19
+ Object.defineProperty(exports, "NotifyKitClient", { enumerable: true, get: function () { return client_1.NotifyKitClient; } });
20
+ __exportStar(require("./types"), exports);
21
+ __exportStar(require("./errors"), exports);
@@ -0,0 +1,45 @@
1
+ export interface NotifyKitConfig {
2
+ apiKey: string;
3
+ baseUrl?: string;
4
+ }
5
+ export interface PaginationMeta {
6
+ total: number;
7
+ page: number;
8
+ limit: number;
9
+ totalPages: number;
10
+ }
11
+ export interface SendEmailOptions {
12
+ to: string;
13
+ subject: string;
14
+ body: string;
15
+ from?: string;
16
+ idempotencyKey?: string;
17
+ }
18
+ export interface ApiInfo {
19
+ name: string;
20
+ version: string;
21
+ description: string;
22
+ documentation: string;
23
+ }
24
+ export interface SendWebhookOptions {
25
+ url: string;
26
+ method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
27
+ payload?: any;
28
+ headers?: Record<string, string>;
29
+ idempotencyKey?: string;
30
+ }
31
+ export interface JobResponse {
32
+ jobId: string;
33
+ status: string;
34
+ type: string;
35
+ createdAt: string;
36
+ }
37
+ export interface JobStatus {
38
+ id: string;
39
+ type: string;
40
+ status: "pending" | "processing" | "completed" | "failed";
41
+ attempts: number;
42
+ errorMessage?: string;
43
+ createdAt: string;
44
+ completedAt?: string;
45
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@notifykit/sdk",
3
+ "version": "1.0.0",
4
+ "description": "Official NotifyKit SDK for Node.js",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "README.md",
10
+ "LICENSE"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "prepublishOnly": "npm run build"
15
+ },
16
+ "engines": {
17
+ "node": ">=14.0.0"
18
+ },
19
+ "keywords": [
20
+ "notifykit",
21
+ "notifications",
22
+ "email",
23
+ "webhook",
24
+ "api"
25
+ ],
26
+ "author": "brayzonn",
27
+ "license": "MIT",
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/brayzonn/notifykit-sdk.git"
31
+ },
32
+ "bugs": {
33
+ "url": "https://github.com/brayzonn/notifykit-sdk/issues"
34
+ },
35
+ "homepage": "https://github.com/brayzonn/notifykit-sdk#readme",
36
+ "dependencies": {
37
+ "axios": "^1.6.0"
38
+ },
39
+ "devDependencies": {
40
+ "@types/node": "^20.0.0",
41
+ "typescript": "^5.0.0"
42
+ }
43
+ }