@develemail/sdk 0.4.0 → 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.cts CHANGED
@@ -3,46 +3,31 @@ interface DevelEmailConfig {
3
3
  baseUrl: string;
4
4
  maxRetries?: number;
5
5
  }
6
- /**
7
- * Wire-format attachment shape — what actually goes over HTTP (`content` is
8
- * already base64). Mirrors `apps/api/src/domains/emails/types.ts`'s
9
- * `AttachmentInput` field-for-field; kept as a distinct name from the
10
- * ergonomic `AttachmentInput` below so the DTO contract test can assert the
11
- * wire shape while `emails.send()`/`emails.batch()` callers get
12
- * base64/Buffer ergonomics. Exported only for `apps/api`'s DTO contract
13
- * test to import — not part of the ergonomic public surface callers build
14
- * requests with.
15
- */
6
+
7
+ /** Wire-format attachment shape — what actually goes over HTTP. */
16
8
  interface WireAttachmentInput {
17
9
  filename: string;
18
10
  content: string;
19
11
  contentType: string;
20
12
  }
21
- /**
22
- * Ergonomic attachment input for `emails.send()` / `emails.batch()`.
23
- * `content` accepts a `Uint8Array` (covers Node `Buffer`) — the SDK
24
- * base64-encodes it before the request goes out — or an already-base64
25
- * `string`, matching the wire format directly.
26
- *
27
- * Server caps: max 10 attachments per email, 5 MiB per file (decoded),
28
- * 7 MiB combined decoded size per email.
29
- */
13
+ /** Ergonomic attachment input for `emails.send()` / `emails.batch()`. */
30
14
  interface AttachmentInput {
31
15
  filename: string;
32
16
  content: string | Uint8Array;
33
17
  contentType: string;
34
18
  }
35
19
  /**
36
- * Deliberately different from `apps/api/src/domains/emails/types.ts`'s
37
- * `SendEmailInput` in `attachments` only: this is the ergonomic pre-request
38
- * shape (`AttachmentInput.content: string | Uint8Array`) while the api's
39
- * `z.infer`'d type is the post-parse wire shape (`content: string`,
40
- * already base64). Every other field matches exactly — see
41
- * `apps/api/src/sdk-dto-contract.test.ts`'s `Omit<..., 'attachments'>`
42
- * assertion. See `apps/api/src/sdk-dto-contract-discovery.test.ts`'s
43
- * registry for the enforcement.
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.
44
23
  */
45
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
+ */
46
31
  from: string;
47
32
  to: string | string[];
48
33
  subject?: string;
@@ -54,17 +39,15 @@ interface SendEmailInput {
54
39
  variables?: Record<string, string>;
55
40
  send_at?: string;
56
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[];
57
46
  }
58
47
  interface SendOptions {
59
48
  idempotencyKey?: string;
60
49
  }
61
- /**
62
- * Mirrors `apps/api/src/domains/emails/types.ts`'s server-side copy of this
63
- * shape. Not imported from there: this package is published to npm for
64
- * external consumers and can't depend on the private api app. Keep both
65
- * copies in sync by hand when the wire shape changes; same for
66
- * `BatchEmailResultItem` / `BatchEmailResponse` below.
67
- */
50
+ /** Mirrors `apps/api/src/domains/emails/types.ts`'s server-side copy. */
68
51
  interface EmailResponse {
69
52
  id: string;
70
53
  status: string;
@@ -76,6 +59,7 @@ interface BatchEmailResultItem {
76
59
  status?: string;
77
60
  duplicate?: boolean;
78
61
  error?: string;
62
+ code?: string;
79
63
  }
80
64
  interface BatchEmailResponse {
81
65
  results: BatchEmailResultItem[];
@@ -83,6 +67,20 @@ interface BatchEmailResponse {
83
67
  errors: number;
84
68
  limitReached?: boolean;
85
69
  }
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;
82
+ }
83
+
86
84
  interface Domain {
87
85
  id: string;
88
86
  organizationId: string;
@@ -100,6 +98,11 @@ interface Domain {
100
98
  createdAt: string;
101
99
  updatedAt: string;
102
100
  }
101
+ interface DomainCreateInput {
102
+ name: string;
103
+ dkimSelector?: string;
104
+ }
105
+
103
106
  interface Template {
104
107
  id: string;
105
108
  organizationId: string;
@@ -111,10 +114,6 @@ interface Template {
111
114
  createdAt: string;
112
115
  updatedAt: string;
113
116
  }
114
- interface DomainCreateInput {
115
- name: string;
116
- dkimSelector?: string;
117
- }
118
117
  interface TemplateCreateInput {
119
118
  name: string;
120
119
  subject: string;
@@ -129,39 +128,8 @@ interface TemplateUpdateInput {
129
128
  text?: string;
130
129
  variables?: string[];
131
130
  }
132
- /**
133
- * Every status an email can be in. `delivered` means the recipient's mail
134
- * gateway accepted the message with a 2xx response — it does not mean the
135
- * message reached the inbox; it can still be filtered or quarantined
136
- * afterward.
137
- */
138
- declare const EMAIL_STATUSES: readonly ["queued", "rendering", "submitted_to_postfix", "deferred", "sent", "delivered", "bounced", "rejected", "failed", "suppressed", "cancelled", "scheduled", "quarantined"];
139
- type EmailStatus = (typeof EMAIL_STATUSES)[number];
140
- /**
141
- * Every event type the server currently emits, including as a webhook's
142
- * `event` field. `WebhookEvent.event` stays typed as `string` (not this
143
- * union) because the server may add new event types over time — treat an
144
- * unrecognized value as informational, not an error. See
145
- * `docs/webhooks.md`: a project's webhook receives every event type below
146
- * automatically, with no per-type opt-in.
147
- */
148
- 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"];
149
- type EmailEventType = (typeof EMAIL_EVENT_TYPES)[number];
150
- /**
151
- * `metadata` shape for `delivered` / `deferred` / `bounced` webhook events
152
- * and lifecycle-timeline entries — written by the Postfix log follower.
153
- */
154
- interface DeliveryEventData {
155
- queueId: string;
156
- relay: string;
157
- response: string;
158
- timestamp: string;
159
- }
160
- /**
161
- * Mirrors `apps/api/src/domains/webhooks/types.ts`'s `WebhookPayload`
162
- * (different name, same shape) — see that file for why this isn't a shared
163
- * import.
164
- */
131
+
132
+ /** Mirrors `apps/api/src/domains/webhooks/types.ts`'s `WebhookPayload`. */
165
133
  interface WebhookEvent {
166
134
  event: string;
167
135
  emailId: string | null;
@@ -170,6 +138,7 @@ interface WebhookEvent {
170
138
  timestamp: string;
171
139
  metadata: Record<string, unknown>;
172
140
  }
141
+
173
142
  type CampaignStatus = 'draft' | 'scheduled' | 'sending' | 'paused' | 'sent' | 'cancelled';
174
143
  interface Campaign {
175
144
  id: string;
@@ -194,20 +163,13 @@ interface Campaign {
194
163
  opened?: number;
195
164
  clicked?: number;
196
165
  bounced?: number;
166
+ configurationBounced?: number;
197
167
  unsubscribed?: number;
198
168
  } | null;
199
169
  createdAt: string;
200
170
  updatedAt: string;
201
171
  }
202
- /**
203
- * Deliberately different from `apps/api/src/domains/campaigns/types.ts`'s
204
- * `CampaignListQuery` in `limit`/`offset` optionality, not a bug: this type
205
- * describes what a caller may omit before the request is sent, while the
206
- * api's `z.infer`'d type describes the post-parse shape after `.default()`
207
- * has filled those fields in. Both are correct for what they represent — see
208
- * `apps/api/src/sdk-dto-contract-discovery.test.ts`'s registry for the
209
- * enforcement.
210
- */
172
+ /** The SDK accepts optional pagination before the API applies defaults. */
211
173
  interface CampaignListQuery {
212
174
  projectId: string;
213
175
  status?: CampaignStatus;
@@ -241,11 +203,7 @@ interface CampaignUpdateInput {
241
203
  rawText?: string;
242
204
  scheduledFor?: string;
243
205
  }
244
- /**
245
- * Mirrors `apps/api/src/domains/campaigns/types.ts`'s server-side copy of
246
- * this shape (and `CampaignProviderStats` below) — see that file for why
247
- * this isn't a shared import.
248
- */
206
+ /** Mirrors `apps/api/src/domains/campaigns/types.ts`'s server-side copy. */
249
207
  interface CampaignStats {
250
208
  campaignId: string;
251
209
  totalRecipients: number;
@@ -253,7 +211,9 @@ interface CampaignStats {
253
211
  deliveryUnknown: number;
254
212
  opened: number;
255
213
  clicked: number;
214
+ /** Reputation bounces only; configuration bounces are in `configurationBounced`. */
256
215
  bounced: number;
216
+ configurationBounced: number;
257
217
  unsubscribed: number;
258
218
  openRate: number;
259
219
  clickRate: number;
@@ -269,44 +229,7 @@ interface CampaignProviderStats {
269
229
  clicks: number;
270
230
  total: number;
271
231
  }
272
- interface List {
273
- id: string;
274
- projectId: string;
275
- name: string;
276
- description: string | null;
277
- createdAt: string;
278
- updatedAt: string;
279
- }
280
- /**
281
- * Deliberately different from `apps/api/src/domains/lists/types.ts`'s
282
- * `ListWithCount` in `createdAt`/`updatedAt` (inherited from `List` above),
283
- * not a bug: this describes what a client receives after the wire
284
- * round-trip (`string`), while the api's type is the server-side shape held
285
- * before JSON serialization (`Date`, via drizzle's `$inferSelect`). See
286
- * `apps/api/src/sdk-dto-contract-discovery.test.ts`'s registry for the
287
- * enforcement.
288
- */
289
- interface ListWithCount extends List {
290
- memberCount: number;
291
- }
292
- interface ListCreateInput {
293
- projectId: string;
294
- name: string;
295
- description?: string;
296
- }
297
- interface ListUpdateInput {
298
- name?: string;
299
- description?: string;
300
- }
301
- interface ListMembersQuery {
302
- search?: string;
303
- limit?: number;
304
- offset?: number;
305
- }
306
- interface ListMembersResponse {
307
- data: Contact[];
308
- total: number;
309
- }
232
+
310
233
  interface Contact {
311
234
  id: string;
312
235
  projectId: string;
@@ -319,15 +242,7 @@ interface Contact {
319
242
  createdAt: string;
320
243
  updatedAt: string;
321
244
  }
322
- /**
323
- * Deliberately different from `apps/api/src/domains/contacts/types.ts`'s
324
- * `ContactListQuery` in `tags`/`tagMode`, not a bug: the api type is
325
- * `z.infer<typeof ContactListQuerySchema>` — `tags` is post-transform
326
- * `string[]` and `tagMode` is post-`.default()` required — while this is the
327
- * pre-request shape callers build, where both stay optional. See
328
- * `apps/api/src/sdk-dto-contract-discovery.test.ts`'s registry for the
329
- * enforcement.
330
- */
245
+ /** The SDK preserves optional filters before API parsing/defaulting. */
331
246
  interface ContactListQuery {
332
247
  projectId: string;
333
248
  search?: string;
@@ -366,36 +281,49 @@ interface ContactBulkResponse {
366
281
  updated: number;
367
282
  skipped: number;
368
283
  }
369
- /**
370
- * Deliberately different from `apps/api/src/domains/contacts/types.ts`'s
371
- * `ContactListItem` in `addedAt`, not a bug: this describes what a client
372
- * receives after the wire round-trip (`string`), while the api's type is
373
- * the server-side shape held before JSON serialization (`Date`). See
374
- * `apps/api/src/sdk-dto-contract-discovery.test.ts`'s registry for the
375
- * enforcement.
376
- */
284
+ /** `addedAt` is serialized to string for SDK consumers. */
377
285
  interface ContactListItem {
378
286
  id: string;
379
287
  name: string;
380
288
  memberCount: number;
381
289
  addedAt: string;
382
290
  }
383
- /**
384
- * Mirrors `apps/api/src/domains/sms/repo.types.ts`'s `smsStatusEnum` values
385
- * (`packages/db/src/schema/enums.ts`). Kept as a local literal union rather
386
- * than an import — this package can't depend on `@develemail/db`, same
387
- * reason `EMAIL_STATUSES` above is hand-copied instead of imported.
388
- */
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. */
389
324
  declare const SMS_STATUSES: readonly ["queued", "sending", "sent", "delivered", "deferred", "failed", "suppressed"];
390
325
  type SmsStatus = (typeof SMS_STATUSES)[number];
391
- /**
392
- * Mirrors `apps/api/src/domains/sms/types.ts`'s `z.infer`'d `SendSmsInput`
393
- * field-for-field — unlike `SendEmailInput`, there's no ergonomic wire
394
- * conversion needed here, so this is asserted equal (not
395
- * `DELIBERATELY_DIFFERENT`) in `apps/api/src/sdk-dto-contract.test.ts`.
396
- * Provide exactly one of `body` or `templateName` — the server 400s
397
- * otherwise; that XOR is a runtime `.refine()`, not expressible in the type.
398
- */
326
+ /** Mirrors `apps/api/src/domains/sms/types.ts`'s `SendSmsInput`. */
399
327
  interface SendSmsInput {
400
328
  to: string;
401
329
  from?: string;
@@ -405,13 +333,6 @@ interface SendSmsInput {
405
333
  tags?: string[];
406
334
  metadata?: Record<string, unknown>;
407
335
  }
408
- /**
409
- * Mirrors `apps/api/src/domains/sms/types.ts`'s server-side copy of this
410
- * shape field-for-field. Not imported from there: this package is published
411
- * to npm for external consumers and can't depend on the private api app.
412
- * Keep both copies in sync by hand when the wire shape changes; same for
413
- * `SmsListResponse` below.
414
- */
415
336
  interface SmsMessageResponse {
416
337
  id: string;
417
338
  to: string;
@@ -432,6 +353,18 @@ interface SmsListQuery {
432
353
  limit?: number;
433
354
  cursor?: string;
434
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
+ }
435
368
 
436
369
  declare class HttpClient {
437
370
  private readonly baseUrl;
@@ -529,7 +462,8 @@ declare class Lists {
529
462
  declare class Sms {
530
463
  private readonly http;
531
464
  constructor(http: HttpClient);
532
- send(input: SendSmsInput): Promise<SmsMessageResponse>;
465
+ send(input: SendSmsInput, options?: SendOptions): Promise<SmsMessageResponse>;
466
+ sendBatch(messages: SendSmsInput[], options?: SendOptions): Promise<BatchSmsResponse>;
533
467
  get(id: string): Promise<SmsMessageResponse>;
534
468
  list(query?: SmsListQuery): Promise<SmsListResponse>;
535
469
  }
@@ -554,4 +488,4 @@ declare class DevelEmail {
554
488
  constructor(config: DevelEmailConfig);
555
489
  }
556
490
 
557
- export { type AttachmentInput, type BatchEmailResponse, type BatchEmailResultItem, 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 };
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 };