@develemail/sdk 0.1.1 → 0.4.1

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/dist/index.d.ts CHANGED
@@ -1,35 +1,135 @@
1
1
  interface DevelEmailConfig {
2
2
  apiKey: string;
3
3
  baseUrl: string;
4
+ maxRetries?: number;
4
5
  }
6
+
7
+ /** Wire-format attachment shape — what actually goes over HTTP. */
8
+ interface WireAttachmentInput {
9
+ filename: string;
10
+ content: string;
11
+ contentType: string;
12
+ }
13
+ /** Ergonomic attachment input for `emails.send()` / `emails.batch()`. */
14
+ interface AttachmentInput {
15
+ filename: string;
16
+ content: string | Uint8Array;
17
+ contentType: string;
18
+ }
19
+ /**
20
+ * Deliberately different from the API's `SendEmailInput` in `attachments`
21
+ * only: this is the ergonomic pre-request shape while the API type is the
22
+ * post-parse wire shape. Every other field matches exactly.
23
+ */
5
24
  interface SendEmailInput {
25
+ /**
26
+ * Sender. Either a bare address (`noreply@example.com`) or a display-name
27
+ * mailbox (`Acme <noreply@example.com>`). Names containing commas or
28
+ * specials must be quoted (`"Acme, Inc." <noreply@example.com>`); non-ASCII
29
+ * names are encoded for you. The address domain must be verified.
30
+ */
6
31
  from: string;
7
32
  to: string | string[];
8
- subject: string;
33
+ subject?: string;
9
34
  html?: string;
10
35
  text?: string;
11
36
  tags?: string[];
12
37
  metadata?: Record<string, unknown>;
38
+ template?: string;
39
+ variables?: Record<string, string>;
40
+ send_at?: string;
41
+ attachments?: AttachmentInput[];
42
+ /** RFC 5322 Message-ID (angle brackets included, e.g. `<id@host>`). */
43
+ inReplyTo?: string;
44
+ /** Same Message-ID format as `inReplyTo`, oldest first. */
45
+ references?: string[];
13
46
  }
47
+ interface SendOptions {
48
+ idempotencyKey?: string;
49
+ }
50
+ /** Mirrors `apps/api/src/domains/emails/types.ts`'s server-side copy. */
14
51
  interface EmailResponse {
15
52
  id: string;
16
53
  status: string;
54
+ duplicate?: boolean;
17
55
  }
18
- declare class DevelEmailError extends Error {
19
- readonly status: number;
20
- constructor(status: number, message: string);
56
+ interface BatchEmailResultItem {
57
+ index: number;
58
+ id?: string;
59
+ status?: string;
60
+ duplicate?: boolean;
61
+ error?: string;
62
+ code?: string;
21
63
  }
22
- declare class EmailsNamespace {
23
- private readonly config;
24
- constructor(config: DevelEmailConfig);
25
- send(input: SendEmailInput): Promise<EmailResponse>;
26
- get(id: string): Promise<EmailResponse>;
27
- private request;
64
+ interface BatchEmailResponse {
65
+ results: BatchEmailResultItem[];
66
+ created: number;
67
+ errors: number;
68
+ limitReached?: boolean;
28
69
  }
29
- declare class DevelEmail {
30
- readonly emails: EmailsNamespace;
31
- constructor(config: DevelEmailConfig);
70
+ /** Every status an email can be in. */
71
+ declare const EMAIL_STATUSES: readonly ["queued", "rendering", "submitted_to_postfix", "deferred", "sent", "delivered", "bounced", "rejected", "failed", "suppressed", "cancelled", "scheduled", "quarantined", "sandboxed"];
72
+ type EmailStatus = (typeof EMAIL_STATUSES)[number];
73
+ /** Every event type the server currently emits. */
74
+ declare const EMAIL_EVENT_TYPES: readonly ["queued", "rendering_started", "rendering_completed", "submitted_to_postfix", "deferred", "sent", "delivered", "bounced", "rejected", "failed", "suppressed", "cancelled", "retry_scheduled", "open", "click", "quarantined"];
75
+ type EmailEventType = (typeof EMAIL_EVENT_TYPES)[number];
76
+ /** `metadata` shape for Postfix-derived lifecycle events. */
77
+ interface DeliveryEventData {
78
+ queueId: string;
79
+ relay: string;
80
+ response: string;
81
+ timestamp: string;
32
82
  }
83
+
84
+ interface Domain {
85
+ id: string;
86
+ organizationId: string;
87
+ name: string;
88
+ verificationStatus: string;
89
+ spfStatus: string | null;
90
+ dkimStatus: string | null;
91
+ dmarcStatus: string | null;
92
+ ptrStatus: string | null;
93
+ mxStatus: string | null;
94
+ returnPathStatus: string | null;
95
+ dmarcPolicy: string | null;
96
+ dkimPublicKey: string;
97
+ dkimSelector: string;
98
+ createdAt: string;
99
+ updatedAt: string;
100
+ }
101
+ interface DomainCreateInput {
102
+ name: string;
103
+ dkimSelector?: string;
104
+ }
105
+
106
+ interface Template {
107
+ id: string;
108
+ organizationId: string;
109
+ name: string;
110
+ subject: string;
111
+ html: string;
112
+ text?: string | null;
113
+ variables?: string[];
114
+ createdAt: string;
115
+ updatedAt: string;
116
+ }
117
+ interface TemplateCreateInput {
118
+ name: string;
119
+ subject: string;
120
+ html: string;
121
+ text?: string;
122
+ variables?: string[];
123
+ }
124
+ interface TemplateUpdateInput {
125
+ name?: string;
126
+ subject?: string;
127
+ html?: string;
128
+ text?: string;
129
+ variables?: string[];
130
+ }
131
+
132
+ /** Mirrors `apps/api/src/domains/webhooks/types.ts`'s `WebhookPayload`. */
33
133
  interface WebhookEvent {
34
134
  event: string;
35
135
  emailId: string | null;
@@ -38,6 +138,354 @@ interface WebhookEvent {
38
138
  timestamp: string;
39
139
  metadata: Record<string, unknown>;
40
140
  }
141
+
142
+ type CampaignStatus = 'draft' | 'scheduled' | 'sending' | 'paused' | 'sent' | 'cancelled';
143
+ interface Campaign {
144
+ id: string;
145
+ projectId: string;
146
+ listId: string | null;
147
+ tagFilters: string[] | null;
148
+ tagFilterMode: 'and' | 'or' | null;
149
+ templateId: string | null;
150
+ name: string;
151
+ subject: string;
152
+ fromAddress: string;
153
+ fromName: string | null;
154
+ rawHtml: string | null;
155
+ rawText: string | null;
156
+ status: CampaignStatus;
157
+ scheduledFor: string | null;
158
+ sentAt: string | null;
159
+ totalRecipients: number | null;
160
+ summarizedStats: {
161
+ delivered?: number;
162
+ deliveryUnknown?: number;
163
+ opened?: number;
164
+ clicked?: number;
165
+ bounced?: number;
166
+ configurationBounced?: number;
167
+ unsubscribed?: number;
168
+ } | null;
169
+ createdAt: string;
170
+ updatedAt: string;
171
+ }
172
+ /** The SDK accepts optional pagination before the API applies defaults. */
173
+ interface CampaignListQuery {
174
+ projectId: string;
175
+ status?: CampaignStatus;
176
+ limit?: number;
177
+ offset?: number;
178
+ }
179
+ interface CampaignCreateInput {
180
+ projectId: string;
181
+ listId?: string;
182
+ tagFilters?: string[];
183
+ tagFilterMode?: 'and' | 'or';
184
+ templateId?: string;
185
+ name: string;
186
+ subject: string;
187
+ fromAddress: string;
188
+ fromName?: string;
189
+ rawHtml?: string;
190
+ rawText?: string;
191
+ scheduledFor?: string;
192
+ }
193
+ interface CampaignUpdateInput {
194
+ listId?: string | null;
195
+ tagFilters?: string[] | null;
196
+ tagFilterMode?: 'and' | 'or';
197
+ templateId?: string | null;
198
+ name?: string;
199
+ subject?: string;
200
+ fromAddress?: string;
201
+ fromName?: string;
202
+ rawHtml?: string;
203
+ rawText?: string;
204
+ scheduledFor?: string;
205
+ }
206
+ /** Mirrors `apps/api/src/domains/campaigns/types.ts`'s server-side copy. */
207
+ interface CampaignStats {
208
+ campaignId: string;
209
+ totalRecipients: number;
210
+ delivered: number;
211
+ deliveryUnknown: number;
212
+ opened: number;
213
+ clicked: number;
214
+ /** Reputation bounces only; configuration bounces are in `configurationBounced`. */
215
+ bounced: number;
216
+ configurationBounced: number;
217
+ unsubscribed: number;
218
+ openRate: number;
219
+ clickRate: number;
220
+ bounceRate: number;
221
+ links: Array<{
222
+ url: string;
223
+ clicks: number;
224
+ }>;
225
+ }
226
+ interface CampaignProviderStats {
227
+ provider: string;
228
+ opens: number;
229
+ clicks: number;
230
+ total: number;
231
+ }
232
+
233
+ interface Contact {
234
+ id: string;
235
+ projectId: string;
236
+ email: string;
237
+ firstName: string | null;
238
+ lastName: string | null;
239
+ country: string | null;
240
+ tags: string[];
241
+ unsubscribedAt: string | null;
242
+ createdAt: string;
243
+ updatedAt: string;
244
+ }
245
+ /** The SDK preserves optional filters before API parsing/defaulting. */
246
+ interface ContactListQuery {
247
+ projectId: string;
248
+ search?: string;
249
+ tags?: string[];
250
+ tagMode?: 'and' | 'or';
251
+ limit?: number;
252
+ offset?: number;
253
+ }
254
+ interface ContactListResponse {
255
+ data: Contact[];
256
+ total: number;
257
+ }
258
+ interface ContactCreateInput {
259
+ projectId: string;
260
+ email: string;
261
+ firstName?: string;
262
+ lastName?: string;
263
+ tags?: string[];
264
+ }
265
+ interface ContactUpdateInput {
266
+ unsubscribe: boolean;
267
+ }
268
+ interface ContactBulkContactInput {
269
+ email: string;
270
+ firstName?: string;
271
+ lastName?: string;
272
+ country?: string;
273
+ tags?: string[];
274
+ }
275
+ interface ContactBulkInput {
276
+ projectId: string;
277
+ contacts: ContactBulkContactInput[];
278
+ }
279
+ interface ContactBulkResponse {
280
+ inserted: number;
281
+ updated: number;
282
+ skipped: number;
283
+ }
284
+ /** `addedAt` is serialized to string for SDK consumers. */
285
+ interface ContactListItem {
286
+ id: string;
287
+ name: string;
288
+ memberCount: number;
289
+ addedAt: string;
290
+ }
291
+
292
+ interface List {
293
+ id: string;
294
+ projectId: string;
295
+ name: string;
296
+ description: string | null;
297
+ createdAt: string;
298
+ updatedAt: string;
299
+ }
300
+ /** API dates are serialized to strings for SDK consumers. */
301
+ interface ListWithCount extends List {
302
+ memberCount: number;
303
+ }
304
+ interface ListCreateInput {
305
+ projectId: string;
306
+ name: string;
307
+ description?: string;
308
+ }
309
+ interface ListUpdateInput {
310
+ name?: string;
311
+ description?: string;
312
+ }
313
+ interface ListMembersQuery {
314
+ search?: string;
315
+ limit?: number;
316
+ offset?: number;
317
+ }
318
+ interface ListMembersResponse {
319
+ data: Contact[];
320
+ total: number;
321
+ }
322
+
323
+ /** Mirrors `apps/api/src/domains/sms/repo.types.ts`'s status values. */
324
+ declare const SMS_STATUSES: readonly ["queued", "sending", "sent", "delivered", "deferred", "failed", "suppressed"];
325
+ type SmsStatus = (typeof SMS_STATUSES)[number];
326
+ /** Mirrors `apps/api/src/domains/sms/types.ts`'s `SendSmsInput`. */
327
+ interface SendSmsInput {
328
+ to: string;
329
+ from?: string;
330
+ body?: string;
331
+ templateName?: string;
332
+ variables?: Record<string, string>;
333
+ tags?: string[];
334
+ metadata?: Record<string, unknown>;
335
+ }
336
+ interface SmsMessageResponse {
337
+ id: string;
338
+ to: string;
339
+ from: string | null;
340
+ body: string;
341
+ status: string;
342
+ tags: string[];
343
+ metadata: Record<string, unknown>;
344
+ createdAt: string;
345
+ updatedAt: string;
346
+ }
347
+ interface SmsListResponse {
348
+ data: SmsMessageResponse[];
349
+ nextCursor: string | null;
350
+ }
351
+ interface SmsListQuery {
352
+ status?: SmsStatus;
353
+ limit?: number;
354
+ cursor?: string;
355
+ }
356
+ interface BatchSmsResultItem {
357
+ index: number;
358
+ id?: string;
359
+ status?: string;
360
+ error?: string;
361
+ code?: string;
362
+ }
363
+ interface BatchSmsResponse {
364
+ results: BatchSmsResultItem[];
365
+ created: number;
366
+ errors: number;
367
+ }
368
+
369
+ declare class HttpClient {
370
+ private readonly baseUrl;
371
+ private readonly apiKey;
372
+ private readonly maxRetries;
373
+ constructor(config: DevelEmailConfig);
374
+ get<T>(path: string): Promise<T>;
375
+ post<T>(path: string, body: unknown, extraHeaders?: Record<string, string>): Promise<T>;
376
+ put<T>(path: string, body: unknown, extraHeaders?: Record<string, string>): Promise<T>;
377
+ patch<T>(path: string, body: unknown, extraHeaders?: Record<string, string>): Promise<T>;
378
+ delete<T>(path: string, extraHeaders?: Record<string, string>): Promise<T>;
379
+ private request;
380
+ private backoff;
381
+ }
382
+
383
+ declare class Emails {
384
+ private readonly http;
385
+ constructor(http: HttpClient);
386
+ send(input: SendEmailInput, options?: SendOptions): Promise<EmailResponse>;
387
+ batch(emails: SendEmailInput[], options?: SendOptions): Promise<BatchEmailResponse>;
388
+ get(id: string): Promise<EmailResponse>;
389
+ }
390
+
391
+ declare class Domains {
392
+ private readonly http;
393
+ constructor(http: HttpClient);
394
+ list(): Promise<Domain[]>;
395
+ get(id: string): Promise<Domain>;
396
+ create(input: DomainCreateInput): Promise<Domain>;
397
+ delete(id: string): Promise<void>;
398
+ verify(id: string): Promise<Domain>;
399
+ }
400
+
401
+ declare class Templates {
402
+ private readonly http;
403
+ constructor(http: HttpClient);
404
+ list(): Promise<Template[]>;
405
+ get(id: string): Promise<Template>;
406
+ create(input: TemplateCreateInput): Promise<Template>;
407
+ update(id: string, input: TemplateUpdateInput): Promise<Template>;
408
+ delete(id: string): Promise<void>;
409
+ }
410
+
411
+ declare class Campaigns {
412
+ private readonly http;
413
+ constructor(http: HttpClient);
414
+ list(query: CampaignListQuery): Promise<Campaign[]>;
415
+ get(id: string): Promise<Campaign>;
416
+ create(input: CampaignCreateInput): Promise<Campaign>;
417
+ update(id: string, input: CampaignUpdateInput): Promise<Campaign>;
418
+ send(id: string): Promise<Campaign>;
419
+ pause(id: string): Promise<Campaign>;
420
+ resume(id: string): Promise<Campaign>;
421
+ cancel(id: string): Promise<Campaign & {
422
+ note: string;
423
+ }>;
424
+ duplicate(id: string): Promise<Campaign>;
425
+ delete(id: string): Promise<void>;
426
+ stats(id: string): Promise<CampaignStats>;
427
+ providerStats(id: string): Promise<CampaignProviderStats[]>;
428
+ }
429
+
430
+ declare class Contacts {
431
+ private readonly http;
432
+ constructor(http: HttpClient);
433
+ list(query: ContactListQuery): Promise<ContactListResponse>;
434
+ get(id: string): Promise<Contact>;
435
+ create(input: ContactCreateInput): Promise<Contact>;
436
+ update(id: string, input: ContactUpdateInput): Promise<Contact>;
437
+ delete(id: string): Promise<void>;
438
+ bulkCreate(input: ContactBulkInput): Promise<ContactBulkResponse>;
439
+ tags(projectId: string): Promise<string[]>;
440
+ lists(contactId: string): Promise<ContactListItem[]>;
441
+ /** @deprecated Use `lists.addContacts` instead. */
442
+ addToList(contactId: string, listId: string): Promise<void>;
443
+ /** @deprecated Use `lists.removeContact` instead. */
444
+ removeFromList(contactId: string, listId: string): Promise<void>;
445
+ }
446
+
447
+ declare class Lists {
448
+ private readonly http;
449
+ constructor(http: HttpClient);
450
+ list(projectId: string): Promise<ListWithCount[]>;
451
+ get(id: string): Promise<List>;
452
+ create(input: ListCreateInput): Promise<List>;
453
+ update(id: string, input: ListUpdateInput): Promise<List>;
454
+ delete(id: string): Promise<void>;
455
+ listContacts(id: string, query?: ListMembersQuery): Promise<ListMembersResponse>;
456
+ addContacts(id: string, contactIds: string[]): Promise<{
457
+ added: number;
458
+ }>;
459
+ removeContact(id: string, contactId: string): Promise<void>;
460
+ }
461
+
462
+ declare class Sms {
463
+ private readonly http;
464
+ constructor(http: HttpClient);
465
+ send(input: SendSmsInput, options?: SendOptions): Promise<SmsMessageResponse>;
466
+ sendBatch(messages: SendSmsInput[], options?: SendOptions): Promise<BatchSmsResponse>;
467
+ get(id: string): Promise<SmsMessageResponse>;
468
+ list(query?: SmsListQuery): Promise<SmsListResponse>;
469
+ }
470
+
471
+ declare class DevelEmailError extends Error {
472
+ readonly status: number;
473
+ readonly code?: string | undefined;
474
+ readonly details?: Record<string, unknown> | undefined;
475
+ constructor(status: number, message: string, code?: string | undefined, details?: Record<string, unknown> | undefined);
476
+ }
477
+
41
478
  declare function verifyWebhookSignature(payload: string, signature: string, secret: string): Promise<boolean>;
42
479
 
43
- export { DevelEmail, type DevelEmailConfig, DevelEmailError, type EmailResponse, type SendEmailInput, type WebhookEvent, verifyWebhookSignature };
480
+ declare class DevelEmail {
481
+ readonly emails: Emails;
482
+ readonly domains: Domains;
483
+ readonly templates: Templates;
484
+ readonly campaigns: Campaigns;
485
+ readonly contacts: Contacts;
486
+ readonly lists: Lists;
487
+ readonly sms: Sms;
488
+ constructor(config: DevelEmailConfig);
489
+ }
490
+
491
+ export { type AttachmentInput, type BatchEmailResponse, type BatchEmailResultItem, type BatchSmsResponse, type BatchSmsResultItem, type Campaign, type CampaignCreateInput, type CampaignListQuery, type CampaignProviderStats, type CampaignStats, type CampaignStatus, type CampaignUpdateInput, type Contact, type ContactBulkContactInput, type ContactBulkInput, type ContactBulkResponse, type ContactCreateInput, type ContactListItem, type ContactListQuery, type ContactListResponse, type ContactUpdateInput, type DeliveryEventData, DevelEmail, type DevelEmailConfig, DevelEmailError, type Domain, type DomainCreateInput, EMAIL_EVENT_TYPES, EMAIL_STATUSES, type EmailEventType, type EmailResponse, type EmailStatus, type List, type ListCreateInput, type ListMembersQuery, type ListMembersResponse, type ListUpdateInput, type ListWithCount, SMS_STATUSES, type SendEmailInput, type SendOptions, type SendSmsInput, type SmsListQuery, type SmsListResponse, type SmsMessageResponse, type SmsStatus, type Template, type TemplateCreateInput, type TemplateUpdateInput, type WebhookEvent, type WireAttachmentInput, verifyWebhookSignature };