@sendmailos/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.
@@ -0,0 +1,480 @@
1
+ /**
2
+ * SendMailOS SDK Types
3
+ */
4
+ interface SendMailOSOptions {
5
+ /** Base URL for the API (default: https://api.sendmailos.com) */
6
+ baseUrl?: string;
7
+ /** Request timeout in milliseconds (default: 30000) */
8
+ timeout?: number;
9
+ /** Custom fetch implementation (for testing/Node.js polyfill) */
10
+ fetch?: typeof fetch;
11
+ }
12
+ interface SendEmailRequest {
13
+ /** Recipient email address */
14
+ to: string;
15
+ /** Email subject line (supports Handlebars variables) */
16
+ subject: string;
17
+ /** HTML content (required if no templateId) */
18
+ html?: string;
19
+ /** Template ID to use (required if no html) */
20
+ templateId?: string;
21
+ /** Sender display name (default: "System") */
22
+ fromName?: string;
23
+ /** Sender email address (must be from verified domain) */
24
+ fromEmail?: string;
25
+ /** Template variables for Handlebars interpolation */
26
+ variables?: Record<string, unknown>;
27
+ /** Email type: "transactional" (default) or "marketing" */
28
+ type?: 'transactional' | 'marketing';
29
+ }
30
+ interface SendEmailResponse {
31
+ success: boolean;
32
+ message: string;
33
+ id: string;
34
+ sandbox?: boolean;
35
+ }
36
+ interface Subscriber {
37
+ id: string;
38
+ email: string;
39
+ firstName?: string;
40
+ lastName?: string;
41
+ status: 'subscribed' | 'unsubscribed' | 'bounced' | 'complained';
42
+ tags?: string[];
43
+ source: string;
44
+ createdAt: string;
45
+ primaryDomain?: {
46
+ id: string;
47
+ domainName: string;
48
+ };
49
+ }
50
+ interface CreateSubscriberRequest {
51
+ /** Subscriber email address */
52
+ email: string;
53
+ /** First name (for personalization) */
54
+ firstName?: string;
55
+ /** Last name (for personalization) */
56
+ lastName?: string;
57
+ /** Tags for segmentation */
58
+ tags?: string[];
59
+ /** Associate with a specific domain */
60
+ domainId?: string;
61
+ }
62
+ interface CreateSubscriberResponse {
63
+ success: boolean;
64
+ subscriber: Subscriber;
65
+ }
66
+ interface ListSubscribersRequest {
67
+ /** Results per page (default: 20, max: 100) */
68
+ limit?: number;
69
+ /** Pagination offset */
70
+ offset?: number;
71
+ }
72
+ interface ListSubscribersResponse {
73
+ success: boolean;
74
+ subscribers: Subscriber[];
75
+ total: number;
76
+ limit: number;
77
+ offset: number;
78
+ }
79
+ interface SendCampaignRequest {
80
+ /** Campaign name (for tracking) */
81
+ name?: string;
82
+ /** Email subject line (supports Handlebars) */
83
+ subject: string;
84
+ /** Sender display name */
85
+ fromName: string;
86
+ /** Sender email (from verified domain) */
87
+ fromEmail: string;
88
+ /** HTML content (required if no templateId) */
89
+ html?: string;
90
+ /** Template ID (required if no html) */
91
+ templateId?: string;
92
+ /** Filter subscribers by tags (AND logic) */
93
+ tags?: string[];
94
+ /** Global template variables */
95
+ variables?: Record<string, unknown>;
96
+ }
97
+ interface SendCampaignResponse {
98
+ success: boolean;
99
+ message: string;
100
+ campaignId: string;
101
+ }
102
+ interface Domain {
103
+ id: string;
104
+ domainName: string;
105
+ status: 'pending' | 'verified' | 'failed';
106
+ dkimTokens: string[];
107
+ createdAt: string;
108
+ verifiedAt?: string;
109
+ dnsRecords?: DnsRecord[];
110
+ }
111
+ interface DnsRecord {
112
+ type: 'CNAME' | 'TXT' | 'MX';
113
+ name: string;
114
+ value: string;
115
+ }
116
+ interface CreateDomainRequest {
117
+ /** Domain name (e.g., "yourcompany.com") */
118
+ domain: string;
119
+ }
120
+ interface CreateDomainResponse {
121
+ success: boolean;
122
+ domain: Domain;
123
+ }
124
+ interface ListDomainsResponse {
125
+ success: boolean;
126
+ domains: Domain[];
127
+ }
128
+ type WebhookEventType = 'email.sent' | 'email.delivered' | 'email.opened' | 'email.clicked' | 'email.bounced' | 'email.complained';
129
+ interface WebhookEvent {
130
+ id: string;
131
+ type: WebhookEventType;
132
+ createdAt: string;
133
+ data: {
134
+ emailId: string;
135
+ messageId: string;
136
+ recipient: string;
137
+ campaignId?: string;
138
+ timestamp: string;
139
+ metadata?: Record<string, unknown>;
140
+ };
141
+ }
142
+ interface CreateWebhookRequest {
143
+ /** Endpoint URL to receive webhook events */
144
+ url: string;
145
+ /** Events to subscribe to */
146
+ events: WebhookEventType[];
147
+ /** Signing secret for webhook verification */
148
+ secret?: string;
149
+ }
150
+ interface Webhook {
151
+ id: string;
152
+ url: string;
153
+ events: WebhookEventType[];
154
+ active: boolean;
155
+ createdAt: string;
156
+ }
157
+ interface ApiError {
158
+ success: false;
159
+ error: string;
160
+ code: string;
161
+ retryAfter?: number;
162
+ }
163
+
164
+ /**
165
+ * Emails resource for sending transactional emails
166
+ */
167
+ declare class EmailsResource {
168
+ private request;
169
+ constructor(request: <T>(endpoint: string, options?: RequestInit) => Promise<T>);
170
+ /**
171
+ * Send a transactional email
172
+ *
173
+ * @example
174
+ * ```ts
175
+ * const result = await client.emails.send({
176
+ * to: 'user@example.com',
177
+ * fromName: 'Your Company',
178
+ * fromEmail: 'hello@yourcompany.com',
179
+ * subject: 'Welcome!',
180
+ * html: '<h1>Hello!</h1>'
181
+ * });
182
+ * ```
183
+ */
184
+ send(params: SendEmailRequest): Promise<SendEmailResponse>;
185
+ /**
186
+ * Send email using a template
187
+ *
188
+ * @example
189
+ * ```ts
190
+ * const result = await client.emails.sendTemplate({
191
+ * to: 'user@example.com',
192
+ * templateId: 'tmpl_welcome',
193
+ * variables: { firstName: 'John' }
194
+ * });
195
+ * ```
196
+ */
197
+ sendTemplate(params: {
198
+ to: string;
199
+ templateId: string;
200
+ fromName?: string;
201
+ fromEmail?: string;
202
+ subject?: string;
203
+ variables?: Record<string, unknown>;
204
+ }): Promise<SendEmailResponse>;
205
+ }
206
+
207
+ /**
208
+ * Subscribers resource for managing email contacts
209
+ */
210
+ declare class SubscribersResource {
211
+ private request;
212
+ constructor(request: <T>(endpoint: string, options?: RequestInit) => Promise<T>);
213
+ /**
214
+ * Create or update a subscriber (upsert)
215
+ *
216
+ * @example
217
+ * ```ts
218
+ * const { subscriber } = await client.subscribers.create({
219
+ * email: 'user@example.com',
220
+ * firstName: 'John',
221
+ * tags: ['newsletter', 'premium']
222
+ * });
223
+ * ```
224
+ */
225
+ create(params: CreateSubscriberRequest): Promise<CreateSubscriberResponse>;
226
+ /**
227
+ * List all subscribers with pagination
228
+ *
229
+ * @example
230
+ * ```ts
231
+ * const { subscribers, total } = await client.subscribers.list({
232
+ * limit: 50,
233
+ * offset: 0
234
+ * });
235
+ * ```
236
+ */
237
+ list(params?: ListSubscribersRequest): Promise<ListSubscribersResponse>;
238
+ /**
239
+ * Get a single subscriber by ID
240
+ */
241
+ get(subscriberId: string): Promise<{
242
+ success: boolean;
243
+ subscriber: Subscriber;
244
+ }>;
245
+ /**
246
+ * Update a subscriber by ID
247
+ */
248
+ update(subscriberId: string, params: Partial<CreateSubscriberRequest>): Promise<CreateSubscriberResponse>;
249
+ /**
250
+ * Update a subscriber by email address
251
+ */
252
+ updateByEmail(email: string, params: Partial<Omit<CreateSubscriberRequest, 'email'>>): Promise<CreateSubscriberResponse>;
253
+ /**
254
+ * Delete/unsubscribe a subscriber
255
+ */
256
+ delete(subscriberId: string): Promise<{
257
+ success: boolean;
258
+ }>;
259
+ /**
260
+ * Add tags to a subscriber
261
+ */
262
+ addTags(subscriberId: string, tags: string[]): Promise<CreateSubscriberResponse>;
263
+ /**
264
+ * Remove tags from a subscriber
265
+ */
266
+ removeTags(subscriberId: string, tags: string[]): Promise<CreateSubscriberResponse>;
267
+ }
268
+
269
+ /**
270
+ * Campaigns resource for bulk email sending
271
+ */
272
+ declare class CampaignsResource {
273
+ private request;
274
+ constructor(request: <T>(endpoint: string, options?: RequestInit) => Promise<T>);
275
+ /**
276
+ * Send a campaign to subscribers
277
+ *
278
+ * @example
279
+ * ```ts
280
+ * const result = await client.campaigns.send({
281
+ * name: 'January Newsletter',
282
+ * subject: 'What\'s new this month',
283
+ * fromName: 'Your Company',
284
+ * fromEmail: 'news@yourcompany.com',
285
+ * html: '<h1>Hello {{first_name}}!</h1>',
286
+ * tags: ['newsletter', 'active']
287
+ * });
288
+ * ```
289
+ */
290
+ send(params: SendCampaignRequest): Promise<SendCampaignResponse>;
291
+ /**
292
+ * Send campaign using a saved template
293
+ */
294
+ sendTemplate(params: {
295
+ name?: string;
296
+ templateId: string;
297
+ subject: string;
298
+ fromName: string;
299
+ fromEmail: string;
300
+ tags?: string[];
301
+ variables?: Record<string, unknown>;
302
+ }): Promise<SendCampaignResponse>;
303
+ }
304
+
305
+ /**
306
+ * Domains resource for managing sending domains
307
+ */
308
+ declare class DomainsResource {
309
+ private request;
310
+ constructor(request: <T>(endpoint: string, options?: RequestInit) => Promise<T>);
311
+ /**
312
+ * Add a new sending domain
313
+ * Returns DKIM tokens and DNS records for verification
314
+ *
315
+ * @example
316
+ * ```ts
317
+ * const { domain } = await client.domains.create({
318
+ * domain: 'yourcompany.com'
319
+ * });
320
+ *
321
+ * console.log('Add these DNS records:', domain.dnsRecords);
322
+ * ```
323
+ */
324
+ create(params: CreateDomainRequest): Promise<CreateDomainResponse>;
325
+ /**
326
+ * List all domains for the organization
327
+ */
328
+ list(): Promise<ListDomainsResponse>;
329
+ /**
330
+ * Get a single domain by ID
331
+ */
332
+ get(domainId: string): Promise<{
333
+ success: boolean;
334
+ domain: Domain;
335
+ }>;
336
+ /**
337
+ * Verify a domain (trigger DNS check)
338
+ */
339
+ verify(domainId: string): Promise<{
340
+ success: boolean;
341
+ domain: Domain;
342
+ }>;
343
+ /**
344
+ * Delete a domain
345
+ */
346
+ delete(domainId: string): Promise<{
347
+ success: boolean;
348
+ }>;
349
+ }
350
+
351
+ /**
352
+ * SendMailOS SDK Client
353
+ *
354
+ * @example
355
+ * ```ts
356
+ * import { SendMailOS } from '@sendmailos/sdk';
357
+ *
358
+ * const client = new SendMailOS('sk_live_your_api_key');
359
+ *
360
+ * // Send an email
361
+ * await client.emails.send({
362
+ * to: 'user@example.com',
363
+ * subject: 'Hello!',
364
+ * html: '<h1>Welcome!</h1>'
365
+ * });
366
+ *
367
+ * // Add a subscriber
368
+ * await client.subscribers.create({
369
+ * email: 'user@example.com',
370
+ * tags: ['newsletter']
371
+ * });
372
+ * ```
373
+ */
374
+ declare class SendMailOS {
375
+ private readonly apiKey;
376
+ private readonly baseUrl;
377
+ private readonly timeout;
378
+ private readonly fetchFn;
379
+ /** Email sending operations */
380
+ readonly emails: EmailsResource;
381
+ /** Subscriber management */
382
+ readonly subscribers: SubscribersResource;
383
+ /** Campaign operations */
384
+ readonly campaigns: CampaignsResource;
385
+ /** Domain management */
386
+ readonly domains: DomainsResource;
387
+ constructor(apiKey: string, options?: SendMailOSOptions);
388
+ /**
389
+ * Make an authenticated request to the API
390
+ */
391
+ private request;
392
+ private safeParseJson;
393
+ /**
394
+ * Check if the API key is valid (test mode only)
395
+ */
396
+ get isTestMode(): boolean;
397
+ /**
398
+ * Get the SDK version
399
+ */
400
+ static get version(): string;
401
+ }
402
+
403
+ /**
404
+ * Custom error classes for SendMailOS SDK
405
+ */
406
+ declare class SendMailOSError extends Error {
407
+ readonly code: string;
408
+ readonly statusCode: number;
409
+ readonly retryAfter?: number;
410
+ constructor(message: string, code: string, statusCode: number, retryAfter?: number);
411
+ /** Whether this error is retryable (rate limit or server error) */
412
+ get isRetryable(): boolean;
413
+ }
414
+ declare class AuthenticationError extends SendMailOSError {
415
+ constructor(message?: string);
416
+ }
417
+ declare class ValidationError extends SendMailOSError {
418
+ constructor(message: string);
419
+ }
420
+ declare class RateLimitError extends SendMailOSError {
421
+ constructor(message: string, retryAfter: number);
422
+ }
423
+ declare class NotFoundError extends SendMailOSError {
424
+ constructor(message: string);
425
+ }
426
+
427
+ /**
428
+ * Webhook signature verification utilities
429
+ *
430
+ * IMPORTANT: This module uses timing-safe comparison to prevent timing attacks.
431
+ */
432
+ interface VerifyWebhookParams {
433
+ /** Raw request body as string */
434
+ payload: string;
435
+ /** Value of X-SendMailOS-Signature header */
436
+ signature: string;
437
+ /** Value of X-SendMailOS-Timestamp header */
438
+ timestamp: string;
439
+ /** Your webhook signing secret */
440
+ secret: string;
441
+ /** Maximum age in seconds (default: 300 = 5 minutes) */
442
+ tolerance?: number;
443
+ }
444
+ /**
445
+ * Verify a webhook signature to ensure the request came from SendMailOS
446
+ *
447
+ * @example
448
+ * ```ts
449
+ * import { verifyWebhookSignature } from '@sendmailos/sdk';
450
+ *
451
+ * app.post('/webhooks', (req, res) => {
452
+ * const isValid = verifyWebhookSignature({
453
+ * payload: JSON.stringify(req.body),
454
+ * signature: req.headers['x-sendmailos-signature'],
455
+ * timestamp: req.headers['x-sendmailos-timestamp'],
456
+ * secret: process.env.WEBHOOK_SECRET
457
+ * });
458
+ *
459
+ * if (!isValid) {
460
+ * return res.status(401).json({ error: 'Invalid signature' });
461
+ * }
462
+ *
463
+ * // Process webhook...
464
+ * });
465
+ * ```
466
+ */
467
+ declare function verifyWebhookSignature(params: VerifyWebhookParams): boolean;
468
+ /**
469
+ * Async version of webhook verification (recommended for edge/browser)
470
+ */
471
+ declare function verifyWebhookSignatureAsync(params: VerifyWebhookParams): Promise<boolean>;
472
+ /**
473
+ * Construct a webhook event from raw request data
474
+ */
475
+ declare function constructWebhookEvent<T = unknown>(payload: string, headers: {
476
+ signature: string;
477
+ timestamp: string;
478
+ }, secret: string): T;
479
+
480
+ export { type ApiError, AuthenticationError, type CreateDomainRequest, type CreateDomainResponse, type CreateSubscriberRequest, type CreateSubscriberResponse, type CreateWebhookRequest, type DnsRecord, type Domain, type ListDomainsResponse, type ListSubscribersRequest, type ListSubscribersResponse, NotFoundError, RateLimitError, type SendCampaignRequest, type SendCampaignResponse, type SendEmailRequest, type SendEmailResponse, SendMailOS, SendMailOSError, type SendMailOSOptions, type Subscriber, ValidationError, type VerifyWebhookParams, type Webhook, type WebhookEvent, type WebhookEventType, constructWebhookEvent, SendMailOS as default, verifyWebhookSignature, verifyWebhookSignatureAsync };