@zyphr-dev/node-sdk 0.1.1 → 0.1.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.
Files changed (2) hide show
  1. package/README.md +436 -47
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # @zyphr-dev/node-sdk
2
2
 
3
- Official Zyphr SDK for Node.js, React, and React Native.
3
+ Official Zyphr SDK for Node.js, React, and React Native. Type-safe access to multi-channel notifications, subscriber management, webhooks, and authentication.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@zyphr-dev/node-sdk)](https://www.npmjs.com/package/@zyphr-dev/node-sdk)
6
+ [![license](https://img.shields.io/npm/l/@zyphr-dev/node-sdk)](./LICENSE)
4
7
 
5
8
  ## Installation
6
9
 
@@ -10,7 +13,7 @@ npm install @zyphr-dev/node-sdk
10
13
  yarn add @zyphr-dev/node-sdk
11
14
  ```
12
15
 
13
- Requires Node.js 18 or later.
16
+ **Requirements:** Node.js 18+. Zero runtime dependencies.
14
17
 
15
18
  ## Quick Start
16
19
 
@@ -22,48 +25,425 @@ const zyphr = new Zyphr({
22
25
  });
23
26
 
24
27
  // Send an email
25
- const { data: email } = await zyphr.emails.send({
26
- to: 'user@example.com',
28
+ await zyphr.emails.sendEmail({
29
+ to: [{ email: 'user@example.com', name: 'Jane' }],
27
30
  subject: 'Welcome!',
28
- html: '<h1>Hello!</h1>',
31
+ html: '<h1>Hello, {{name}}!</h1>',
32
+ templateData: { name: 'Jane' },
29
33
  });
30
34
 
31
35
  // Send a push notification
32
- await zyphr.push.send({
33
- subscriber_id: 'sub_123',
34
- title: 'New message',
35
- body: 'You have a new notification',
36
+ await zyphr.push.sendPush({
37
+ subscriberId: 'sub_123',
38
+ payload: { title: 'New message', body: 'You have a new notification' },
36
39
  });
37
40
 
38
41
  // Send an SMS
39
- await zyphr.sms.send({
42
+ await zyphr.sms.sendSms({
40
43
  to: '+15551234567',
41
- body: 'Your verification code is 123456',
44
+ message: 'Your verification code is 123456',
42
45
  });
43
46
 
44
47
  // Send an in-app notification
45
- await zyphr.inbox.send({
46
- subscriber_id: 'sub_123',
48
+ await zyphr.inbox.sendInApp({
49
+ subscriberId: 'sub_123',
47
50
  title: 'Welcome aboard',
48
51
  body: 'Thanks for signing up!',
49
52
  });
50
53
  ```
51
54
 
52
- ## Available APIs
53
-
54
- | Property | Description |
55
- |----------|-------------|
56
- | `zyphr.emails` | Send and manage emails |
57
- | `zyphr.push` | Send push notifications |
58
- | `zyphr.sms` | Send SMS messages |
59
- | `zyphr.inbox` | In-app notifications |
60
- | `zyphr.subscribers` | Manage subscribers and preferences |
61
- | `zyphr.templates` | Create and render templates |
62
- | `zyphr.webhooks` | Configure and monitor webhooks |
63
- | `zyphr.topics` | Manage notification topics |
64
- | `zyphr.devices` | Manage push devices |
65
- | `zyphr.applications` | Manage applications |
66
- | `zyphr.auth.*` | Authentication APIs (login, registration, MFA, etc.) |
55
+ ## Configuration
56
+
57
+ ```ts
58
+ const zyphr = new Zyphr({
59
+ apiKey: 'zy_live_xxxx', // Required your API key
60
+ baseUrl: 'https://custom.api.url', // Optional defaults to https://api.zyphr.dev/v1
61
+ });
62
+ ```
63
+
64
+ | Option | Type | Default | Description |
65
+ |--------|------|---------|-------------|
66
+ | `apiKey` | `string` | | **Required.** API key (`zy_live_*` or `zy_test_*`) |
67
+ | `baseUrl` | `string` | `https://api.zyphr.dev/v1` | API base URL override |
68
+
69
+ ## API Reference
70
+
71
+ ### Emails — `zyphr.emails`
72
+
73
+ Send transactional emails with template support, tracking, and scheduling.
74
+
75
+ ```ts
76
+ // Send a single email
77
+ await zyphr.emails.sendEmail({
78
+ to: [{ email: 'user@example.com', name: 'Jane' }],
79
+ from: { email: 'noreply@company.com', name: 'My App' },
80
+ subject: 'Order Confirmed',
81
+ html: '<h1>Order #{{orderId}} confirmed</h1>',
82
+ templateData: { orderId: '12345' },
83
+ tag: 'order-confirmation',
84
+ trackingEnabled: true,
85
+ });
86
+
87
+ // Send batch emails (up to 100)
88
+ await zyphr.emails.sendBatchEmail({
89
+ messages: [
90
+ { to: [{ email: 'a@example.com' }], subject: 'Hello A', html: '...' },
91
+ { to: [{ email: 'b@example.com' }], subject: 'Hello B', html: '...' },
92
+ ],
93
+ });
94
+
95
+ // Get email details and tracking
96
+ const email = await zyphr.emails.getEmail('email_id');
97
+ const events = await zyphr.emails.getEmailEvents('email_id');
98
+ const tracking = await zyphr.emails.getEmailTracking('email_id');
99
+
100
+ // List emails with filtering
101
+ const { data } = await zyphr.emails.listEmails('delivered', 'welcome', 20, 0);
102
+ ```
103
+
104
+ **Send options:** `to`, `from`, `replyTo`, `cc`, `bcc`, `subject`, `html`, `text`, `templateId`, `templateData`, `tag`, `metadata`, `headers`, `trackingEnabled`, `sendAt`, `delay`.
105
+
106
+ ### SMS — `zyphr.sms`
107
+
108
+ Send SMS messages with scheduling and provider configuration.
109
+
110
+ ```ts
111
+ // Send SMS
112
+ await zyphr.sms.sendSms({
113
+ to: '+15551234567',
114
+ message: 'Your code is 123456',
115
+ });
116
+
117
+ // Batch send (up to 100)
118
+ await zyphr.sms.sendBatchSms({
119
+ messages: [
120
+ { to: '+15551234567', message: 'Hello from Zyphr' },
121
+ { to: '+15559876543', message: 'Hello from Zyphr' },
122
+ ],
123
+ });
124
+
125
+ // Manage SMS provider configuration
126
+ const config = await zyphr.sms.getSmsConfig();
127
+ await zyphr.sms.upsertSmsConfig({
128
+ provider: 'twilio',
129
+ accountSid: 'AC...',
130
+ authToken: '...',
131
+ fromNumber: '+15550001234',
132
+ });
133
+ await zyphr.sms.verifySmsConfig();
134
+
135
+ // List and inspect
136
+ const list = await zyphr.sms.listSms(1, 20, 'delivered');
137
+ const detail = await zyphr.sms.getSms('sms_id');
138
+ ```
139
+
140
+ ### Push Notifications — `zyphr.push`
141
+
142
+ Send push notifications to individual devices, subscribers, or topic subscribers.
143
+
144
+ ```ts
145
+ // Send to a subscriber (all their devices)
146
+ await zyphr.push.sendPush({
147
+ subscriberId: 'sub_123',
148
+ payload: {
149
+ title: 'New Order',
150
+ body: 'Order #12345 has been placed',
151
+ icon: 'https://cdn.example.com/icon.png',
152
+ clickAction: 'https://app.example.com/orders/12345',
153
+ customData: { orderId: '12345' },
154
+ },
155
+ priority: 'high',
156
+ ttl: 3600,
157
+ });
158
+
159
+ // Send to a topic
160
+ await zyphr.push.sendPushToTopic('product-updates', {
161
+ payload: { title: 'New Feature', body: 'Check out our latest update' },
162
+ });
163
+
164
+ // Topic management
165
+ await zyphr.push.subscribePushTopic('alerts', { deviceIds: ['device_1'] });
166
+ await zyphr.push.unsubscribePushTopic('alerts', { deviceIds: ['device_1'] });
167
+
168
+ // Stats and listing
169
+ const stats = await zyphr.push.getPushStats();
170
+ const pushes = await zyphr.push.listPush('sub_123');
171
+ ```
172
+
173
+ ### In-App Inbox — `zyphr.inbox`
174
+
175
+ Manage in-app notifications for the `@zyphr-dev/inbox-react` component library.
176
+
177
+ ```ts
178
+ // Send in-app notification
179
+ await zyphr.inbox.sendInApp({
180
+ subscriberId: 'sub_123',
181
+ title: 'New comment',
182
+ body: 'Someone replied to your post',
183
+ category: 'comments',
184
+ cta: { label: 'View Comment', action: '/posts/456#comments' },
185
+ icon: 'https://cdn.example.com/comment.svg',
186
+ });
187
+
188
+ // Batch send (up to 100)
189
+ await zyphr.inbox.sendBatchInApp({
190
+ notifications: [
191
+ { subscriberId: 'sub_123', title: 'Hello', body: '...' },
192
+ { subscriberId: 'sub_456', title: 'Hello', body: '...' },
193
+ ],
194
+ });
195
+
196
+ // Read operations
197
+ const unread = await zyphr.inbox.getUnreadCount('sub_123');
198
+ const notifications = await zyphr.inbox.listInbox('sub_123');
199
+
200
+ // Actions
201
+ await zyphr.inbox.markInboxRead('notification_id');
202
+ await zyphr.inbox.markAllInboxRead({ subscriberId: 'sub_123' });
203
+ await zyphr.inbox.archiveInboxNotification('notification_id');
204
+ await zyphr.inbox.deleteInboxNotification('notification_id');
205
+ ```
206
+
207
+ ### Subscribers — `zyphr.subscribers`
208
+
209
+ Manage subscribers, their preferences, and consent records.
210
+
211
+ ```ts
212
+ // Create/upsert subscriber
213
+ const subscriber = await zyphr.subscribers.createSubscriber({
214
+ externalId: 'user_123',
215
+ email: 'jane@example.com',
216
+ name: 'Jane Doe',
217
+ timezone: 'America/New_York',
218
+ metadata: { plan: 'pro', company: 'Acme' },
219
+ });
220
+
221
+ // Get by ID or external ID
222
+ const sub = await zyphr.subscribers.getSubscriber('sub_id');
223
+ const subByExt = await zyphr.subscribers.getSubscriberByExternalId('user_123');
224
+
225
+ // Update
226
+ await zyphr.subscribers.updateSubscriber('sub_id', {
227
+ name: 'Jane Smith',
228
+ metadata: { plan: 'enterprise' },
229
+ });
230
+
231
+ // List with filtering
232
+ const subs = await zyphr.subscribers.listSubscribers('subscribed', undefined, 50, 0);
233
+
234
+ // Preferences
235
+ const prefs = await zyphr.subscribers.getSubscriberPreferences('sub_id');
236
+ await zyphr.subscribers.setSubscriberPreferences('sub_id', {
237
+ categoryId: 'marketing',
238
+ subscribed: false,
239
+ channel: 'email',
240
+ });
241
+
242
+ // Unsubscribe/resubscribe
243
+ await zyphr.subscribers.unsubscribeSubscriber('sub_id');
244
+ await zyphr.subscribers.resubscribeSubscriber('sub_id');
245
+
246
+ // Consent management
247
+ await zyphr.subscribers.recordSubscriberConsent('sub_id', {
248
+ type: 'opt_in', source: 'signup_form',
249
+ });
250
+ const consent = await zyphr.subscribers.getSubscriberConsent('sub_id');
251
+ const history = await zyphr.subscribers.getSubscriberConsentHistory('sub_id');
252
+
253
+ // Categories
254
+ const category = await zyphr.subscribers.createCategory({
255
+ name: 'Product Updates', slug: 'product-updates',
256
+ });
257
+ ```
258
+
259
+ ### Templates — `zyphr.templates`
260
+
261
+ Create and manage reusable email templates with variable substitution.
262
+
263
+ ```ts
264
+ // Create template
265
+ const template = await zyphr.templates.createTemplate({
266
+ name: 'welcome-email',
267
+ subject: 'Welcome, {{name}}!',
268
+ html: '<h1>Hello {{name}}</h1><p>Welcome to {{company}}.</p>',
269
+ variables: ['name', 'company'],
270
+ });
271
+
272
+ // Render template (preview without sending)
273
+ const rendered = await zyphr.templates.renderTemplate('template_id', {
274
+ data: { name: 'Jane', company: 'Acme' },
275
+ });
276
+
277
+ // CRUD operations
278
+ const t = await zyphr.templates.getTemplate('template_id');
279
+ await zyphr.templates.updateTemplate('template_id', { subject: 'New subject' });
280
+ await zyphr.templates.deleteTemplate('template_id');
281
+ const all = await zyphr.templates.listTemplates(20, 0);
282
+ ```
283
+
284
+ ### Webhooks — `zyphr.webhooks`
285
+
286
+ Configure webhook endpoints, monitor deliveries, and manage circuit breakers.
287
+
288
+ ```ts
289
+ // Create webhook
290
+ const webhook = await zyphr.webhooks.createWebhook({
291
+ url: 'https://api.example.com/webhooks',
292
+ events: ['email.delivered', 'email.bounced', 'subscriber.created'],
293
+ active: true,
294
+ });
295
+
296
+ // Delivery management
297
+ const deliveries = await zyphr.webhooks.listWebhookDeliveries(
298
+ 'webhook_id', 'failed', undefined, undefined, undefined, undefined, 20, 0
299
+ );
300
+ await zyphr.webhooks.retryWebhookDelivery('webhook_id', 'delivery_id');
301
+ await zyphr.webhooks.bulkRetryWebhookDeliveries('webhook_id', {
302
+ status: 'failed', startDate: new Date('2026-01-01'),
303
+ });
304
+
305
+ // Replay events
306
+ await zyphr.webhooks.replayWebhookEvents('webhook_id', {
307
+ startDate: new Date('2026-01-01'), endDate: new Date('2026-01-02'),
308
+ });
309
+
310
+ // Testing
311
+ await zyphr.webhooks.sendWebhookTestEvent('webhook_id', {
312
+ eventType: 'email.delivered',
313
+ });
314
+
315
+ // Metrics and health
316
+ const metrics = await zyphr.webhooks.getWebhookMetrics('webhook_id');
317
+ const circuit = await zyphr.webhooks.getWebhookCircuitState('webhook_id');
318
+ await zyphr.webhooks.closeWebhookCircuit('webhook_id');
319
+
320
+ // Secret rotation
321
+ await zyphr.webhooks.rotateWebhookSecret('webhook_id');
322
+
323
+ // Metadata
324
+ const eventTypes = await zyphr.webhooks.listWebhookEventTypes();
325
+ const versions = await zyphr.webhooks.listWebhookVersions();
326
+ const ips = await zyphr.webhooks.getWebhookIps();
327
+ ```
328
+
329
+ ### Topics — `zyphr.topics`
330
+
331
+ Group subscribers by interest for targeted notifications.
332
+
333
+ ```ts
334
+ // Create topic
335
+ await zyphr.topics.createTopic({
336
+ key: 'product-updates',
337
+ name: 'Product Updates',
338
+ description: 'New features and releases',
339
+ });
340
+
341
+ // Manage subscribers
342
+ await zyphr.topics.addTopicSubscribers('product-updates', {
343
+ subscriberIds: ['sub_123', 'sub_456'],
344
+ });
345
+ await zyphr.topics.removeTopicSubscribers('product-updates', ['sub_789']);
346
+
347
+ // CRUD
348
+ const topic = await zyphr.topics.getTopic('product-updates');
349
+ await zyphr.topics.updateTopic('product-updates', { name: 'Product News' });
350
+ await zyphr.topics.deleteTopic('old-topic');
351
+ const topics = await zyphr.topics.listTopics(50, 0);
352
+ ```
353
+
354
+ ### Devices — `zyphr.devices`
355
+
356
+ Register and manage push notification devices.
357
+
358
+ ```ts
359
+ // Register device
360
+ const device = await zyphr.devices.registerDevice({
361
+ userId: 'user_123',
362
+ platform: 'ios',
363
+ pushToken: 'apns_token_xxx',
364
+ deviceName: 'iPhone 16 Pro',
365
+ });
366
+
367
+ // List devices
368
+ const devices = await zyphr.devices.listDevices('user_123', 'ios', 20, 0);
369
+
370
+ // Stats
371
+ const stats = await zyphr.devices.getDeviceStats();
372
+
373
+ // Cleanup
374
+ await zyphr.devices.deleteDevice('device_id');
375
+ await zyphr.devices.deleteUserDevices('user_123');
376
+ ```
377
+
378
+ ### Authentication — `zyphr.auth.*`
379
+
380
+ Full authentication API with login, registration, MFA, magic links, OAuth, and more.
381
+
382
+ ```ts
383
+ // Login
384
+ const session = await zyphr.auth.login.loginEndUser({
385
+ email: 'user@example.com',
386
+ password: 'secure_password',
387
+ });
388
+
389
+ // Registration
390
+ await zyphr.auth.registration.registerUser({
391
+ email: 'new@example.com',
392
+ password: 'secure_password',
393
+ name: 'New User',
394
+ });
395
+
396
+ // Email verification
397
+ await zyphr.auth.emailVerification.sendVerification('user@example.com');
398
+
399
+ // Password reset
400
+ await zyphr.auth.passwordReset.requestReset('user@example.com');
401
+
402
+ // Magic links
403
+ await zyphr.auth.magicLinks.sendMagicLink('user@example.com');
404
+
405
+ // MFA
406
+ const mfaStatus = await zyphr.auth.mfa.getMfaStatus();
407
+ await zyphr.auth.mfa.enrollMfa({ method: 'totp' });
408
+
409
+ // User profile
410
+ const profile = await zyphr.auth.profile.getProfile();
411
+ await zyphr.auth.profile.updateProfile({ name: 'Updated Name' });
412
+ ```
413
+
414
+ **Available auth modules:** `login`, `registration`, `sessions`, `emailVerification`, `passwordReset`, `magicLinks`, `mfa`, `oauth`, `phone`, `webauthn`, `profile`.
415
+
416
+ ### WaaS — `zyphr.waas.*`
417
+
418
+ Webhooks-as-a-Service: multi-tenant webhook delivery infrastructure for your customers.
419
+
420
+ ```ts
421
+ // Create a WaaS application
422
+ const app = await zyphr.waas.applications.createWaaSApplication({
423
+ name: 'My SaaS',
424
+ description: 'Webhook delivery for My SaaS customers',
425
+ });
426
+
427
+ // Define event types
428
+ await zyphr.waas.eventTypes.createEventType(app.data.id, {
429
+ eventType: 'order.created',
430
+ name: 'Order Created',
431
+ description: 'Fired when a new order is placed',
432
+ examplePayload: { order_id: '123', total: 99.99 },
433
+ });
434
+
435
+ // Send events to all subscribed endpoints
436
+ await zyphr.waas.events.sendEvent(app.data.id, {
437
+ eventType: 'order.created',
438
+ payload: { order_id: '456', total: 149.99 },
439
+ });
440
+
441
+ // Generate portal token for embedded UI
442
+ const portalToken = await zyphr.waas.portal.getPortalToken(app.data.id);
443
+ // Pass this token to @zyphr-dev/webhook-portal
444
+ ```
445
+
446
+ **Available WaaS modules:** `applications`, `eventTypes`, `endpoints`, `events`, `deliveries`, `portal`.
67
447
 
68
448
  ## Error Handling
69
449
 
@@ -80,41 +460,50 @@ import {
80
460
  } from '@zyphr-dev/node-sdk';
81
461
 
82
462
  try {
83
- await zyphr.subscribers.get('non_existent_id');
463
+ await zyphr.subscribers.getSubscriber('non_existent_id');
84
464
  } catch (error) {
85
465
  if (error instanceof ZyphrNotFoundError) {
86
- console.log('Not found:', error.message); // 404
466
+ console.log('Not found:', error.message); // 404
87
467
  } else if (error instanceof ZyphrValidationError) {
88
- console.log('Invalid input:', error.details); // 400/422
468
+ console.log('Invalid input:', error.details); // 400/422
89
469
  } else if (error instanceof ZyphrAuthenticationError) {
90
- console.log('Check your API key'); // 401/403
470
+ console.log('Check your API key'); // 401/403
91
471
  } else if (error instanceof ZyphrRateLimitError) {
92
- console.log('Retry after:', error.retryAfter); // 429
472
+ console.log('Retry after:', error.retryAfter); // 429
93
473
  } else if (error instanceof ZyphrError) {
94
474
  console.log('API error:', error.status, error.code);
95
475
  }
96
476
  }
97
477
  ```
98
478
 
99
- All error classes extend `ZyphrError`, which extends `Error`. Common properties:
479
+ ### Error Properties
100
480
 
101
- - `status` HTTP status code
102
- - `code` — Machine-readable error code
103
- - `requestId` — Request ID for support
104
- - `details` — Additional error context (validation errors)
481
+ All error classes extend `ZyphrError`, which extends `Error`:
105
482
 
106
- ## Configuration
483
+ | Property | Type | Description |
484
+ |----------|------|-------------|
485
+ | `status` | `number` | HTTP status code |
486
+ | `code` | `string \| undefined` | Machine-readable error code |
487
+ | `requestId` | `string \| undefined` | Request ID for support tickets |
488
+ | `details` | `Record<string, unknown> \| undefined` | Validation errors and context |
489
+ | `retryAfter` | `number \| undefined` | Seconds to wait (`ZyphrRateLimitError` only) |
107
490
 
108
- ```ts
109
- const zyphr = new Zyphr({
110
- apiKey: 'zy_live_xxxx', // Required
111
- baseUrl: 'https://custom.api.url', // Optional override
112
- });
113
- ```
491
+ ## Bundle
492
+
493
+ Dual-format build — works with both ESM and CommonJS:
494
+
495
+ - **ESM:** `dist/index.js`
496
+ - **CommonJS:** `dist/index.cjs`
497
+ - **Types:** `dist/index.d.ts`
498
+
499
+ Zero runtime dependencies.
114
500
 
115
- ## Examples
501
+ ## Related Packages
116
502
 
117
- See the [examples/](./examples/) directory for complete usage examples covering all APIs.
503
+ | Package | Description |
504
+ |---------|-------------|
505
+ | [`@zyphr-dev/inbox-react`](https://www.npmjs.com/package/@zyphr-dev/inbox-react) | Drop-in React notification inbox components |
506
+ | [`@zyphr-dev/webhook-portal`](https://www.npmjs.com/package/@zyphr-dev/webhook-portal) | Embeddable webhook management portal |
118
507
 
119
508
  ## License
120
509
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zyphr-dev/node-sdk",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Official Zyphr SDK for Node.js, React, and React Native",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",